Files
strategy32/config.py

186 lines
7.1 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from strategy29.common.models import Regime
from strategy29.config import Strategy29Config
DEFAULT_QUOTE_ASSETS = ("USDT", "USDC")
DEFAULT_EXCLUDED_BASE_ASSETS = ("USDT", "USDC", "BUSD", "FDUSD", "TUSD", "USDP", "DAI", "USDS", "USDD", "EUR", "AEUR")
PROFILE_V5_BASELINE = "v5_baseline"
PROFILE_V7_DEFAULT = "v7_default"
@dataclass(slots=True)
class Strategy32Budgets:
strong_up_momentum: float = 0.85
strong_up_carry: float = 0.10
strong_up_sideways: float = 0.00
up_momentum: float = 0.25
up_carry: float = 0.15
up_sideways: float = 0.00
sideways_momentum: float = 0.00
sideways_carry: float = 0.20
sideways_sideways: float = 0.10
down_momentum: float = 0.00
down_carry: float = 0.10
down_sideways: float = 0.03
def for_regime(self, regime: Regime) -> tuple[float, float, float]:
if regime == Regime.STRONG_UP:
return self.strong_up_momentum, self.strong_up_carry, self.strong_up_sideways
if regime == Regime.UP:
return self.up_momentum, self.up_carry, self.up_sideways
if regime == Regime.SIDEWAYS:
return self.sideways_momentum, self.sideways_carry, self.sideways_sideways
if regime == Regime.DOWN:
return self.down_momentum, self.down_carry, self.down_sideways
return 0.0, 0.0, 0.0
@dataclass(slots=True)
class Strategy32Config:
symbols: list[str] = field(default_factory=list)
auto_discover_symbols: bool = True
quote_assets: tuple[str, ...] = DEFAULT_QUOTE_ASSETS
excluded_base_assets: tuple[str, ...] = DEFAULT_EXCLUDED_BASE_ASSETS
discovery_min_quote_volume_24h: float = 5_000_000.0
timeframe: str = "4h"
warmup_days: int = 90
max_symbol_staleness_days: int = 3
universe_size: int = 0
universe_lookback_bars: int = 30
universe_min_avg_dollar_volume: float = 5_000_000.0
hard_filter_refresh_cadence: str = "4h"
hard_filter_min_history_bars: int = 120
hard_filter_lookback_bars: int = 30
hard_filter_min_avg_dollar_volume: float = 50_000_000.0
momentum_min_history_bars: int = 120
momentum_min_score: float = 0.55
momentum_min_relative_strength: float = 0.0
momentum_min_7d_return: float = 0.0
momentum_max_7d_return: float = 1.0
momentum_min_positive_bar_ratio: float = 0.0
momentum_max_short_volatility: float = 1.0
momentum_max_beta: float = 10.0
momentum_max_latest_funding_rate: float = 1.0
enable_liquidity_universe_fallback: bool = True
universe_fallback_min_avg_dollar_volume: float = 2_500_000.0
universe_fallback_top_n: int = 8
enable_momentum_filter_fallback: bool = True
momentum_fallback_min_score: float = 0.45
momentum_fallback_min_relative_strength: float = -0.03
momentum_fallback_min_7d_return: float = -0.02
momentum_fallback_top_n: int = 3
carry_min_expected_edge: float = 0.0
position_vol_lookback_bars: int = 36
correlation_lookback_bars: int = 36
max_pairwise_correlation: float = 0.78
target_annualized_vol: float = 0.55
governor_vol_lookback_bars: int = 42
drawdown_window_days: int = 30
drawdown_scale_1_trigger: float = 0.08
drawdown_scale_1: float = 0.70
drawdown_scale_2_trigger: float = 0.12
drawdown_scale_2: float = 0.40
drawdown_stop_trigger: float = 0.18
vol_scale_floor: float = 0.35
up_btc_hedge_ratio: float = 0.35
sideways_btc_hedge_ratio: float = 0.65
sideways_top_n: int = 1
carry_relaxed_top_n: int = 128
carry_relaxed_min_positive_ratio: float = 0.52
carry_relaxed_min_mean_funding_rate: float = 0.000015
carry_relaxed_max_basis_volatility: float = 0.0075
carry_relaxed_roundtrip_cost_pct: float = 0.0022
carry_relaxed_basis_risk_multiplier: float = 1.0
carry_deep_relaxed_min_positive_ratio: float = 0.48
carry_deep_relaxed_min_mean_funding_rate: float = 0.0
carry_deep_relaxed_max_basis_volatility: float = 0.012
carry_deep_relaxed_roundtrip_cost_pct: float = 0.0018
carry_deep_relaxed_basis_risk_multiplier: float = 0.75
enable_carry_score_fallback: bool = True
carry_score_fallback_min_expected_edge: float = -0.0002
carry_score_fallback_min_positive_ratio: float = 0.48
carry_score_fallback_top_n: int = 2
enable_sideways_engine: bool = False
enable_strong_kill_switch: bool = True
enable_daily_trend_filter: bool = True
enable_expanded_hedge: bool = False
enable_max_holding_exit: bool = False
enable_execution_refinement: bool = True
execution_refinement_timeframe: str = "1h"
execution_refinement_lookback_bars: int = 48
execution_refinement_fast_ema: int = 8
execution_refinement_slow_ema: int = 21
execution_refinement_scale_down_gap: float = 0.008
execution_refinement_max_chase_gap: float = 0.018
execution_refinement_max_recent_return: float = 0.03
execution_refinement_scale_down_factor: float = 0.5
strong_kill_drawdown_window_days: int = 60
strong_kill_scale_1_trigger: float = 0.05
strong_kill_scale_1: float = 0.60
strong_kill_scale_2_trigger: float = 0.08
strong_kill_scale_2: float = 0.35
strong_kill_stop_trigger: float = 0.10
long_trend_fast_ema_days: int = 50
long_trend_slow_ema_days: int = 200
expanded_up_btc_hedge_ratio: float = 0.55
expanded_sideways_btc_hedge_ratio: float = 0.85
expanded_strong_up_btc_hedge_ratio: float = 0.10
max_holding_bars: int = 42
trend_fail_ema_span: int = 18
min_hold_bars_for_trend_fail: int = 12
budgets: Strategy32Budgets = field(default_factory=Strategy32Budgets)
PROFILE_OVERRIDES: dict[str, dict[str, bool]] = {
PROFILE_V5_BASELINE: {
"enable_sideways_engine": True,
"enable_strong_kill_switch": False,
"enable_daily_trend_filter": False,
"enable_expanded_hedge": False,
"enable_max_holding_exit": False,
},
PROFILE_V7_DEFAULT: {
"enable_sideways_engine": False,
"enable_strong_kill_switch": True,
"enable_daily_trend_filter": True,
"enable_expanded_hedge": False,
"enable_max_holding_exit": False,
},
}
def apply_strategy32_profile(config: Strategy32Config, profile: str) -> Strategy32Config:
try:
overrides = PROFILE_OVERRIDES[profile]
except KeyError as exc:
supported = ", ".join(sorted(PROFILE_OVERRIDES))
raise ValueError(f"Unsupported Strategy32 profile: {profile}. Supported: {supported}") from exc
for attr, value in overrides.items():
setattr(config, attr, value)
return config
def build_strategy32_config(profile: str = PROFILE_V7_DEFAULT, **overrides: object) -> Strategy32Config:
config = Strategy32Config()
apply_strategy32_profile(config, profile)
for attr, value in overrides.items():
setattr(config, attr, value)
return config
def build_engine_config() -> Strategy29Config:
config = Strategy29Config()
config.momentum.top_n = 128
config.momentum.max_positions = 128
config.momentum.rebalance_bars = 24
config.momentum.trailing_stop_pct = 0.08
config.momentum.stop_loss_pct = 0.07
config.momentum.overheat_funding_rate = 0.00025
config.carry.top_n = 128
return config