Fájl részletek

Ezen az oldalon egy konkrét fájl aktuális állapotát tudod megnézni.

Vissza a fájltérképhez Csak változott Stratégia-labor Monitor főoldal ← Előző módosult Következő módosult →
Fájl útvonala
/opt/bots/saturnus_monitor/app/monitor_app.py
Létezik most?
IGEN
Aktuális státusz
MODIFIED
Méret
100724
Módosítás ideje
1779891348.85247
Korábbi baseline időpont
1776156245.4915786
SHA256 rövid

Előnézet (első 120 sor)

#!/usr/bin/env python3
import csv
import io
import json
import math
import hashlib
import subprocess
from datetime import datetime, timezone
from pathlib import Path
from types import SimpleNamespace
from zoneinfo import ZoneInfo

from flask import Flask, render_template, send_file, jsonify, request, redirect, url_for

import sys
sys.path.insert(0, "/opt/bots/saturnus/app")

from rules_loader import load_rules_doc, load_lab_override_doc
from rules_merge import build_effective_rules
from rule_engine import decide as shared_rule_decide, normalize_state as shared_normalize_state, compute_levels as shared_compute_levels


APP_DIR = Path("/opt/bots/saturnus_monitor/app")
DATA_DIR = Path("/opt/bots/saturnus_monitor/data")

STATE_PATH = Path("/opt/bots/saturnus/state.json")
CONFIG_PATH = Path("/opt/bots/saturnus/freqtrade/user_data/config.json")

PRICES_CSV = DATA_DIR / "prices.csv"
EVENTS_CSV = DATA_DIR / "events.csv"
TRADE_EVENTS_CSV = DATA_DIR / "trade_events.csv"
ANALYSIS_JSON = DATA_DIR / "analysis_summary.json"
ANALYSIS_SCRIPT = Path("/opt/bots/saturnus_monitor/scripts/analyze_monitor_data.py")
FILE_AUDIT_JSON = DATA_DIR / "files_audit_snapshot.json"

app = Flask(__name__, template_folder=str(APP_DIR / "templates"))


# ------------------------------------------------
# alap segédfüggvények
# ------------------------------------------------

def read_json(path: Path):
    if not path.exists():
        return {}
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}


def read_csv_rows(path: Path):
    if not path.exists():
        return []
    try:
        with path.open("r", encoding="utf-8", newline="") as f:
            return list(csv.DictReader(f))
    except Exception:
        return []


def to_float(value, default=None):
    try:
        if value is None or value == "":
            return default
        return float(value)
    except Exception:
        return default


def fmt_num(value, digits=4):
    if value is None:
        return "—"
    try:
        return f"{float(value):,.{digits}f}".replace(",", " ")
    except Exception:
        return "—"


def fmt_pct(value, digits=2):
    if value is None:
        return "—"
    try:
        return f"{float(value):.{digits}f}%"
    except Exception:
        return "—"


def safe_tail(rows, n):
    if not rows:
        return []
    return rows[-n:]


def first_nonempty(row, keys, default=""):
    for key in keys:
        val = row.get(key)
        if val not in (None, ""):
            return val
    return default


def parse_bool_arg(name: str, default: bool) -> bool:
    values = request.args.getlist(name)
    if not values:
        return default
    last = values[-1]
    return str(last).strip().lower() in ("1", "true", "yes", "on")


def parse_float_arg(name: str, default: float, min_value=None, max_value=None) -> float:
    value = to_float(request.args.get(name), default)
    if value is None:
        value = default
    if min_value is not None and value < min_value:
        value = min_value
    if max_value is not None and value > max_value:
        value = max_value
    return value

Csak változott diff sorok

