Add trend MACD spot strategy

This commit is contained in:
Codex
2026-06-21 09:15:38 +03:00
parent f19856ca6e
commit 8a211acf98
18 changed files with 593 additions and 81 deletions
+31 -13
View File
@@ -5,7 +5,8 @@ from dataclasses import dataclass
from pathlib import Path
FIXED_SPOT_SYMBOLS = ("BTCUSDT", "ETHUSDT", "HYPEUSDT", "SOLUSDT", "LTCUSDT", "XRPUSDT")
FIXED_SPOT_SYMBOLS = ("BTCUSDT", "ETHUSDT", "SOLUSDT")
STRATEGY_MODES = {"legacy", "trend_macd"}
def _load_dotenv(path: Path) -> None:
@@ -55,8 +56,11 @@ class Settings:
auto_select_symbols: bool
top_symbols_count: int
symbols: tuple[str, ...]
strategy_mode: str
base_interval: str
kline_limit: int
trend_interval: str
trend_kline_limit: int
loop_interval_seconds: int
fast_trading_enabled: bool
fast_loop_interval_seconds: float
@@ -96,6 +100,10 @@ class Settings:
kelly_sizing_enabled: bool
kelly_fraction: float
kelly_max_fraction: float
risk_per_trade_percent: float
atr_trailing_multiplier: float
trend_rsi_min: float
trend_rsi_max: float
time_series_forecast_enabled: bool
time_series_min_candles: int
time_series_forecast_horizon: int
@@ -166,6 +174,9 @@ def load_settings(env_file: str | Path | None = None) -> Settings:
mode = os.getenv("TRADING_MODE", "paper").strip().lower()
if mode not in {"paper", "live"}:
raise ValueError("TRADING_MODE must be paper or live")
strategy_mode = os.getenv("STRATEGY_MODE", "trend_macd").strip().lower()
if strategy_mode not in STRATEGY_MODES:
raise ValueError("STRATEGY_MODE must be legacy or trend_macd")
settings = Settings(
trading_mode=mode,
host=os.getenv("HOST", "127.0.0.1"),
@@ -177,8 +188,11 @@ def load_settings(env_file: str | Path | None = None) -> Settings:
auto_select_symbols=_bool_env("AUTO_SELECT_SYMBOLS", False),
top_symbols_count=_int_env("TOP_SYMBOLS_COUNT", len(FIXED_SPOT_SYMBOLS)),
symbols=_symbols_env("SYMBOLS") or FIXED_SPOT_SYMBOLS,
base_interval=os.getenv("BASE_INTERVAL", "1"),
strategy_mode=strategy_mode,
base_interval=os.getenv("BASE_INTERVAL", "60"),
kline_limit=_int_env("KLINE_LIMIT", 240),
trend_interval=os.getenv("TREND_INTERVAL", "D"),
trend_kline_limit=_int_env("TREND_KLINE_LIMIT", 260),
loop_interval_seconds=_int_env("LOOP_INTERVAL_SECONDS", 5),
fast_trading_enabled=_bool_env("FAST_TRADING_ENABLED", False),
fast_loop_interval_seconds=_float_env("FAST_LOOP_INTERVAL_SECONDS", 1.0),
@@ -188,9 +202,9 @@ def load_settings(env_file: str | Path | None = None) -> Settings:
min_signal_confidence=_float_env("MIN_SIGNAL_CONFIDENCE", 0.64),
max_spread_percent=_float_env("MAX_SPREAD_PERCENT", 0.18),
min_24h_turnover_usdt=_float_env("MIN_24H_TURNOVER_USDT", 1000000.0),
pattern_analysis_enabled=_bool_env("PATTERN_ANALYSIS_ENABLED", True),
pattern_analysis_enabled=_bool_env("PATTERN_ANALYSIS_ENABLED", False),
pattern_score_weight=_float_env("PATTERN_SCORE_WEIGHT", 0.18),
learning_enabled=_bool_env("LEARNING_ENABLED", True),
learning_enabled=_bool_env("LEARNING_ENABLED", False),
learning_lookback_trades=_int_env("LEARNING_LOOKBACK_TRADES", 120),
learning_min_samples=_int_env("LEARNING_MIN_SAMPLES", 3),
learning_max_adjustment=_float_env("LEARNING_MAX_ADJUSTMENT", 0.12),
@@ -202,30 +216,34 @@ def load_settings(env_file: str | Path | None = None) -> Settings:
llm_advisor_timeout_seconds=_int_env("LLM_ADVISOR_TIMEOUT_SECONDS", 45),
llm_advisor_max_adjustment=_float_env("LLM_ADVISOR_MAX_ADJUSTMENT", 0.06),
min_position_usdt=_float_env("MIN_POSITION_USDT", 1.0),
max_position_usdt=_float_env("MAX_POSITION_USDT", 20.0),
max_symbol_exposure_usdt=_float_env("MAX_SYMBOL_EXPOSURE_USDT", 20.0),
max_total_exposure_usdt=_float_env("MAX_TOTAL_EXPOSURE_USDT", 80.0),
max_open_positions=_int_env("MAX_OPEN_POSITIONS", 6),
max_position_usdt=_float_env("MAX_POSITION_USDT", 25.0),
max_symbol_exposure_usdt=_float_env("MAX_SYMBOL_EXPOSURE_USDT", 25.0),
max_total_exposure_usdt=_float_env("MAX_TOTAL_EXPOSURE_USDT", 75.0),
max_open_positions=_int_env("MAX_OPEN_POSITIONS", len(FIXED_SPOT_SYMBOLS)),
max_positions_per_symbol=_int_env("MAX_POSITIONS_PER_SYMBOL", 1),
grid_trading_enabled=_bool_env("GRID_TRADING_ENABLED", True),
grid_trading_enabled=_bool_env("GRID_TRADING_ENABLED", False),
grid_entry_confidence=_float_env("GRID_ENTRY_CONFIDENCE", 0.58),
grid_buy_zone=_float_env("GRID_BUY_ZONE", 0.45),
grid_max_position_usdt=_float_env("GRID_MAX_POSITION_USDT", 8.0),
rebound_trading_enabled=_bool_env("REBOUND_TRADING_ENABLED", True),
rebound_trading_enabled=_bool_env("REBOUND_TRADING_ENABLED", False),
rebound_entry_confidence=_float_env("REBOUND_ENTRY_CONFIDENCE", 0.58),
rebound_min_probability=_float_env("REBOUND_MIN_PROBABILITY", 0.58),
rebound_max_position_usdt=_float_env("REBOUND_MAX_POSITION_USDT", 6.0),
kelly_sizing_enabled=_bool_env("KELLY_SIZING_ENABLED", True),
kelly_sizing_enabled=_bool_env("KELLY_SIZING_ENABLED", False),
kelly_fraction=_float_env("KELLY_FRACTION", 0.25),
kelly_max_fraction=_float_env("KELLY_MAX_FRACTION", 0.20),
time_series_forecast_enabled=_bool_env("TIME_SERIES_FORECAST_ENABLED", True),
risk_per_trade_percent=_float_env("RISK_PER_TRADE_PERCENT", 0.01),
atr_trailing_multiplier=_float_env("ATR_TRAILING_MULTIPLIER", 2.2),
trend_rsi_min=_float_env("TREND_RSI_MIN", 45.0),
trend_rsi_max=_float_env("TREND_RSI_MAX", 65.0),
time_series_forecast_enabled=_bool_env("TIME_SERIES_FORECAST_ENABLED", False),
time_series_min_candles=_int_env("TIME_SERIES_MIN_CANDLES", 120),
time_series_forecast_horizon=_int_env("TIME_SERIES_FORECAST_HORIZON", 3),
time_series_min_edge_percent=_float_env("TIME_SERIES_MIN_EDGE_PERCENT", 0.04),
time_series_max_adjustment=_float_env("TIME_SERIES_MAX_ADJUSTMENT", 0.08),
time_series_lstm_enabled=_bool_env("TIME_SERIES_LSTM_ENABLED", True),
time_series_lstm_model_path=Path(os.getenv("TIME_SERIES_LSTM_MODEL_PATH", "runtime/lstm_forecaster.json")),
stop_loss_percent=_float_env("STOP_LOSS_PERCENT", 0.02),
stop_loss_percent=_float_env("STOP_LOSS_PERCENT", 0.04),
take_profit_percent=_float_env("TAKE_PROFIT_PERCENT", 0.035),
trailing_stop_percent=_float_env("TRAILING_STOP_PERCENT", 0.015),
min_hold_seconds=_int_env("MIN_HOLD_SECONDS", 180),