--- baseline +++ current @@ -118,16 +118,21 @@ - - raw = (request.args.get("rows_limit", "500") or "500").strip().lower() - allowed = {"100", "250", "500", "1000", "2000", "all"} - if raw not in allowed: - raw = "500" - if raw == "all": + raw = (request.args.get("rows_limit", "all") or "all").strip().lower() + + if raw in ("", "all", "max", "full", "10d", "10days"): - return int(raw), raw - + + try: + value = int(raw) + except Exception: + return None, "all" + + if value <= 0: + return None, "all" + + return value, str(value) @@ -197,11 +202,9 @@ - "BUY_PROFITLESS": "BUY_RECOVERY", - "BUY_PANIC": "BUY_PANIC", + "BUY_PANIC": "BUY_PANIC", - "SELL_PROFITLESS": "SELL_RECOVERY", - "SELL_PANIC": "SELL_PANIC", + "SELL_PANIC": "SELL_PANIC", @@ -402,9 +405,7 @@ - "SELL_PROFITLESS": "SELL_RECOVERY", - "PROFITLESS_SELL": "SELL_RECOVERY", - "RECOVERY_SELL": "SELL_RECOVERY", + "RECOVERY_SELL": "SELL_RECOVERY", @@ -414,9 +415,7 @@ - "BUY_PROFITLESS": "BUY_RECOVERY", - "PROFITLESS_BUY": "BUY_RECOVERY", - "RECOVERY_BUY": "BUY_RECOVERY", + "RECOVERY_BUY": "BUY_RECOVERY", @@ -442,16 +441,14 @@ - "PROFITLESS SELL": "recovery_sell", - "SELL_STANDARD": "std_sell", + "SELL_STANDARD": "std_sell", - "PROFITLESS BUY": "recovery_buy", - "BUY_STANDARD": "std_buy", + "BUY_STANDARD": "std_buy", @@ -541,8 +538,6 @@ - - note = str(note).replace("PROFITLESS", "RECOVERY").replace("profitless", "recovery") @@ -944,7 +939,7 @@ - value = float(default_internal) + value = float(default_internal or 0.0) @@ -991,24 +986,26 @@ - "std_sell_pct": parse_percent_arg("std_sell_pct", 0.03, 0.0), + "std_sell_pct": parse_percent_arg("std_sell_pct", None, 0.0), - "panic_sell_pct": parse_percent_arg("panic_sell_pct", 0.01, 0.0), + "panic_sell_pct": parse_percent_arg("panic_sell_pct", None, 0.0), - "std_buy_pct": parse_percent_arg("std_buy_pct", 0.03, 0.0), + "std_buy_pct": parse_percent_arg("std_buy_pct", None, 0.0), - "panic_buy_pct": parse_percent_arg("panic_buy_pct", 0.01, 0.0), + "panic_buy_pct": parse_percent_arg("panic_buy_pct", None, 0.0), + "sell_reversal_min_pct": parse_percent_arg("sell_reversal_min_pct", 0.0, 0.0), + "ma_sideways_band_pct": parse_percent_arg("ma_sideways_band_pct", 0.0005, 0.0), @@ -1030,6 +1027,7 @@ + params_ns.sell_reversal_min_pct_ui = format_percent_ui_from_internal(params_ns.sell_reversal_min_pct, 3) @@ -1055,18 +1053,17 @@ - if str(getattr(params, "rules_source", "lab") or "lab").strip().lower() == "lab": - params.rules_profile_type = "lab-effective" - params.rules_profile_name = "lab" - params.rules_source_label = "LAB nézet / kézi űrlap paraméterek" - return params - - # FONTOS: - # LAB módban a felhasználó által beírt űrlapérték az elsődleges. - # CANONICAL módban az effective threshold sorokból töltjük vissza - # a tényleges paramétereket. + """ + A stratégia-labor mindig a közös shared engine-t használja. + A rules_source itt már nem külön stratégiai logikát választ, + csak nézeti / kiinduló forrás címke marad. + + A tényleges szimulációs engine input elsődlegesen a form/UI értékekből épül fel. + """ + if rules_source not in ("lab", "canonical"): + rules_source = "lab" @@ -1084,84 +1081,13 @@ - threshold_mode = "bot" - params.rules_profile_type = "canonical-effective" - params.rules_profile_name = threshold_mode - params.rules_source_label = "Canonical nézet / effective bot paraméterek" + params.rules_profile_type = "shared-engine" + params.rules_profile_name = "canonical-base + ui-overrides" + params.rules_source_label = "Közös engine / canonical alap + kézi labor paraméterek" - threshold_mode = "lab" - params.rules_profile_type = "lab-effective" - params.rules_profile_name = threshold_mode - params.rules_source_label = "LAB nézet / kézi űrlap paraméterek" - - # LAB módban NEM írjuk felül az űrlapból jött értékeket. - return params - - try: - threshold_rows = build_effective_threshold_rows(threshold_mode) - except Exception: - threshold_rows = [] - - threshold_map = {} - label_alias = { - "SELL_STANDARD": "SELL_STANDARD",

Teljes diff

--- baseline +++ current @@ -118,16 +118,21 @@ value = max_value return value - def parse_rows_limit_arg(): - raw = (request.args.get("rows_limit", "500") or "500").strip().lower() - allowed = {"100", "250", "500", "1000", "2000", "all"} - if raw not in allowed: - raw = "500" - if raw == "all": + raw = (request.args.get("rows_limit", "all") or "all").strip().lower() + + if raw in ("", "all", "max", "full", "10d", "10days"): return None, "all" - return int(raw), raw - + + try: + value = int(raw) + except Exception: + return None, "all" + + if value <= 0: + return None, "all" + + return value, str(value) # ------------------------------------------------ # rules source helper @@ -197,11 +202,9 @@ rule_map = { "BUY_STD": "BUY_STANDARD", - "BUY_PROFITLESS": "BUY_RECOVERY", - "BUY_PANIC": "BUY_PANIC", + "BUY_PANIC": "BUY_PANIC", "SELL_STD": "SELL_STANDARD", - "SELL_PROFITLESS": "SELL_RECOVERY", - "SELL_PANIC": "SELL_PANIC", + "SELL_PANIC": "SELL_PANIC", } out = [] @@ -402,9 +405,7 @@ "STANDARD_SELL": "SELL_STANDARD", "SELL_STANDARD": "SELL_STANDARD", - "SELL_PROFITLESS": "SELL_RECOVERY", - "PROFITLESS_SELL": "SELL_RECOVERY", - "RECOVERY_SELL": "SELL_RECOVERY", + "RECOVERY_SELL": "SELL_RECOVERY", "SELL_RECOVERY": "SELL_RECOVERY", "SELL_PANIC": "SELL_PANIC", @@ -414,9 +415,7 @@ "STANDARD_BUY": "BUY_STANDARD", "BUY_STANDARD": "BUY_STANDARD", - "BUY_PROFITLESS": "BUY_RECOVERY", - "PROFITLESS_BUY": "BUY_RECOVERY", - "RECOVERY_BUY": "BUY_RECOVERY", + "RECOVERY_BUY": "BUY_RECOVERY", "BUY_RECOVERY": "BUY_RECOVERY", "BUY_PANIC": "BUY_PANIC", @@ -442,16 +441,14 @@ threshold_key_from_label = { "STD SELL": "std_sell", "PANIC SELL": "panic_sell", - "PROFITLESS SELL": "recovery_sell", - "SELL_STANDARD": "std_sell", + "SELL_STANDARD": "std_sell", "SELL_PANIC": "panic_sell", "SELL_RECOVERY": "recovery_sell", "SELL_CATASTROPHE": "catastrophe_sell", "STD BUY": "std_buy", "PANIC BUY": "panic_buy", - "PROFITLESS BUY": "recovery_buy", - "BUY_STANDARD": "std_buy", + "BUY_STANDARD": "std_buy", "BUY_PANIC": "panic_buy", "BUY_RECOVERY": "recovery_buy", "BUY_CATASTROPHE": "catastrophe_buy", @@ -541,8 +538,6 @@ "A RECOVERY szabályok kontextusfüggők; kevés minta esetén az értékek csak előzetes " "irányadónak tekintendők." ) - - note = str(note).replace("PROFITLESS", "RECOVERY").replace("profitless", "recovery") if note == "Ha a RECOVERY események dominálnak, akkor a recovery szabály túl gyakran aktiválódhat. A becsült értékek kevés adat mellett még csak előzetes javaslatok.": note = ( @@ -944,7 +939,7 @@ def parse_percent_arg(name, default_internal, min_value=None, max_value=None): raw = request.args.get(name) if raw is None: - value = float(default_internal) + value = float(default_internal or 0.0) else: normalized = _normalize_localized_number(raw) if normalized is None: @@ -991,24 +986,26 @@ "rows_limit_label": rows_limit_label, "std_sell_enabled": parse_bool_arg("std_sell_enabled", True), - "std_sell_pct": parse_percent_arg("std_sell_pct", 0.03, 0.0), + "std_sell_pct": parse_percent_arg("std_sell_pct", None, 0.0), "panic_sell_enabled": parse_bool_arg("panic_sell_enabled", True), - "panic_sell_pct": parse_percent_arg("panic_sell_pct", 0.01, 0.0), + "panic_sell_pct": parse_percent_arg("panic_sell_pct", None, 0.0), "catastrophe_sell_pct": parse_percent_arg("catastrophe_sell_pct", 0.10, 0.0), "std_buy_enabled": parse_bool_arg("std_buy_enabled", True), - "std_buy_pct": parse_percent_arg("std_buy_pct", 0.03, 0.0), + "std_buy_pct": parse_percent_arg("std_buy_pct", None, 0.0), "panic_buy_enabled": parse_bool_arg("panic_buy_enabled", True), - "panic_buy_pct": parse_percent_arg("panic_buy_pct", 0.01, 0.0), + "panic_buy_pct": parse_percent_arg("panic_buy_pct", None, 0.0), "catastrophe_buy_pct": parse_percent_arg("catastrophe_buy_pct", 0.10, 0.0), "panic_buy_confirm_ticks": int(parse_float_arg("panic_buy_confirm_ticks", 2, 1, 10)), "recovery_buy_rebound_pct": parse_percent_arg("recovery_buy_rebound_pct", 0.003, 0.0), "recovery_sell_retrace_pct": parse_percent_arg("recovery_sell_retrace_pct", 0.003, 0.0), "recovery_profit_target_pct": parse_percent_arg("recovery_profit_target_pct", 0.001, 0.0), + "sell_reversal_min_pct": parse_percent_arg("sell_reversal_min_pct", 0.0, 0.0), "ma_filter_enabled": parse_bool_arg("ma_filter_enabled", True), "ma_period": int(parse_float_arg("ma_period", 20, 5, 100000)), + "ma_sideways_band_pct": parse_percent_arg("ma_sideways_band_pct", 0.0005, 0.0), "rules_source": get_rules_source(), } @@ -1030,6 +1027,7 @@ params_ns.recovery_buy_rebound_pct_ui = format_percent_ui_from_internal(params_ns.recovery_buy_rebound_pct, 3) params_ns.recovery_sell_retrace_pct_ui = format_percent_ui_from_internal(params_ns.recovery_sell_retrace_pct, 3) params_ns.recovery_profit_target_pct_ui = format_percent_ui_from_internal(params_ns.recovery_profit_target_pct, 3) + params_ns.sell_reversal_min_pct_ui = format_percent_ui_from_internal(params_ns.sell_reversal_min_pct, 3) params_ns.catastrophe_buy_pct_ui = format_percent_ui_from_internal(params_ns.catastrophe_buy_pct, 3) return params_ns @@ -1055,18 +1053,17 @@ def apply_effective_rules_to_params(params): - if str(getattr(params, "rules_source", "lab") or "lab").strip().lower() == "lab": - params.rules_profile_type = "lab-effective" - params.rules_profile_name = "lab" - params.rules_source_label = "LAB nézet / kézi űrlap paraméterek" - return params - - # FONTOS: - # LAB módban a felhasználó által beírt űrlapérték az elsődleges. - # CANONICAL módban az effective threshold sorokból töltjük vissza - # a tényleges paramétereket. + """ + A stratégia-labor mindig a közös shared engine-t használja. + A rules_source itt már nem külön stratégiai logikát választ, + csak nézeti / kiinduló forrás címke marad. + + A tényleges szimulációs engine input elsődlegesen a form/UI értékekből épül fel. + """ try: rules_source = str(getattr(params, "rules_source", "lab") or "lab").strip().lower() + if rules_source not in ("lab", "canonical"): + rules_source = "lab" params.std_sell_enabled = bool(getattr(params, "std_sell_enabled", True)) params.panic_sell_enabled = bool(getattr(params, "panic_sell_enabled", True)) @@ -1084,84 +1081,13 @@ params.recovery_profit_target_pct = max(0.0, float(getattr(params, "recovery_profit_target_pct", 0.001))) if rules_source == "canonical": - threshold_mode = "bot" - params.rules_profile_type = "canonical-effective" - params.rules_profile_name = threshold_mode - params.rules_source_label = "Canonical nézet / effective bot paraméterek" + params.rules_profile_type = "shared-engine" + params.rules_profile_name = "canonical-base + ui-overrides" + params.rules_source_label = "Közös engine / canonical alap + kézi labor paraméterek" else: - threshold_mode = "lab" - params.rules_profile_type = "lab-effective" - params.rules_profile_name = threshold_mode - params.rules_source_label = "LAB nézet / kézi űrlap paraméterek" - - # LAB módban NEM írjuk felül az űrlapból jött értékeket. - return params - - try: - threshold_rows = build_effective_threshold_rows(threshold_mode) - except Exception: - threshold_rows = [] - - threshold_map = {} - label_alias = { - "SELL_STANDARD": "SELL_STANDARD", ... [DIFF LEVÁGVA] további sorok: 768