
    ګ9j֌                       d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlmZmZ ej"                  j%                  dej"                  j'                  ej"                  j'                  ej"                  j)                  e                         ddlmZ ddlmZmZmZmZmZmZm Z m!Z!m"Z"m#Z$m%Z&m'Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z. dZ/dZ0da1da2d	a3d
td         dtf         da4da5da6da7da8e$a9e&a:dZ;dZ<dZ= G d de>      Z?dhdZ@d ZAd ZBd ZCdddddddd d!d"d#
ZDh d$ZE eFe*      eEz  ZGdid%ZHd& ZIdjd'ZJd( ZKd) ZLd* ZMg d+ZNd, ZOd- ZPi d.d/gd0d1gd2d3gd4d5gd6d7gd8d9gd:d;gd<d=gd>d?gd@dAgdBdCgdDdEgdFdGgdHdIgdJdKgdLdMgdNdOgdPgdQgdRgdSgdTgdUgdVdWgdXgdYgdZgdddd[ZQd\ ZRd] ZSd^ ZTd_ ZUd` ZVda ZWdb ZXdc ZYdkddZZde Z[df Z\e]dgk(  r e\        yy)lu   
Auto-Optimizer Loop
Iteratively runs the GPU random search optimizer and tracks the best result across runs.
Parameter ranges are never modified automatically — edit the params JSON file manually.
    N)ProcessPoolExecutoras_completed)TRAIN_STARTSCORE_START	TRAIN_END	OOS_STARTRESULTS_DIRWINNERS_DIR
SWEEPS_DIRREPORTS_DIR
OUTPUT_DIRMVRV_BEAR_THRESHOLDMVRV_BULL_THRESHOLDcomposite_scoreSUBPERIOD_SPLITWEIGHT_COLS	WFO_FOLDSWFO_MIN_OOS_TRADESWFO_MIN_VALID_FOLDS	WFO_TOP_Nzstrategy_activation_scores.py	Compositez data/mlp/COINBASE_BTCUSD, 1D.csvCOINBASE_BTCUSD1D4strategies/params/params_strategy_activation_scores__.jsoni   randomallzresults/sweep_database.dbi" c                        e Zd ZddZd Zd Zy)Loggerc                 T    t         j                  | _        t        |dd      | _        y )Nwzutf-8)encoding)sysstdoutterminalopenlog)selffilenames     C/Users/jameslopez/projects/TradingBot25/tools/auto_optimize_loop.py__init__zLogger.__init__.   s    

#8    c                     | j                   j                  |       | j                  j                  |       | j                  j                          y N)r'   writer)   flush)r*   messages     r,   r1   zLogger.write2   s2    G$wr.   c                 l    | j                   j                          | j                  j                          y r0   )r'   r2   r)   )r*   s    r,   r2   zLogger.flush7   s     r.   N)zoptimization_log.txt)__name__
__module____qualname__r-   r1   r2    r.   r,   r!   r!   -   s    9
r.   r!   c                 	   g d}| j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }	| j                  dd      }
| j                  dd      }| j                  d	d      }d
dl}|j                  j                         j	                         }|dk7  rt        |      dnd}| j                  dd      }|dvrt        |      d
kD  rt        |      dnd}|dk7  rdnd}|r| d| n|}d d| d| d| d| dt        |      ddt        |      ddt        |      dd| dt        |	      ddt        |
      ddt        t        |             d t         d!t         d"d d#}d$ }|D ch c]  ^}}| }}}|g}d}|D ]l  \  }}}}}||k7  r|j                  d%| d&       |}| j                  |d      }|dk(  s||d'nd(}  ||||      }!|j                  d)|d*d+|!d,d-| d.|         n | j                         D "cg c],  }"t        |"t              s|"j                  d/      s&|"|vs+|". }#}"|#rX|j                  d0       t        |#      D ]9  } || j                  |d      d1d      }!|j                  d)|d*d+|!d,d-| d.       ; t        j                   j#                  |d2| d| d3      }$t%        |$d4      5 }%|%j'                  d#j#                  |      d#z          ddd       d5| d| d6d7t        |      dd8t        |      dd9t        |	      d:d;t        |
      dd<t        t        |             
d=t         d!t         d>t(         d.d?d(g}&d}|D ]j  \  }}}}}||k7  r|&j                  d@| d&       |}| j                  |d      } ||||      }!|dk(  s||dAnd(}'|&j                  |d*dB| dC|! dD|'        l |#rS|&j                  dE       t        |#      D ]4  } || j                  |d      d1d      }!|&j                  |d*dF|! dG       6 t        j                   j#                  |d2| d| dH      }(t%        |(d4      5 }%|%j'                  d#j#                  |&      d#z          ddd       t+        dI|$        t+        dJ|(        yc c}}w c c}"w # 1 sw Y   xY w# 1 sw Y   >xY w)Kz
    Writes two human-readable companion files alongside the winner CSV:
      - optimization_winner_<name>_cheatsheet.txt : TradingView UI groups + values
      - optimization_winner_<name>_pine_snippet.pine : input.float() defaults to paste
    )E)!i_long_entry_activation_thresholdzLong Entry Activation ThresholdNeural Activation ThresholdsfloatN) i_long_exit_activation_thresholdzLong Exit Activation Thresholdr;   r<   N)-i_long_exit_activation_confirmation_thresholdz+Long Exit Activation Confirmation Thresholdr;   r<   N)i_use_long_exit_confirmationzUse Long Exit Confirmationr;   boolN)i_use_long_entry_confirmationzUse Long Entry Confirmationr;   r@   N)i_trailing_stop_thresholdzTrailing Stop % (0 = disabled)r;   r<   N)	i_w_stochzStochastic WeightNeural Activation Weightsr<   N)i_w_macd_predzMACD Prediction WeightrD   r<   N)i_w_oscz
OSC WeightrD   r<   N)i_w_macd_bullishzMACD Bullish WeightrD   r<   N)i_w_m3_momentumzM3 Momentum WeightrD   r<   N)i_m3_momentum_periodzM3 Momentum PeriodrD   intN)i_w_m2_tinyzM2 Tiny Momentum WeightrD   r<   N)i_w_rsid_osczRSID OSC WeightrD   r<   N)i_w_stoch_div_osczStoch Div OSC WeightrD   r<   N)i_w_vwap_div_osczVWAP Div OSC WeightrD   r<   N)i_w_stoch_peakingzStoch Peaking WeightrD   r<   N)i_w_stoch_bottomingzStoch Bottoming WeightrD   r<   N)i_w_m3_div_osczM3 Div OSC WeightrD   r<   N)i_w_m2_div_osczM2 Div OSC WeightrD   r<   N)i_w_m2_div_osc_noOffsetzM2 Div OSC (No Offset) WeightrD   r<   N)i_w_bearish_engulfingzBearish Engulfing WeightCandlestick Patternsr<   N)i_cs_body_quality_ratiozBody Quality RatiorU   r<   N)i_cs_confidence_scaling_factorzConfidence Scaling FactorrU   r<   N)i_w_bullish_hammerzBullish Hammer WeightrU   r<   N)i_cs_hammer_min_lower_shadowzHammer Min Lower Shadow RatiorU   r<   333333?)i_cs_hammer_max_body_ratiozHammer Max Body RatiorU   r<   ffffff?)i_cs_hammer_max_upper_shadowzHammer Max Upper Shadow RatiorU   r<   333333?)i_w_bullish_engulfingzBullish Engulfing WeightrU   r<   N)i_cs_bull_eng_scaling_factorz Bullish Engulfing Scaling FactorrU   r<   g      @)i_w_shooting_starzShooting Star WeightrU   r<   N)i_cs_star_min_upper_shadowzShooting Star Min Upper ShadowrU   r<   rZ   )i_cs_star_max_body_ratiozShooting Star Max Body RatiorU   r<   r\   )i_cs_star_max_lower_shadowzShooting Star Max Lower ShadowrU   r<   r^   )i_w_btc_spx_corrzBTC/SPX Correlation WeightMacro Signalsr<   N)i_w_dxyz
DXY Weightrf   r<   N)i_w_vixz
VIX Weightrf   r<   N)i_w_btc_domzBTC Dominance Weightrf   r<   N)	i_w_us10yzUS 10Y Yield Weightrf   r<   N)i_w_spyz
SPY Weightrf   r<   N)i_w_goldzGold Weightrf   r<   N)i_w_mvrvzMVRV Z-Score Weight (discrete)On-Chain Regime Signalsr<   N)i_w_mvrv_contz MVRV Z-Score Weight (continuous)rn   r<   N)i_w_nuplzRealized Price NUPL Weightrn   r<   N)i_w_fed_net_liqzFed Net Liquidity Sign Weightrn   r<   N)i_w_gc_positionz Gaussian Channel Position Weightrn   r<   N)i_w_us2yzUS 2Y Yield WeightRates & Macror<   N)i_w_yield_curvezYield Curve (10Y-2Y) Weightrt   r<   N)i_w_qqq_spy_ratiozQQQ/SPY Ratio Weightrt   r<   N)i_regime_windowzRegime Filter Window (0=off)MVRV Macro RegimerJ   N)i_regime_entry_min_scorezRegime Filter Min Scorerx   r<   N)i_mvrv_suppress_bearzSuppress Entries in Bear Regimerx   r@   N)i_w_rsid_reg_bullzRSI Div Regular Bullish WeightRSI Divergence Signalsr<   N)i_w_rsid_reg_bearzRSI Div Regular Bearish Weightr|   r<   N)i_w_rsid_hid_bullzRSI Div Hidden Bullish Weightr|   r<   N)i_w_rsid_hid_bearzRSI Div Hidden Bearish Weightr|   r<   N)i_w_rsid_rt_bullz RSI Div Real-Time Bullish Weightr|   r<   N)i_w_rsid_rt_bearz RSI Div Real-Time Bearish Weightr|   r<   N)i_w_rsid_slow_bullzRSI Div Slowing Bullish Weightr|   r<   N)i_w_rsid_slow_bearzRSI Div Slowing Bearish Weightr|   r<   N)i_w_rsid_delayed_peakzRSI Div Delayed Peak Weightr|   r<   N)i_w_rsid_delayed_dipzRSI Div Delayed Dip Weightr|   r<   N)i_div_windowz)RSI Div Window (bars signal stays active)r|   rJ   N)
i_w_oi_roczPerp OI ROC WeightDerivatives & Market Structurer<   N)
i_w_usdt_dzUSDT Dominance ROC Weightr   r<   N)	i_w_basiszSpot-Perp Basis Weightr   r<   N)i_w_fear_greedz$Fear & Greed Index Weight (disabled)Sentiment & Sub-TF Signalsr<   N)i_w_btc_goldzBTC/Gold Ratio Weightr   r<   N)i_w_rsi_subtfz%Sub-TF RSI Weight (half chart period)r   r<   NCalmar RatioN/ASortino RatioSharpe RatioTotal P&L %Max Drawdown %Total Tradesr   r   N.4f	WFO_Score)Nr   zWFO-selectedzIS-Composite-selectedr   zH========================================================================u   
  OPTIMIZED PARAMETERS —     — z  [z]
  Composite: z  |  Calmar: z  |  Sortino: z  |  Sharpe: z
  WFO Score: z3  (mean OOS Calmar across 5 temporal folds)
  P&L: ,.1fz%  |  Max Drawdown: .2fz%  |  Trades: z1
  NOTE: Metrics above cover the SCORING WINDOW (    → z) only.

c                     | dk(  s| ||} 	 |dk(  rt        |       j                         dv rdS dS |dk(  rt        t        t        |                   S t        |       dS # t        $ r t        |       cY S w xY w)z=Format a param value; fall back to default if val is missing.r   r@   )true1r   falserJ   g)strlowerrJ   r<   	Exception)val	pine_typedefaults      r,   _fmtz#write_winner_readable.<locals>._fmt   s    5LCKW-@C	F"!$S!1]!BvOOe#3uSz?++*Q( 	s8O	s!   !A  A  !A  A   A76A7z
--- z ---z  (fixed Pine default)   z<48 z<12  ()i_w_uI   
--- ⚠ Unlisted params (add to PARAM_META in write_winner_readable) ---r<   optimization_winner_z_cheatsheet.txtr#   u   // === Optimized Defaults —  ===z
// Calmar z | Sortino z | P&L ,.0fz% | DD z% | Trades z!// Metrics above: scoring window z+ only (TradingView shows full history from zH// Replace the first argument of each input.float/bool/int() call below:z// --- z  // fixed Pine defaultz	 = input.(z, ...)u2   // --- ⚠ Unlisted params (add to PARAM_META) ---z = input.float(u    , ...)  // ⚠ add to PARAM_METAz_pine_snippet.pinez   >> [READABLE] Cheat-sheet: z   >> [READABLE] Pine snippet: )getdatetimedatetoday	isoformatr<   rJ   r   r   appendkeys
isinstancer   
startswithsortedospathjoinr(   r1   r   print))
winner_rowstrategy_nameresults_dirasset	timeframe
PARAM_METAcalmarsortinosharpepnlddtrades	composite_dtdate_strcomposite_str	wfo_scorewfo_strselection_labelasset_tfheaderr   keyr   _param_meta_keyslinescurrent_grouplabelgroupr   r   r   suffixval_strkunlistedcheatsheet_pathf
pine_linescomment	pine_paths)                                            r,   write_winner_readabler   <   s   FJP ~6F6G~6F}6C/6B~6F{6Ixx~~))+H1:e1CuY',M{D1I+4M+IeT]N^abNby!#&hmG(/5(8n>UO).%)%IH( &&.ZuXJc/AR S%mE&M#3FnUZ[bUcdgThhuv{  }C  wD  EH  vI Iy !*T""6uRyo^TWX]^dXeTfSg h;;F-uYKW`("	  ,66:a:6 HEM1;-UE9gM!LL6%-.!MnnS%(.1UlckwOb)hjsIw/r%Agc]#cU!F8DE 2< &??,z,a
1c0Bq||TZG[`aiy`y,Hzac(#C:>>#u5wEGLL2c#Ya}CuA>? $ ggll;2F}oUVW_V``o0pqO	os	#q			% 4'( 
$
 )
%zF
U6]3'{5>#2FgeTWjY]M^^efklnfopsett  AD  EJ  KQ  ER  AS  @T  	U
+K=i[Hst  tA  AB  	C
R
J M1;-UE9gM!wd34!MnnS%(sIw/03uQXQd+jlSIYyk7)6'ST 2< NO(#C:>>#u5wEGS		Aabc $ [,@qQYPZZl*mnI	i				*%,- 
 
*?*;
<=	+I;
78w 7$ { 
$	#: 
	s6   R>#S9SSS#$S	5$S	SSc                    dg}| j                         D ]  \  }}||v rd|v r|j                  dd      }d|gi| |<   )d|v s.d|v s3d|v s8	 t        |d         }t        |d         }t        |d         }||kD  r||}}|dk  r|dk7  rt        |      nd}|||z
  kD  r||k7  r||z
  dz  }||z
  d	z  }||k  r|}|||c|d<   |d<   |d<    | S # t        t
        f$ r Y w xY w)
z<Ensures parameter ranges are valid (start < stop, step > 0).rI   startr   valuesstopstep皙?g      @g     @@)itemsr   r<   abs
ValueError	TypeError)	paramslocked_paramsr   configr   r   r   r   min_steps	            r,   sanitize_paramsr      s>    ,,M||~V-Gv$5**Wa(C#cU+F3Kf6!1f6FfWo.VF^,VF^, 4<"&4E 19(,	3t9sD 4%<(Ud] 5LC/D !5LF2(?#DBGt?w= &B M 	* s   A>CC! C!c                     |yt        d       | j                         D ];  \  }}||v s	 t        ||         }d|v rd|v r||d   k  r||d<   ||d   kD  r||d<   = y# t        t        f$ r Y Pw xY w)z
    Ensures that the parameters from the winner_row are included in the search space
    defined by params. Modifies params in-place.
    Nz`   >> [SAFEGUARD] Extending search space to include global best parameters (preventing drift)...r   r   )r   r   r<   r   r   )r   r   r   r   best_vals        r,   ensure_winner_in_search_spacer     s    
 	
lm||~V* C1f$6)9&/1*2w&.0)1v & 	* s   0AA0/A0c                     t        j                  t        d       t        j                  t        d       t        j                  t        d       t        j                  t
        d       t        j                  t        d       t        j                  t              } | j                  d       | j                  d       | j                  d       | j                  d       | j                  d       | j                  d      j                         D ch c]  }|d	   	 }}t        t              t        t        j                               z   D ]+  }||vs| j                  d
| d       t!        d| d       - dD ]0  \  }}||vs| j                  d
| d|        t!        d| d       2 | j#                          | j%                          yc c}w )z@Create the sweep results database and table if they don't exist.T)exist_oka  
        CREATE TABLE IF NOT EXISTS sweep_results (
            id              INTEGER PRIMARY KEY AUTOINCREMENT,
            asset           TEXT    NOT NULL,
            timeframe       TEXT    NOT NULL,
            schema_ver      INTEGER NOT NULL DEFAULT 1,
            recorded_at     TEXT    NOT NULL,
            run_id          TEXT,
            train_start     TEXT,
            train_end       TEXT,
            score_start     TEXT,
            calmar_ratio    REAL,
            sortino_ratio   REAL,
            sharpe_ratio    REAL,
            pnl_dd_ratio        REAL,
            pnl_dd_percentile   REAL,
            total_pnl_pct       REAL,
            max_drawdown        REAL,
            total_trades        INTEGER,
            pct_in_market       REAL,
            i_long_entry_activation_threshold              REAL,
            i_long_exit_activation_threshold               REAL,
            i_long_exit_activation_confirmation_threshold  REAL,
            i_use_long_exit_confirmation                   INTEGER,
            i_use_long_entry_confirmation                  INTEGER,
            i_trailing_stop_threshold                      REAL,
            i_w_stoch                REAL,
            i_w_macd_pred            REAL,
            i_w_osc                  REAL,
            i_w_macd_bullish         REAL,
            i_w_m3_momentum          REAL,
            i_m3_momentum_period     REAL,
            i_w_m2_tiny              REAL,
            i_w_rsid_osc             REAL,
            i_w_stoch_div_osc        REAL,
            i_w_vwap_div_osc         REAL,
            i_w_stoch_peaking        REAL,
            i_w_stoch_bottoming      REAL,
            i_w_m3_div_osc           REAL,
            i_w_m2_div_osc           REAL,
            i_w_m2_div_osc_noOffset  REAL,
            i_w_bearish_engulfing           REAL,
            i_w_bullish_hammer              REAL,
            i_w_bullish_engulfing           REAL,
            i_w_shooting_star               REAL,
            i_cs_body_quality_ratio         REAL,
            i_cs_confidence_scaling_factor  REAL,
            i_cs_bull_eng_scaling_factor    REAL,
            i_w_btc_spx_corr  REAL,
            i_w_dxy           REAL,
            i_w_vix           REAL,
            i_w_btc_dom       REAL,
            i_w_us10y         REAL,
            i_w_spy           REAL,
            i_w_gold          REAL,
            i_w_mvrv          REAL,
            i_w_mvrv_cont     REAL,
            i_w_nupl          REAL,
            i_w_fed_net_liq   REAL,
            i_w_gc_position   REAL,
            i_w_us2y             REAL,
            i_w_yield_curve      REAL,
            i_w_qqq_spy_ratio    REAL,
            i_w_rsid_reg_bull    REAL,
            i_w_rsid_reg_bear    REAL,
            i_w_rsid_hid_bull    REAL,
            i_w_rsid_hid_bear    REAL,
            i_w_rsid_rt_bull     REAL,
            i_w_rsid_rt_bear     REAL,
            i_w_rsid_slow_bull   REAL,
            i_w_rsid_slow_bear   REAL,
            i_w_rsid_delayed_peak REAL,
            i_w_rsid_delayed_dip  REAL,
            i_w_oi_roc           REAL,
            i_w_usdt_d           REAL,
            i_w_basis            REAL,
            i_regime_window         REAL,
            i_regime_entry_min_score REAL,
            i_mvrv_suppress_bear    REAL,
            iteration_number        INTEGER,
            gpu_score               REAL,
            composite_score         REAL,
            subperiod_consistent    INTEGER   -- NULL=unchecked, 0=failed, 1=passed
        )
    zMCREATE INDEX IF NOT EXISTS idx_asset_tf   ON sweep_results (asset, timeframe)zICREATE INDEX IF NOT EXISTS idx_pnl_dd     ON sweep_results (pnl_dd_ratio)zCCREATE INDEX IF NOT EXISTS idx_run_id     ON sweep_results (run_id)zGCREATE INDEX IF NOT EXISTS idx_schema_ver ON sweep_results (schema_ver)z PRAGMA table_info(sweep_results)   z%ALTER TABLE sweep_results ADD COLUMN z REALz#   >> [DB] Migrated: added column 'z' to sweep_results))iteration_numberINTEGER)	gpu_scoreREAL)subperiod_consistentr   )search_strategyTEXTr   N)r   makedirsr	   r
   r   r   r   sqlite3connectSWEEP_DB_FILEexecutefetchalllist_PARAM_COLS_METRIC_TO_COLr   r   commitclose)connrexisting_colscolcol_types        r,   init_sweep_dbr  2  s   KKd+KKd+KK
T*KKd+KK
T*??=)DLL T T	j 	LL`aLL\]LLVWLLZ[ $(<<0R#S#\#\#^_#^aQqT#^M_K 4(=(=(?#@@m#LL@UKL7u<NOP A\Xm#LL@QxjQR7u<NOP	\ 	KKMJJL `s   Gpnl_dd_ratiototal_pnl_pctmax_drawdowntotal_tradespct_in_marketcalmar_ratiosortino_ratiosharpe_ratior   r   )
P&L/DD Ratior   r   r   % In Marketr   r   r   r   r   >   r   rw   rI   rz   rV   ry   rB   r`   r?   rA   rW   r=   r:   r>   c                    ddl }| D cg c].  }|j                  dd      dkD  r|j                  dd      dkD  r|0 }}|syt        dk(  rdndt        fd|D              }	t	        t        |	      dz
  d      }
|D ]0  }|j                  d	      }|	j                  |      }d
|z  |
z  |d<   2 |j                   j                         j                  d      }g }|D ]  }||t        ||t        t        t        |j                  d      |||j                  d      d|v r|j                  d      rdndnddt        j                         D ](  \  }}|j                  |      }|t        |      nd|<   * t         D ]%  }|j                  |      }|t        |      nd|<   ' |j#                          t%        |d   j'                               }dj)                  dt        |      z        }dj)                  |      }d| d| d}|D cg c]  t+        fd|D               }}	 t-        j.                  t0              }|j3                  ||       |j5                          |j7                          t9        dt        |       d       yc c}w c c}w # t:        $ r}t9        d|        Y d}~yd}~ww xY w)u  
    Writes all CPU-verified results with at least 1 trade and Sortino > -5 to the sweep database.
    Filters on trades + Sortino rather than P&L/DD so high-drawdown regime runs (e.g. sideways
    training verified on full IS) are still captured. P&L/DD is stored as-is and can be 0 when
    drawdown exceeds the 40% cap — that is an analysis detail, not a write gate.
    Called after each iteration so no data is thrown away.
    r   Nr   r         $r   c              3   B   K   | ]  }|j                  d         yw)        Nr   ).0r  rank_keys     r,   	<genexpr>z$write_to_sweep_db.<locals>.<genexpr>  s     ;(QAEE(C((   r   r         Y@_pnl_dd_percentileseconds)timespec	GPU_Scorer   )r   r   
schema_verrecorded_atrun_idtrain_start	train_endscore_startpnl_dd_percentiler   r   r   r   , ?zINSERT INTO sweep_results (z
) VALUES (r   c              3   (   K   | ]	  }|     y wr0   r8   )r"  crows     r,   r$  z$write_to_sweep_db.<locals>.<genexpr>  s     )DqCFDs   z   >> [DB] Saved z$ verified results to sweep database.z7   >> [DB] Warning: could not write to sweep database: )r   r   OPTIMIZATION_METRICr   maxlenindexnowr   DB_SCHEMA_VERr   r   r   r
  r   r<   r	  r   r  r   r   tupler  r  r  executemanyr  r  r   r   )verified_resultsr   r   r-  r   r   r   r  positivescoresnsidxr;  rows_to_insertsrcr  r   colsplaceholders	col_namessqlr6  r   r  er#  s                         `   @r,   write_to_sweep_dbrL    s    + V+a55+a/AEE.%4PST4T +H V
 2[@{nH;(;;FCK!OQAEE(C ll1o"'#+/
 
 ,,



&
&	
&
:CN"'&"&!"';!< 0.{+(>!(C +,%%0F*GQQIM
  ',,.HC%%*C%(_uSz$CH / C%%*C%(_uSz$CH  	c"/ 2 q!&&()D99S3t9_-L		$I'	{*\N!
LC5CD^ce)D))^FDM}-f%

!#n"5!66Z[\mV^ E  MGsKLLMs$   3JJ/A#J 	J>&J99J>c                    | \  }}}}ddl }ddl}ddlm} ddlm} 	 |j                  |j                  |            }	 |j                  |	fi |}
|j                  |
|      }|j                  |      }|j                  |
|
d   |k     j                         |      }|j                  |
|
d   |kD     j                         |      }|j                  dd      dk\  xrC |j                  dd      dk\  xr, |j                  dd      dk\  xr |j                  dd      dk\  |d	<   |j                         }|j                  |       d
|d<   |S # t        $ r Y yw xY w)u3  
    Worker function for parallel CPU verification.
    Must be at module level so pickle can serialise it for ProcessPoolExecutor.
    On Linux (fork), df_data_bytes is inherited from the parent — no actual copy.
    Runs two extra calculate_metrics calls (subperiod halves) to check IS consistency.
    r   N)r   r0  timer   r  r   r   Tverified)iopandas%strategies.strategy_activation_scoresstrategy_activation_scoresr   r   read_pickleBytesIOgenerate_signalscalculate_metricsto_datetimecopyr   updater   )argsparams_dictdf_data_bytesr0  optimization_metric_io_pd_strat_SPLITdf_datadf_resmetricssplit_tsm1m2results                   r,   _verify_onerk    s    DH@K-@:0//#++m"<=(((@K@**6{*K ??6*%%6&>X-.335; & P%%6&>X-.3356 & K FF>5)Q. W266/53QUV3V WFF>5)Q.W3566/53QUV3V 	&'
 !!#g!z s   D/E 	EEc                   8 t        d| dt         d       t        j                  j	                  |       s`t        d|         t        j                  j	                  t
              r.t        j                  t
              }t        dt
         d|        y	 t        j                  |       }|j                  ryt        |j                  v rt        nd}|j                  |d	
      j                  |      }t        j                  |      }	|	j                  j                  j                         |	_
        d|	j                  v rlt        j                  |	d   d      j                   j#                  d      |	d<   |	d   t$        k\  |	d   t&        k  z  }
|	j(                  |
   j+                         }	d}	 |	|	d   t        j                  t,              k\     }t/        |      dkD  r@|d   j0                  d   }|d   j0                  d   }t3        d||z
  j4                  dz        }t9        j:                         }|	j=                  |       |j?                         }|jA                         D cg c]  \  }}|jC                          }}}|D cg c]  }||t,        t        f }}g }t        jD                         xs d}t3        dtG        d|dz
              }t        d| dt/        |       d       tI        |      5 }|D ci c]  }|jK                  tL        |      |d    }}tO        |      D ]  }|jQ                         }|||   }|jS                  dd      |d<   |jS                  dd      }|jS                  dd      } tU        |jS                  dd            }!|jS                  dd      }"tW        || |!||"      }#|jS                  dd      sd}#|#|d <   |jS                  t        d      |d!<   |jY                  |        	 ddd       |sy"|D $cg c]  }$|$jS                  d d      dkD  s|$ }%}$d}&|%rt[        |%d# d$      dt\         }'t        d%t/        |'       d&t/        |%       d't/        t^               d(       ta        j`                         }(|'D cg c]  }||t^        tb        td        f })}tI        |      5 }tg        |)      D *ci c]  \  }*}|jK                  th        |      |* }+}*}tO        |+      D ]<  }|+|   },|jQ                         \  }-}.}/}0|-|'|,   d)<   |.|'|,   d*<   |/|'|,   d+<   |0|'|,   d,<   > 	 ddd       ta        j`                         |(z
  }1t        d-|1d.d/|1t/        |'      z  d0z  d1d2       |'D $ci c]  }$tk        |$      |$ }2}$|D ]s  }$tk        |$      |2v s|2tk        |$         jS                  d)d      |$d)<   |2tk        |$         jS                  d+d3      |$d+<   |2tk        |$         jS                  d,d      |$d,<   u t3        |'d4 5      }&tm        d6 |'D              }3g d78d8jo                  8fd9tg        |&jS                  d*g             D              }4t        d:|3 d&t/        |'       d;|&jS                  d d      d<d=|&jS                  d)d      d<d>|&jS                  d+d?      d<d@|&jS                  d,dA              t        dB|4        tq        |tr        tt        |||C       t        jv                  |      }5|5j                  t        d	
      j0                  d   }6t        dD|6d   d<dE|6d!   d<       |6|&fS # t6        $ r Y <w xY wc c}}w c c}w c c}w # 1 sw Y   oxY wc c}$w c c}w c c}}*w # 1 sw Y   OxY wc c}$w # t6        $ r}7t        dF|7        Y d}7~7y"d}7~7ww xY w)Gz
    Reads the sweep results, picks the top N by the optimization metric, and verifies them on CPU.
    Returns the best VERIFIED result row.
    z   >> [VERIFY] Verifying Top z GPU results on CPU (sorted by )...z%   >> [VERIFY] Sweep file not found: z   >> [VERIFY] Files found in : Nr   F)by	ascendingrO  Tutc       @r   r         ?     v@      z   >> [VERIFY] Launching z parallel workers for z candidates...)max_workersr*  r   r   r   r   r   r   	CPU_ScoreNNc                 &    | j                  dd      S )Nr   r   r!  xs    r,   <lambda>z$verify_top_results.<locals>.<lambda>  s    ~q9Qr.   )r   reversez   >> [WFO] Rescoring top /z2 eligible candidates (sorted by IS Calmar) across z	 folds...r   WFO_Fold_CalmarsWFO_Min_FoldWFO_Neg_Foldsz   >> [WFO] Completed in .1fzs (  .0fzms/candidate)     Xc                 l    | j                  dd      | j                  dd      | j                  dd      fS )Nr  r  r   r   r   r!  r}  s    r,   r  z$verify_top_results.<locals>.<lambda>  sE    ~u9UWXW\W\]hjmWnpqpupu  wB  DG  qH  9Ir.   r   c              3   L   K   | ]  }|j                  d d      dkD  sd  yw)r   r   r   Nr!  )r"  r  s     r,   r$  z%verify_top_results.<locals>.<genexpr>  s$      UKq155a;PST;TKs   $$)2021202220232024H1PoliRunz  |  c              3   :   K   | ]  \  }}|    d |d  yw)=z.3fNr8   )r"  ir5  fold_labelss      r,   r$  z%verify_top_results.<locals>.<genexpr>  s,      *8i1;q>"!Ac7+8is   z   >> [WFO] z( candidates pass WFO  |  WFO Winner: IS=r     WFO_Mean=z
  WFO_Min=iz  NegFolds=r3  z   >> [WFO] Fold Calmars: )r   r   z   >> [VERIFY] IS Winner: GPU=z -> CPU=z   >> [VERIFY] Error: )<r   r7  r   r   existsr	   listdirpdread_csvemptycolumnssort_valuesheadr   r   rY  dttz_localizer   r   locrZ  r   r9  ilocr8  daysr   rQ  rV  	to_picklegetvalueiterrowsto_dict	cpu_countminr   submitrk  r   rj  r   rJ   _composite_scorer   r   r   r   rO  r   r   	enumerate_wfo_score_oneidsumr   rL  ASSET	TIMEFRAME	DataFrame)9
sweep_file	data_filetop_nr-  r   r   filesdf_sweepgpu_sort_colrd  maskis_yearsdf_score_windowt0t1_bufr^  r   r6  candidate_paramspworker_argsr?  r  ry  executorafuturesfutrj  original_paramsr   r   r   r   r   r  eligible
wfo_winnertop_for_wfo_wfo_t0wfo_argsr  wfo_futuresrD  r   fold_calmarswfo_minwfo_neg_wfo_elapsed
wfo_lookupn_positive_wfobest_folds_strdf_verifiedbest_verifiedrK  r  s9                                                           @r,   verify_top_resultsr  3  s   
 
)%0OPcOddh
ij77>>*%5j\BC77>>+&JJ{+E2;-r%IJB;;z*>>$ /BXEUEU.U*[i''<5'INNuU++i(!//--335W__$ nnWV_$GJJVVW[\GFOFO{2wv)7STDkk$',,.G 	%gfo9T&TUO?#a'$V,11!4$V,11"5sR"WNNV$;<
 zz|$8@8I8I8KL8KfaCKKM8KLUefUePQ=+7JKUefLLN'a	 !SIM23)+6LSQaMbLccqrs [9XFQRkx{A6!<kGR#G,%&-clO*9*=*=na*PF;'  &zz.#>F%zz/3?G"6::na#@AF%zz-=C 0&(TW XI!::&<dC$'	*3F;'*0**5H!*LF;'$++F3# - :*  
  0M/!155a3H13LA/M
 !/Q[_`akbklK.s;/?.@#h- Q225i.1AL MiikG %$A M9.@BUV$   %=QZ[cQdeQdAx~qA1DQde'4C%c*C@C

=I|Wg4=K$[1;GK$%787>K$^48?K$_5 5 >  99;0L-l3-?s<PST_P`C`aeCefiBjjwxy -88Kq"Q%(KJ8%a5J&%/1%6%:%:;%LAkN(22a5(9(=(=ne(TAn%)3BqE):)>)>PQ)RAo&	 & [  /I  JJ  UK UUNGK$\\ *8A*..QcegBh8i* N L 0#k2B1C D$$.NN;$B3#G{S]SaSabmopSqruRv w'^^NC@E[Q[Q_Q_`oqtQuPvx y .~.>?@*E9fWg  zI  	Jll#34#//3FRW/X]]^_`.}[/I#.NhWdepWqruVvwxj((M  		 Mf S :96 N
 f >= 9<  &qc*+s   !^  :C6^  1A0] !A^  )]!^  
]'A^  ;]1 !],!"]1B?]1
^  ^  ]>.]>2A)^  ^5^  ^!^3A^A^  ^^  /F!^  	]^  ]^  ,]11];6^  ^^^   	_)^<<_c                    | \  }}}}}ddl }ddl}ddl}ddlm}	 	 |j                  |j                  |            }
g }|D ]  \  }}}|
|
d   |j                  |      k     j                         } |	j                  |fi |}||d   |j                  |      k     j                         }|	j                  ||      }t        |j                  dd            }||k\  s|j                  |j                  dd              t        |      |k  rd|dt        |      fS t        t!        |            }t#        d	 |D              }t        |j%                  |            |||fS # t&        $ r	 dg ddfcY S w xY w)
a$  
    Worker: evaluate one candidate across all WFO OOS folds.

    For each fold (is_end, oos_start, oos_end):
      - Generate signals on all data up to oos_end (IS warms up crossunder state).
      - Score only the OOS slice [oos_start, oos_end].
      - Record OOS Calmar if OOS trade count >= min_oos_trades.

    Returns (wfo_score, fold_calmars) where wfo_score = mean(fold_calmars) when
    at least min_valid_folds qualify, otherwise (0.0, fold_calmars).

    Must be at module level so pickle can serialise it for ProcessPoolExecutor.
    r   NrO  rN  r   r   r  r   c              3   ,   K   | ]  }|d k  s	d  yw)r   r   Nr8   r"  r5  s     r,   r$  z!_wfo_score_one.<locals>.<genexpr>  s     7AQas   
)rQ  rR  numpyrS  rT  rU  rV  rY  rZ  rW  rX  rJ   r   r   r9  r<   r  r  meanr   )r\  r]  df_full_bytesfoldsmin_oos_tradesmin_valid_foldsr`  ra  _nprb  df_fullr  is_end	oos_startoos_end	df_window
df_signalsdf_oosrf  
oos_tradesr  r  s                         r,   r  r    s~    JNFK~:!//#++m"<=,1(VY3??73K KLQQSI000JkJJ
6 2coog6N NOTTVF..v9.MGW[[;<J^+##GKK$FG -2 |.eS->>>L)*777SXXl+,lGWLL !Bq  !s   CE" ?E" AE" "E43E4c           
         t         j                  j                  t        d|  dt         dt
         d      }t         j                  j                  |      syt        d       	 t        j                  |      }|j                  ry|j                  d   }|j                  t        d      }t        j                  |      }|j                  j                  j!                         |_        d|j                  v rlt        j"                  |d   d	      j$                  j'                  d      |d<   |d   t(        k\  |d   t*        k  z  }|j,                  |   j/                         }|j1                         }t3        j4                  |j/                         fi |}	t3        j6                  |	t8        
      }
t        dk(  r	 ||d   t        j"                  t8              k\     }t;        d|d   j                  d   |d   j                  d   z
  j<                  dz        }tA        |
j                  dd      |
j                  dd      tC        |
j                  dd            ||
j                  dd            |
d<   |
j                  t        d      }tE        ||z
        dkD  r`t        d|dd|dd       |
jG                         D ]  \  }}||jH                  d|f<    |jK                  |d       |j                  d   }nt        dt         d|dd       tM        || t        t        t
               |S # t>        $ r d}Y %w xY w# t>        $ r}t        d |        Y d}~yd}~ww xY w)!z
    Checks if the winner file exists and if its recorded metrics match a CPU backtest.
    If there's a discrepancy, it updates the file with the correct CPU metrics.
    r   r   .csvNz6   >> [SANITY CHECK] Verifying existing winner file...r   rO  Trq  rN  r   ru  rt  rv  rs  r   r   r   r   r   gư>z1   >> [FIX] Winner file score changed (Recorded: r   u
    → CPU: z). Updating...Fr:  z+   >> [SANITY CHECK] Winner file is valid (rn  z).r   r   z7   >> [SANITY CHECK] Failed to verify/fix winner file: )'r   r   r   r
   r  r  r  r   r  r  r  r  r   r7  r  r   r   rY  r  r  r   r   r  rZ  r  strategy_modulerW  rX  r   r8  r  r   r  rJ   r   r   atto_csvr   )r   r  winner_filedfr6  recorded_scorerd  r  r   re  rf  
df_score_wis_yrs	cpu_scorer   vrK  s                    r,   sanitize_winner_filer    s   
 '',,{.B=/QRSXRYYZ[dZeei,jkK77>>+&	BD-M[[%88Vggaj!4a8++i(!//--335W__$ nnWV_$GJJVVW[\GFOFO{2wv)7STDkk$',,.G 11',,.KFK!33FT+-$WV_{8S%ST
S:f#5#:#:2#>FASAXAXYZA[#["a"adj"jk $4NC0'++os2SGKK23VW[[X[=\$^GK  KK 3Q7	~	)*T1EnUXEYYcdmnqcr  sA  B  C1ad (IIkI/''!*C?@S?TTVW`adVeeghi 	c=+UV_`)  ,  MGsKLLMsE   #!M D5M ;AL0 DM 0L?;M >L??M 	M#MM#c                    ddl }t        j                  j                  t        d|  dt
         dt         d      }t        j                  j                  |      sy	 t        j                  |      j                  d   }|j                         }t        j                  |      }|j                  j                  j                         |_        d|j                  v r6t        j                  |d   d      j                   j#                  d      |d<   t%        j&                  |j)                         fi |}t        j                  t*              }||d   |k     j)                         }	t%        j,                  |	t.        	      }
t%        j,                  |t0        	      }d|j                  v r!|d   j                  d
   j3                  d      nd}d } ||
      \  }}}}}}}} ||      \  }}}}}}}}|dk(  rd}n||dk(  rd}nt|dk  r|dk\  rd|ddn|dd}d| d| d}nS|dk  rd| d}nG|dk  rd|dd}n:|dkD  r||z  nd} | dk\  rd| dd}n!| d k\  rd!| dd}n| d"k\  rd#| dd}nd$| dd}d%t
         d&t         d'|j                   j5                         j3                  d(       d)d*d+d,t.         d-t*         d.|d/d0|d1d0|dd.|dd.|dd.| d.|dd0|dd2d3t0         d-| d.|d/d0|d1d0|dd.|dd.|dd.| d.|dd0|dd2d)d4| d)d5d6d7g}!t        j                  j                  t6        d8t
         dt         d9      }"t9        |"d:      5 }#|#j;                  d;j                  |!      d;z          ddd       t=        d<|"        t=        d=|dd>|d/d?|        t=        d@|dd>|d/d?| dA|j?                  dB      d    d	       y# 1 sw Y   ZxY w# t@        $ r}$t=        dC|$        Y d}$~$yd}$~$ww xY w)Du#  
    Runs the current winner on the FULL data (training + OOS) and writes a
    side-by-side in-sample vs out-of-sample performance report to
    results/performance_report_{ASSET}_{TIMEFRAME}.md.

    In-sample  : SCORE_START → TRAIN_END
    Out-of-sample : OOS_START → end of data
    r   Nr   r   r  rO  Trq  rN  rt  z%Y-%m-%dr3  c                 H   | j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }t        | j                  dd            }| j                  dd      }| j                  d	d      }||||||||fS )
Nr   r   r   r   r   r   r   r  r  )r   rJ   )	mr   r   sortsharpcalmtrmktpdds	            r,   fmtz%write_performance_report.<locals>.fmtP  s    EE-+CEE*A.BEE/1-DEE.!,EEE.!,Dna01BEE-+CEE.!,CD%r3;;r.   u+   ⚠ No in-sample trades — cannot evaluateu   ⚠ No OOS trades yet
   +r  %u   ⚠ FEW OOS TRADES (u
   ) — P&L=u(    (need ≥10 for Sortino to be reliable)g      u   ) — Sortino not reliableu#   ❌ POOR — negative OOS Sortino (r   r   g?u!   ✅ EXCELLENT — OOS Sortino is z.0%z of in-sampleru  u"   ✅ ACCEPTABLE — OOS Sortino is       ?u   ⚠ WEAK — OOS Sortino is u   ❌ POOR — OOS Sortino is u   # Performance Report — r   zGenerated: %Y-%m-%d %H:%M:%Sr   z\| Window | Period | P&L | Max DD | Sortino | Sharpe | Calmar | Trades | In Market | P&L/DD |z\|--------|--------|-----|--------|---------|--------|--------|--------|-----------|--------|z| **In-Sample** | r   z | r   z% | r   z |z| **Out-of-Sample** | z**Verdict:** z---z_*In-sample metrics use the scoring window only (crossunder signals generated on full history).*z$*Generated by auto_optimize_loop.py*performance_report_z.mdr#   r   u#      >> [OOS] Performance report → z   >> [OOS] In-sample  Sortino=  P&L=
%  Trades=z   >> [OOS] Out-sample Sortino=r   r   z3   >> [OOS] Failed to generate performance report: )!r   r   r   r   r
   r  r  r  r  r  r  r  r  r   r   rY  r  r  r  rW  rZ  r   rX  r   r   strftimer;  r   r(   r1   r   splitr   )%r   r  r   r  r6  r   r  r  train_end_tsdf_is
is_metricsoos_metricsoos_lastr   ipiddisoishicaitriimipddopoddosooshocaotroimopddverdict	directionratior   out_pathr   rK  s%                                        r,   write_performance_reportr$  -  s    '',,{.B=/QRSXRYYZ[dZeei,jkK77>>+&RIkk+&++A.++i(!//--335W__$ nnWV_$GJJVVW[\GFO$55gllnOO
 ~~i0:f-=>CCE$66u+V
 &77
PYZDJgooD]76?''+44Z@cf		< 25Z.Cc3S$14[1A.Cc3S$ !8CGAX-G2X)+q!Bs81ClI,SEI;FnoGD[,SE1KLG1W;C9AFG!$qC#IaE|=eC[V#>uSkW$8s=Q8s=Q (wa	{;#,,**,556IJKLjj U9+SD	cRUYVZ[^_bZccfgjknfoorsvwzr{{~  @C  D  DG  HK  LO  GP  PT  UY  Z]  T^  ^`  a$YKuXJc"T$sSViW[\_`c[ddghklogppstwx{s||  AD  @E  EH  IL  MP  HQ  QU  VZ  [^  U_  _a  bG9%m2
  77<</B5'9+UX-YZ(C AGGDIIe$t+, !3H:>?/Cyr$izRUQVWX/Cyr$izRUQVVYZaZgZghoZpqrZsYttuvw	 !   ICA3GHHIs2   K;O  $O;AO  OO   	P)O<<P)gMbP?gMb`?g{Gzt?g{Gz?g{Gz?g?r   g?r  ru  r         r        2   d      i  c                 ,     t        t         fd      S )z>Rounds a raw step to the nearest clean value from _NICE_STEPS.c           	          t        t        j                  t        | d            t        j                  t        d            z
        S )Ng-q=)r   mathr)   r8  )rC  raws    r,   r  z_nice_step.<locals>.<lambda>  s1    #dhhs1e}.EQTUXZ_Q`Ha.a*br.   r  )r  _NICE_STEPS)r/  s   `r,   
_nice_stepr1    s    { bccr.   c                 x   d}d}d}	 t        | d      5 }t        j                  |      }ddd       t	        |       }|dkD  r||z  dz  nd}t        d	d
        t        d       t        d
        t        dt        |              t        dt        |              t        d|dd       g }	j                         D ]  \  }
}d|vsd|vsd|vrt        |d         }t        |d         }t        |d         }||z
  }|dk  s|dk  rMt        dt        ||z              }||kD  s||k  sp||z  }t        |      }t        dt        ||z              }||d<   |	j                  |
||||f        |	rt        dt        |	       d| d       |	D ]1  \  }
}}}}||kD  rdnd}t        d| d|
dd|dd|d d!| d|        3 t        | d"      5 }t        j                  ||d#$       ddd       t        d%|         nt        d&| d'| d(       t        | d      5 }t        j                  |      }ddd       g }j                         D ]r  \  }
}d|v sd|v sd|v st        |d         t        |d         z
  }t        |d         }|dkD  sF|dkD  sL|j                  t        dt        ||z                     t |rt        d)t        |       d*t!        |      t        |      d+z      d*t        |              |D cg c]
  }||k  s	| }}|D cg c]
  }||kD  s	| }}|s|r%t        d,t        |       d-t        |       d.       nt        d/| d'| d0       t        d
 d	       y# 1 sw Y   TxY w# t        $ r Y yw xY w# 1 sw Y   xY w# 1 sw Y   nxY wc c}w c c}w )1z
    Reports parameter coverage, then auto-adjusts any params whose step is
    so fine (>50 values) or so coarse (<3 values) that random search will be
    ineffective.  Target: ~20 values per param.  Saves the file if changed.
    r'  r)  r   r  Nr   r*  r&  r   <============================================================z  PARAMETER COVERAGE ANALYSISz  Search Space : z  Total Samples: z  Coverage     : z.6fr  r   r   r   r   z
  Auto-adjusted z param(s) to ~z values each:FINECOARSEz    [z] z<42r   z>4u   →z<4z values  step r#   rw  indentz  Saved adjusted params to z
  All params already in [u   –u(   ] values range — no adjustment needed.z,
  Per-param value counts (min/median/max): z / r%  u     ⚠  z over-fine, z/ over-coarse after adjustment (check manually).u#     ✓  All range-based params have z* values. Random search is well-calibrated.)r(   jsonloadr   calculate_search_spacer   format_quantityr   r<   r8  roundr1  r   r9  dumpr  r   )params_filetotal_samplesTARGET_VALUES
MAX_VALUES
MIN_VALUESr   r   total_spacecoverage_pctadjustmentsr   r   r   r   r   rng
num_valuesraw_newnew_step	new_countold_nold_snew_nnew_stag
adj_paramsper_param_countscfgr5  crampedbloateds                                  r,   analyze_params_coveragerU    s    MJJ+s#qYYq\F $
 )5K:E/MK/#5uL	Bvh-	)+	VH	ok:;
<=	om<=
>?	l3/q
12K||~V& F&$8F&<PfWo&fVn%fVn%u19qE#*-.

"j:&=m+G"7+HAuS8^45I%F6NZy(KL# && "3{#3"4N=/Q^_`/:+Cue!J.&HCE#bS	5*CbzPUwVYZ_Y`ab 0; +s#qIIfa* $+K=9:+J<s:,Fnop
 
k3	1YYq\
 
 $$&Sc>fm#V%c'l(;;CV%DaxC!G ''AuS4Z/@(AB ' =%&'s62B+CCHXDY[\D\+]*^^abefvbwaxz 	{.A.!j.1.A.A.!j.1.AgGCL>c'l^Crst7
|3zlR|}~	VHB-I $# L $# 
 	 BAsW   N	 M<N	 N#N%
N2N2!
N7,N7<NN	 		NNN"%N/rC   
stoch_normrE   macd_pred_normrF   osc_normrG   macd_bullish_normrH   m3_momentum_normrK   m2_tiny_normrL   	rsid_normrM   stoch_div_normrN   vwap_div_normrO   stoch_peak_normrP   stoch_bot_normrQ   m3_div_normrT   bearish_engulfing_scorerS   m2_nooff_normrR   m2_div_normre   btc_spx_corr_30rg   dxy_roc_normvix_pctrank_invbtc_dom_roc_signus10y_roc_inv_signspy_above_200emagold_roc_pctrankmvrv_zscore_valuemvrv_zscore_contzscore	nupl_normfed_net_liq_signgc_position)rh   ri   rj   rk   rl   rm   ro   rp   rq   rr   rX   r_   ra   c                     ddl } d}d}t        j                  j                  |      syt        j                  j	                  |      }t        j                  j                  |      st        d       t        d       t        d       t        d       t        d	       t        d
       t                t        d       t        d       t        d       t        d       t        d       yt        j                  j	                  |      }||kD  rddlm} |j                  |      j                  d      }|j                  |      j                  d      }t        d       t        d       t        d       t        d       t        d|        t        d|        t                t        d       t        d
       t                t        d       t        d       t        d       t        d       yy)z
    Warn if the Pine strategy file has been modified since it was last confirmed
    to compile in TradingView. Gives a 10-second countdown so the user can Ctrl+C
    to fix the Pine file first, preventing a wasted optimization run.
    r   Nz*strategies/strategy_activation_scores.pinez.pine_tv_validatedG
======================================================================u   ⚠️  PINE VALIDATION WARNINGF======================================================================z?  The Pine strategy file has NEVER been confirmed to compile inz>  TradingView. If it has compile errors, this optimization runz*  will produce weights that can't be used.z?  To dismiss this warning permanently, paste the Pine file intoz-  TradingView, confirm it compiles, then run:z.      python3 tools/check_pine.py --mark-validr  )r   r  zC  The Pine strategy file was modified AFTER the last TV validation.z  Pine modified:   z  Last validated:  z?  If the edits introduced compile errors, this optimization runz&  After verifying in TradingView, run:)
rO  r   r   r  getmtimer   
_countdownr   fromtimestampr	  )_time	pine_filesentinel_file
pine_mtimesentinel_mtimer   pine_dtsent_dts           r,   _check_pine_validation_sentinelr    s    <I(M77>>)$!!),J77>>-(o/0hOQNP:<c
OQ=?>@h2WW%%m4NN",##J/889LM##N3<<=PQo/0hSU#G9-.#G9-.c
OQ:<c
68>@h2# #r.   c                    ddl }ddl}	 t        | dd      D ]L  }|j                  j	                  d| d       |j                  j                          |j                  d       N |j                  j	                  d       |j                  j                          y# t        $ r t        d       |j                  d       Y yw xY w)	z,Print a countdown, allowing Ctrl+C to abort.r   Nrt  z  Continuing in zs... (Ctrl+C to cancel)  r   z2  Continuing...                                

z

  Run cancelled by user.)
rO  r%   ranger&   r1   r2   sleepKeyboardInterruptr   exit)r(  rx  _sysr  s       r,   rv  rv  D  s    	w2&AKK 21#5NOPKKKKN ' 	QR ,-		!s   BB %CCc                    	 t        |       5 }t        j                  |      }ddd       t        t              }D cg c]  }|j                  d      s||vs| }}|syt	                t	        d       t	        d       t	                t	        d       t	        d       t	        d       t	                t        |      D ]  }t	        d	|         t	                t	        d
       t	        d       t	        d       t	                t        j                  d       y# 1 sw Y   xY w# t        $ r}t	        d|        Y d}~yd}~ww xY wc c}w )u  
    Pre-run sync check: ensure every i_w_* param in the params JSON is also in
    config.WEIGHT_COLS. If any are missing, they will be silently skipped by the
    sweep dashboard and SHAP — wasting a long optimization run.

    This is a hard stop (non-interactive) because a missing entry in WEIGHT_COLS
    means results will be incomplete regardless of how long the run takes.
    Fix: add the missing param(s) to WEIGHT_COLS in config.py, then restart.
    Nz8   >> [WARN] Could not read params file for sync check: r   rt  uM      >> [ERROR] PARAMS/CONFIG OUT OF SYNC — aborting before wasting run time.z?   The following i_w_* params are in the params JSON but NOT inzA   config.WEIGHT_COLS. Results for these signals will be silentlyz@   missing from the sweep dashboard and SHAP importance reports.      zI   Fix: add the param(s) above to WEIGHT_COLS in config.py, then restart.uH      The DB migration runs automatically — no manual ALTER TABLE needed.r   )r(   r8  r9  r   r   setr   r   r   r%   r  )r>  r   r   rK  weight_cols_setr   missings          r,   validate_params_syncr  T  s   +!YYq\F  +&O V&QALL$8Qo=Uq&GV	G	(O	
YZ	G	
KL	
MN	
LM	GG_qcl 	G	
UV	
TU	(O	GHHQK7  HLM
 Ws>   D- D!D- EEE!D*&D- -	E6E		Ec            	      (   ddl } t        j                  j                  t        j                  j	                  t        j                  j	                  t        j                  j                  t                          ddd      }t        | j                  |            }|syt        t              dhz  }g }|D ]s  }	 t        |      5 }t        j                  |      }ddd       |D cg c]	  }|vs| }	}|	sD|j                  t        j                  j                  |      |	f       u |syt!                t!        d       t!        d       t!                t!        d	       t!        d
       t!        d       t!                |D ])  \  }
}	t!        d|
 d       |	D ]  }t!        d|         + t!                t!        d       t!        d       t!                t#        j$                  d       y# 1 sw Y   xY w# t        $ r Y Uw xY wc c}w )aq  
    Hard stop if ANY of the 20 active params files is missing a key from WEIGHT_COLS
    or i_div_window. Catches the case where config.py was updated but sync_params.py
    wasn't run, which would cause SHAP/dashboard to report MISSING FROM SOME PARAMS
    and silently treat those weights as zero in affected runs.

    Fix: python3 tools/sync_params.py --apply
    r   N
strategiesr   z*params_strategy_activation_scores_*_*.jsonr   rt  uL      >> [ERROR] PARAMS FILES OUT OF SYNC — aborting before wasting run time.zA   The following active params files are missing keys that are inzD   config.WEIGHT_COLS (or i_div_window). SHAP will show MISSING FROMz@   SOME PARAMS warnings and those weights will be silently zero.r  :z        z,   Fix: python3 tools/sync_params.py --applyr   )globr   r   r   dirnameabspath__file__r   r  r   r(   r8  r9  r   r   basenamer   r%   r  )_globpatternr  expected	bad_filesr   r   r  r   r  fnames              r,   _validate_all_params_syncr  }  s    ggll277??277??277??8;T+UV'3_aG5::g&'E;>"22HI	dqIIaL  '5h!1*1h5bgg..t4g>?  	G	(O	
XY	G	
MN	
PQ	
LM	G#wugQ AHQC.!  $ 
G	
89	(O	GHHQK3  		5s6   :G?G2G?'	H1H2G<	7G??	HHc                    	 t        |       5 }t        j                  |      }ddd       t        j                  |d      }t        d |j                  D              g }D ]  }|j                  d      st        j                  |      }|-||   }	t        |	t              r"|	j                  d      }
|
t        |
      dk(  rdt        fd	|D              ry|j!                  ||f        |syt                t        d
       t        d       t                t        d       t        d       t        d       t                |D ]0  \  }}t        d|        t        ddj#                  |              2 t                t        d       t        d       t        d
       t                t$        j&                  j)                         rbt+        d      j-                         j/                         }|dk7  r t        d       t%        j0                  d       t        d       t                yt        d       t                y# 1 sw Y   'xY w# t        $ r}t        d|        Y d}~yd}~ww xY w)a  
    Check that every i_w_* param in the params file has a corresponding column
    in the data CSV. If any are missing, the optimizer silently treats them as
    all-zero (wasted search budget). Warn the user and prompt to continue or quit.

    Normal action on warning: quit, re-export TV chart data with the missing
    columns included in data/, then restart the optimization run.
    Nr   )nrowsc              3   X   K   | ]"  }|j                         j                          $ y wr0   )r   stripr  s     r,   r$  z(validate_data_columns.<locals>.<genexpr>  s     B/Qqwwy(/s   (*z.   >> [WARN] Could not validate data columns: r   r   r   c              3   B   K   | ]  }|j                         v   y wr0   )r   )r"  r5  csv_colss     r,   r$  z(validate_data_columns.<locals>.<genexpr>  s     =*Q1779(*r%  rt  zE   >> [WARNING] Missing CSV columns for weight params in params file.zD   The following params are in the search space but have NO matchingzE   column in the data CSV. The optimizer will treat them as all-zero,z7   wasting search budget on params that have no effect.r  z        expected column(s): r2  zB   Normal action: quit now, re-export the TV chart data to includez>   the missing indicator columns, save to data/, then restart.z   Continue anyway? [y/N]: yz4   Aborting. Update your TV data export and restart.z3   Continuing with missing columns treated as zero.z\   [NON-INTERACTIVE] Continuing automatically (batch mode). Missing columns treated as zero.)r(   r8  r9  r  r  r  r  r   r   r   _WEIGHT_TO_CSV_COLSr   r   dictr9  anyr   r   r%   stdinisattyinputr  r   r  )r>  r  r   r   df_headrK  r  r   
candidatespdefvalsrG  answerr  s                @r,   validate_data_columnsr    s   +!YYq\F ++iq1B'//BB
 G~~f%(,,S1
c{dD!88H%DCIN=*==NNC,-  	G	(O	
QR	G	
PQ	
QR	
CD	G	Tsen,TYYt_,=>?  
G	
NO	
JK	(O	G
yy45;;=CCES=HIHHQKCD 
G 	lm	Gg   >qcBCs-   I I	;I 	II 	I7I22I7c                 v   	 t        | d      5 }t        j                  |      }ddd       d}j                         D ]]  \  }}d|v r>d|v r:d|v r6|d   |d   |d   }}}|dk  r't	        dt        ||z
  |z              }	||	z  }Hd|v sM|t        |d         z  }_ |S # 1 sw Y   }xY w# t        $ r Y yw xY w)	zGCalculates the approximate size of the search space from the JSON file.r  Nr   r   r   r   r   r   )r(   r8  r9  r   r8  rJ   r9  r   )
r>  r   r   totalr   r   r   r   r   counts
             r,   r:  r:    s    +s#qYYq\F $!<<>KC& Vv%5&F:J$*7OVF^VF^Tt19hAsD5LD#89:V#VH-.. *  $#  s.   B, B A&B, B,  B)%B, ,	B87B8c                     | dk\  r	| dz  ddS | dk\  r	| dz  ddS | dk\  r	| dz  ddS | dk\  r	| dz  dd	S | d
k\  r	| d
z  ddS | dk\  r	| dz  ddS | dk\  r	| dz  ddS | dS )z6Formats numbers with suffixes (million, billion, etc).l      B3v^!< r   z septillionl     @=7M.cz sextillionl     NZoz quintillionl     I5 z quadrillionl    J)z	 trillioni ʚ;z billion@B r  z million,r8   )rB  s    r,   r;  r;    s    --55c:+FF	
+	+11#6kBB	
'	'--c2,??	
#	#))#.l;;	
	%%c*)44	
m	M/#&h//	
iI+c"(++Ar.   c                     | dk  rd| ddS t        | dz        }t        | dz        }|dk  r	d| d| dS t        |dz        }|dz  }d| d| dS )z7Formats seconds into a friendly string (e.g. '6m 20s').<   ~r  rC  zm zh r  )rJ   )r(  r  rC  hs       r,   format_durationr    s{    |73-q!!GrMAGbLA2v1#Rs!}AGA	BAqcA3a=r.   c                     t        t              }|dkD  rt        ||       n| }|dkD  r||k  rdnd}|dk(  rt        |t        z        nd}t        d| dt        |       dt        |       d       t        d	| d
       dddt        dt        dt        dt        dt        dt        |       ddt        d| dt        dt        dt        t              dt        t               g}t        ddj#                  |              t$        j&                  j)                         }t$        j*                  j-                  d      r-|j/                  dd      }d|vr|r| dnd|d<   t        d        t1        j2                  |d!|t$        j4                  t0        j6                  t0        j8                  d"#      }	d$ }
t;        j<                  |
|	fd!%      }|j?                          d&}	 |	jA                  |'      }|j#                          |dk7  r$t        d(| d)       tC        jD                  d"       y# t0        jF                  $ r t        d*|d+z   d,       t        d-       dd.l$}t%        jJ                  t%        jL                  |	jN                        |jP                         tS        jT                  d/       t%        jJ                  t%        jL                  |	jN                        |jV                         |j#                  d0'       t        d1       Y yw xY w)2z
    Runs the existing optimize_strategy.py script using Popen for better process control.
    Includes a timeout and forceful termination to prevent hangs.
    r   GridRandomz
N/A (Grid)z   >> Running z search (Space: z | Sample: rm  z   >> Estimated Time: z (GPU)python3zstrategies/optimize_strategy.py--dataz--strategy_filez--params_filez--assetz--timeframez--random_searchz--gpuz--metricz--baseline-score=--search--regime--regime-bear-threshold--regime-bull-thresholdz   >> Executing: r   z/usr/lib/wsl/libLD_LIBRARY_PATHr   z:/usr/lib/wsl/libzQ   >> [WSL CONFIG] Injected /usr/lib/wsl/lib into LD_LIBRARY_PATH for GPU access.Tr   )textenv
preexec_fnr&   stderrbufsizec                 B    | j                   D ]  }t        |dd        y )Nr   T)endr2   )r&   r   )proclines     r,   _streamz!run_optimization.<locals>._streamG  s    KKD$Bd+  r.   )targetr\  daemoni  )timeoutz3   >> [ERROR] Optimization script exited with code .z4
   >> [ERROR] Optimization process timed out after r  z	 minutes.z-   >> Forcefully terminating process group...Nr%  r&  zT   >> Process terminated. The loop will continue, but the underlying issue persists.),r:  PARAMS_FILEr  r  GPU_RATEr   r;  	DATA_FILESTRATEGY_FILEr  r  r   r7  SEARCH_MODEREGIMEREGIME_BEAR_THRESHOLDREGIME_BULL_THRESHOLDr   r   environrZ  r   r  r   
subprocessPopensetsidPIPESTDOUT	threadingThreadr   waitr%   r  TimeoutExpiredsignalkillpggetpgidpidSIGTERMrO  r  SIGKILL)iteration_samplesbaseline_scorerC  effective_iterationssearch_methodest_time_strcmdr  
current_ldprocessr  stream_threadtimeout_secondsreturn_coder  s                  r,   run_optimizationr    s   
 )5KBMPQ/3{,=>Wh)Ao+AU2UF[cMGTX`G`?#7(#BCfrL	N=/)9/+:V9WWbcr  tH  dI  cJ  JN  O  P	"<.
78 	4)=5y301'
N+,KF!3'<#=!3'<#=C" 
chhsm_
-.
**//
C	ww~~()WW.3
Z/IS
|3D%EYkC!"efs3299&0ooj>O>OYZ\G, $$G7*TRMOfll?l;!G}TUVWHHQK  $$ 
fEoXZFZE[[def=>
		"**W[[)6>>:

1
		"**W[[)6>>:1%de
fs   AH* *C LLc            
      F   t         j                  dd      j                  dd      } t        j                  j	                  t
        d|  dt         dt         d      }t        j                  j                  |      r$t        j                  |      }|j                  d   S t        d       t        j                  j	                  t
        d	|  dt         dt         d      }t        j                  j                  |      r"t        j                  |      j                  d   S y
)zIReads the best result from the CURRENT run (optimization_run_best_*.csv)..pyr   	strategy_optimization_run_best_r   r  r   zr   >> [INFO] 'Run Best' file not found (Run likely produced no trades/improvement). Falling back to Global Winner.r   N)r  replacer   r   r   r
   r  r  r  r  r  r  r   )r   run_best_filer  r  s       r,   get_run_best_resultr  f  s    !))%4<<["MMGGLL0F}oUVW\V]]^_h^iim.noM	ww~~m$[['wwqz  C  	Eggll;2F}oUVW\V]]^_h^iim0no77>>+&;;{+0033r.   c                  0   t        j                  dt         j                  d      } | j                  dt        d d       | j                  dt
        d	       | j                  d
ddd       | j                  dddd       | j                  dddd       | j                  dt        dddgd       | j                  dt        d d       | j                  dt        dg d d!       | j                  d"t
        t        d#t         d$       | j                  d%t
        t        d&t         d'       | j                         }|j                  at                t        j                  t              }t        |j                        d(k(  rS|j                  d)      j!                         d(   }|j                  d*       |j#                          t%        d+| d,       nt        |j                        d-k(  r|j                  d(   |j                  d.   j'                         }}|j                  d/||f      j!                         d(   }|j                  d0||f       |j#                          t%        d1| d2| d3| d4       nt%        d5       |j)                          t+        j,                  d(       |j.                  a|j2                  a|j6                  a|j:                  a|j>                  r|j>                  a d6d7d8d9d:d;}tB        jD                  jG                  tB        jD                  jI                  t@                    d(   }d<|v r9|jK                  d<d.      \  }}	||jM                  |	|	j'                               ca'a(n?|jK                  d=d.      }
t        |
      d-k(  r|
d(   |
d.   j'                         ca'a(n|d:ca'a(d>tN         d?tP         d@a)|jT                  r|jT                  a)t%        dAtR                tB        jD                  jW                  tR              sd>tP         d@}dB}tB        jD                  jW                  |      r|n"tB        jD                  jW                  |      r|nd }|r1d(d l,}|j[                  |tR               t%        dCtR         dD| d4       n(t%        dEtR         dF       t+        j,                  d.       t%        dGt@         dHtN         dItP         dJtR                t]        tB        jD                  j_                  t`        dKtN         d?tP         dL            t*        _1        |jd                  r|jd                  dMz  }dN}tg        dOti        ||z              a5|tj        z  }tm        |tn        z        }tg        dP|      a8t%        dQ       t%        dR|jd                   dS|dTdU       t%        dVtj         dW|dXz  dTdY       t%        dZtp        d[d\tp        tj        z  d[d]       t4        dk7  r!t%        d^t4         d_t8         d`t<         da       ts                tu        tR        tp        tj        z         tw        tR               ty                t{        tR        t@               t%        dbtj         dc       t%        ddt|                t%        detR                t%        dft@                t                t	        t        j                               }	 t        j                  t              j                  d/tN        tP        f      j!                         d(   }t|        j                  dgdh      j                  didh      }t        |t@              }tB        jD                  j_                  t        dj| d?tN         d?tP         dk      }tB        jD                  jW                  |      r|d(k(  rt%        dl       t%        dm       t%        dn       t%        dotN         d3tP         dp       t%        dq       t%        dr       t%        ds       t%                t%        dt       t%        du       t%        dv       t%                t%        dw       t%        dx       t%        dy       t%        dn       t        dz       g }t        d{       }d }d|}t        d{       }d }d}}t        d{       }t        j                         } ||}t%        d~t         d|d       nt|        j                  dgdh      j                  didh      }!tB        jD                  j_                  t        dj|! d?tN         d?tP         dk      }"tB        jD                  jW                  |"      rZ	 t        j                  |"      }#|#j                  d(   jM                  t        t        d{             }t%        dt         d|dd       tB        jD                  j_                  t        dj| d?tN         d?tP         dk      }$tB        jD                  jW                  |$      r	 t        j                  |$      j                  d(   }t        |jM                  dd|            }|jM                  dd       }%|%2t        |%t
              r|%|%k7  st        |%      }d}t%        d|dd       t        d.tj        d.z         D 
]  }&t%        d|& dtj         d       |jd                  rJt        j                         | z
  }'tg        d(|jd                  dMz  |'z
        }(t%        dt        |(              t|        j                  dgdh      j                  didh      }!tB        jD                  j_                  t        d|! d?tN         d?tP         dk      })tB        jD                  jW                  |)      rtC        j                  |)       t        j                         }*t        tp        |      }+t        j                         |*z
  },|,d(kD  r8t        tR              d(kD  rt        t        tR              tp              ntp        |,z  nd(}-t%        dt        |,       d|-dz  dd       |-dk  r|+rt%        d       t%        |+dd         t|        j                  dgdh      j                  didh      }!tB        jD                  j_                  t        d|! d?tN         d?tP         dk      }.t        |.t@        d||&|j.                        \  }/}0d}}1|0L|0jM                  dd      }2|0jM                  dd|      }3|2|kD  r"|2}|0}tB        jD                  j_                  t        dj|! d?tN         d?tP         d      }4t        j                  |0g      j                  |4d}       t%        d|2dd|3dd|0jM                  dd(      dd]       |2d(k\  rtB        jD                  j_                  t        dj|! d?tN         d?tP         dk      }5t        j                  |0g      j                  |5d}       t        |0|!t        tN        tP               |0}d}t%        d       nt%        d       |/t               }/|/{t%        d       	 t        j                  t@              }6|6j                  j                  j                         |6_X        d|6j                  v rlt        j                  |6d   d      j                  j                  d       |6d<   |6d   t        k\  |6d   t        k  z  }7|6j                  |7   j[                         }6|/j                         }8t        j                  |6j[                         fi |8}9t        j                  |9t              }:t%        dt         d3|/jM                  t        d(      dd|:jM                  t        d(      d       |:j                         D ]
  \  };}<|<|/|;<    d}1nd}1|/t%        d        n|/jM                  t        d(      }>tm        |/jM                  dd(            }?|/jM                  dd(      }@|/jM                  dd(      }A|/jM                  dd|      }B|/jM                  dd|      }C|/jM                  dd|      }D|/jM                  dd|      }Et        dk(  r(t%        d|>ddDddBdd@ddAdd|? dEdd       n.t%        dt         d|>ddBddCdd@ddAdd|? dEdd       |>|kD  xr |>d(kD  }F|>|k(  xr |&d.kD  }Gd}}H|0|0jM                  dd|      nd|}I|Id(kD  r|0n|/}JId(kD  rdnd}KtB        jD                  j_                  t        dj|! d?tN         d?tP         dk      }5FrWJKdk(  r|0|0jM                  dd      nd }L|xr Kdk(  xr Ld uxr L|k  }H|HrZt%        dLdd|dd       |t        j                  |g      j                  |5d}       t        ||!t        tN        tP               nCt        j                  Jg      j                  |5d}       t        |J|!t        tN        tP               Hs%tg        |t        JjM                  dd|                  }|sJ}|1rGHr$t%        dt         d|dd|>ddLdd|dd]       nt%        dt         d|dd|>ddK d̝	       |>}nct%        d|>ddΝ       nR|Ct        j                  |g      j                  |5d}       t        ||!t        tN        tP               Grt%        dϫ       |?d(k(  r|+rt%        dЫ       t%        |+dd         Fxr H }M|MrdnFrdndh}N|/|/jM                  dd       nd }O|OdOdndh}Pt        dk(  r6t%        d|& dtj         d|>ddDddBdd@dڛdAdd|? d|dP N dޝ       n8t%        d|& dtj         dt         d|>ddBdd@dڛdAdd|? d|dP N dޝ       |j                  st        j                  t*        j                  dgd}       t        j                  t*        j                  ddgd}       |j                  r(t        j                  t*        j                  ddgd}       t        j                  t*        j                  dgd}       t        j                  t*        j                  dgd}       |j                  d|& dt         d|> d|?        |>}|&tj        k(  rt%        d|& d        nt        tR        d      5 }Qt        j                  |Q      }Rd d d        t        R      }S|S|Rk7  r>t%        d       S}Rt        tR        d      5 }Qt        j                  R|Qd       d d d        |&d.kD  rt        j                  d       t        j                  d       
 t        j                         | z
  }T	 t        j                  t              j                  d/tN        tP        f      j!                         d(   }Ut        j                  t              j                  d)      j!                         d(   }VU|z
  }Wt%        d       t%        d       t%        d       |D ]  }Xt%        d|X         t%        dt         d|d       |$t%        d|dd|jM                  dd(      dd]       t%        dt        T              t%        dW d3tN         d3tP         dVd[d]	       t%        d       t%        d       |j                  s't        j                  t*        j                  dgd}       t|        j                  dgdh      j                  didh      }Yt        |Yt@               |j                  s't        j                  t*        j                  dgd}       |j                  s't        j                  t*        j                  dgd}       	 dtN         d3tP         d|ddt        T       d]	}Zt        j                  dd d|Zdgdzd}       y # t        $ r d(}Y w xY w# t        $ r Y Jw xY w# t        $ r Y w xY w# t        $ r}=t%        d|=        Y d }=~=|d }=~=ww xY w# 1 sw Y   NxY w# 1 sw Y   xY w# t        $ r |}Ud(}VY Yw xY w# t        $ r Y y w xY w(  Nz;Auto-Optimize Strategy (iterative GPU random/Optuna search)u  
Arguments:
  --data PATH       Path to OHLCV data CSV. Asset and TF extracted from filename.
  --hours N         Total runtime budget. Divided evenly across ~15-min iterations.
  --search MODE     'random' (default) or 'optuna' (DB-history biased sampling + importance report).
                    Optuna biased sampling works from iteration 1 (requires prior DB rows).
                    Importance report (results/reports/optuna_importance_*.md) requires ~3h+ to appear
                    because it needs ≥30 CPU-verified results from a single iteration.
  --regime MODE     Filter IS bars by MVRV regime: all (default) / bull / bear / sideways.
  --params PATH     Override the params JSON file (default: derived from --data).
  --no-dashboard    Skip sweep dashboard regeneration after each iteration.
  --reset-db [ASSET TF]  Delete DB rows then exit. No args = wipe all.

Examples:
  # First run on a new combo — always start with random
  python3 tools/auto_optimize_loop.py --data data/COINBASE_BTCUSD-4H.csv --hours 2

  # After ≥1 random run — switch to Optuna for DB-biased sampling
  # Use ≥4h if you want the importance report (results/reports/) to appear
  python3 tools/auto_optimize_loop.py --data data/COINBASE_BTCUSD-4H.csv --hours 4 --search optuna

  # Optuna with LLM-guided range narrowing (only ≥6h runs)
  python3 tools/auto_optimize_loop.py --data data/COINBASE_BTCUSD-1D.csv --hours 8 --search optuna --llm

  # Bull-regime only (filter IS training bars to MVRV bull phase)
  python3 tools/auto_optimize_loop.py --data data/COINBASE_BTCUSD-4H.csv --hours 4 --regime bull

  # Wipe one combo's DB rows and restart
  python3 tools/auto_optimize_loop.py --reset-db COINBASE_BTCUSD 4H
  python3 tools/auto_optimize_loop.py --data data/COINBASE_BTCUSD-4H.csv --hours 4

  # Usually called via batch runners rather than directly:
  python3 run_btc.py --hours 10 --tfs 4H 6H 8H 12H 1D
  python3 run_btc.py --hours 10 --search optuna
  python3 run_marathon.py --hours 96 --hours-per-combo 1
)descriptionformatter_classepilogr  zkPath to the OHLCV data CSV (e.g. results/COINBASE_BTCUSD-1D.csv). Timeframe is extracted from the filename.)typer   helpz--hoursz:Target runtime in hours (scales sample size automatically))r  r   z
--reset-db*ASSET_TFzDelete sweep DB rows then exit. No args: wipe all. Two args (ASSET TIMEFRAME): wipe that combo. E.g.: --reset-db COINBASE_BTCUSD 4H)nargsmetavarr   z--no-dashboardno_dashboard
store_truezMSkip regenerating the sweep dashboard (mine_sweep_db.py) after each iteration)destactionr   z	--tightentightenu   Auto-apply q5-q95 range tightening (tighten_params.py --apply) after each iteration. Off by default — only enable after several runs have built up sufficient DB coverage.r  r   optunazSearch strategy passed to optimize_strategy.py: 'random' (default) or 'optuna' (biased sampling from DB history + importance analysis). Optuna mode requires prior DB results to be effective.)r  r   choicesr   z--paramszOverride the params JSON file (default: derived from --data filename). Used by run_phased.py to pass phase-specific param files.r  r   )r   bullbearsidewayszPre-filter IS training bars by MVRV regime before optimisation. 'bull': zscore >= bull_threshold; 'bear': zscore < bear_threshold; 'sideways': bear_threshold <= zscore < bull_threshold; 'all': no filter (default).r  z6zscore percentile below which bars are Bear (default: z<). Historically: 2022 bear median=6.6, 2018 bear median=9.9.r  z<zscore percentile at or above which bars are Bull (default: z,). Aligns with onset of confirmed bull runs.r   z"SELECT COUNT(*) FROM sweep_resultszDELETE FROM sweep_resultszWiped entire sweep database (z rows deleted).r%  r   z@SELECT COUNT(*) FROM sweep_results WHERE asset=? AND timeframe=?z7DELETE FROM sweep_results WHERE asset=? AND timeframe=?zDeleted z
 rows for r   r  z1Usage: --reset-db  OR  --reset-db ASSET TIMEFRAME4H6H8H12Hr   )240360480720r   r2  -r   r   r   z    >> [CONFIG] Params override: z;strategies/params/params_strategy_activation_scores_1D.jsonz-   >> [CONFIG] Created asset-specific params z from template z%   >> [ERROR] Params file not found: z (and no template found)z   >> [CONFIG] Data: z
 | Asset: z | Timeframe: z | Params: optimization_log_z.txti  i  r   r  z"--- Time-Based Scaling Enabled ---zTarget Runtime : z hours (r  zs)zIterations     : z  (~r  z
 min each)zSamples/iter   : r  z
  (Total: r   z   >> [REGIME] Training on 'z' bars only (bear_thr=z, bull_thr=z.). Filter applied inside optimizer subprocess.z%--- Starting Auto-Optimization Loop (z Iterations) ---zTarget: zParams: zData Source: r  r   r  r   r  rs  u'   ⚠️  STALE WINNER / EMPTY DB WARNINGrt  z  A winner file exists for z but the sweep DB hasz,  0 rows for this combo. This usually means:z>    a) The DB was reset/deleted after the winner was found, ORzL    b) The scoring formula or simulation changed since the winner was saved.zG  Risk: the winner's score will be used as the GPU pre-filter baseline.zG  If it's inflated relative to the current simulation, nothing new willu=     ever beat it and no new results will be saved — silently.z1  Recommended action (if scoring or sim changed):zJ      python3 tools/reset_results.py --apply   # wipe winner + start freshzE  Or if the winner is still valid, continue and it will self-correct.r  infr   Fz   >> [INIT] Baseline z (CPU-verified): r   z$   >> [INIT] Loaded historical best rn  z (unverified)r   r  Tz1   >> [INIT] Loaded existing winner WFO_Min_Fold=z as baseline (WFO guard active)z
=== Iteration r  r   z   >> Global Time Remaining: r  z   >> Actual Time: z	 | Rate: r  r   zk samples/si@ zQ   >> [WARNING] Low sampling rate detected. Dumping optimizer logs for debugging:i0optimization_sweep_  )r  r-  r   r   r  r   z_wfo.csvr  u/      >> [WFO] ★ New global WFO winner (WFO_Min=r  z  IS=r   r  u<      >> [WFO] ★ Promoted to main winner (all folds positive)uN      >> [WFO] ★ Saved to _wfo.csv only (WFO_Min<0, keeping main winner intact)zF   >> [INFO] Sweep file missing. Verifying 'Run Best' result on CPU...rO  rq  rN  z   >> [VERIFY] Run Best: z -> z)   >> [FALLBACK] CPU calculation failed: z4   >> [WARNING] No valid results found for this run.r   r   r   r   r   r  z   >> Best Composite: z | Calmar: z | Sortino: z | P&L: z% | DD: r   z% | Trades: z | In Market: r  r  z   >> Best z | Sharpe: WFOzIS-Compositez0   >> [WFO] IS global best improved but WFO_Min=z < existing promoted best z . Restoring superior WFO winner.z   >> [INFO] IS z improved (r   z6) but WFO guard kept existing winner on disk (WFO_Min=z < z)   >> [SUCCESS] New VERIFIED global best z found (Old: z, New: z) [z winner saved]z    >> [CAUTION] New best found (zH) but NOT VERIFIED. Will NOT update global baseline to avoid corruption.z4   >> [STAGNATION] Result identical to previous run.z>   >> [WARNING] Zero trades detected. Optimizer Output (tail):iu    ★ NEW BESTu!    ↑ IS improved (WFO guard held)z  WFO=z
  Iteration Summary z: Composite=z	  Calmar=z
  Sortino=r  r   z%  DD=r  z  Best=r   r  zmine_sweep_db.py)checkztools/lock_params.pyz--applyztools/tighten_params.pyztools/oos_dashboard.pyz tools/shap_feature_importance.pyzIteration Summary z	, Trades=z   >> [INFO] Final iteration z
 complete.r  zE   >> [INIT] Sanitized initial parameter ranges (fixed steps/bounds).r#   rw  r6  r&  z=
============================================================z  OPTIMIZATION RUN COMPLETEr3  r   z
  Global Best IS z  Global Best WFO Score   : z  (IS=z  Total Elapsed Time: z  DB Rows Added      : +z  (total DB: z/
Final results are in the 'results/' directory.u   ✅ z  optimization done! Best P&L/DD=z (curlz-sz-dzntfy.sh/jlo_alerts)r  r  )sargparseArgumentParserRawDescriptionHelpFormatteradd_argumentr   r<   _MVRV_BEAR_DEFAULT_MVRV_BULL_DEFAULT
parse_argsreset_dbr  r  r  r  r9  r  fetchoner  r   upperr  r%   r  searchr  regimer  regime_bear_thresholdr  regime_bull_thresholdr  datar  r   r   splitextr  rsplitr   r  r  r  r   r  shutilrZ  r!   r   r   r&   hoursr8  r<  MAX_ITERATIONSrJ   r  SEARCH_ITERATIONSr  rU  r  r  r  r  uuiduuid4r   r  r  r
   rv  rO  r7  r  r  r  r   r  r  remover  r:  r  r   r  r  r  r   r  r  r   rY  r  r  r   r   r  r  r  rW  rX  r   r   r  r  run
executabler	  r   r(   r8  r9  r   r=  r  r$  )[parserr\  r  rB  	asset_argtf_arg
_MIN_TO_TFstem_asset_part_periodpartstf_templategen_templatetemplater0  total_secondsTARGET_SECS_PER_ITERseconds_per_iterscaled_iterationsr-  _db_rows_beforestrategy_name_cleanverified_best_winner_file_checkhistoryglobal_best_scoreglobal_best_rowglobal_best_calmarglobal_wfo_best_scoreglobal_wfo_best_rowglobal_wfo_promotedprevious_scorestart_loop_timer   historical_winner_filehist_df_init_winner_file_init_wfo_minr  elapsed_totalremaining_totalr  
iter_start
opt_outputiter_elapsedrater  best_rowwfo_winner_this_iteris_verifiedwfo_min_thiswfo_mean_thiswfo_winner_filewinner_csv_pathdf_data_fallbackr  r   re  rf  r   valuerK  scorer   r   r   r   r   r   r  is_new_global_bestis_stagnant_skip_writewfo_score_this_iterr   winner_source_wfo_min_this_iter_winner_file_updatedbest_markerwfo_score_display
wfo_suffixr   current_paramssanitized_paramstotal_elapsed_db_rows_after	_db_total	_db_addedentrystrategy_name_finalmsgs[                                                                                              r,   mainr|  v  sc   $$Q <<#'FP sD  @m  n
	4pq
CC  D (~ll  n
)Lw  x 
hS[H\V  W 
dY  Z 
eEhr  s 1GYUVhUi jY Y  Z 1GY[\n[o pI I  J D }} }-t}}"ABKKMaPALL45KKM1!ODE1$ $a 0$--2B2H2H2JvIRF#%%-XZ3A LLR#V,.KKMHQCz)AfXQ?@EF

 ++K[[F 66 66yyII	
 d4TRJ77BGG,,Y78;Dt|#{{43W&
w(PyC#u:?$Qxq)9E9#TE9HqQZP[[`aK{{kk0>?77>>+&Mi[X]^T"$''.."=;TVT[T[TbTbcoTpLvzKK+.A+o^f]gghij9+F^_`HHQK	!)Jug^I;Vabman
opZ3DUG1YKW[1\]^CJ zz

T)&Qm6J&J KL(>9 08 ;<	+<=24!$**XmC5HKL!.!16Fr6I#5NjYZ!"3A!6jARUcAcde@ffghi ,VH 501=R<S T<= 	> $%K):^)KL%+y1	1.1AAQ
RS	H]O
$%	H[M
"#	M)
%&OF!//-8@@NI  (
1. (//r:BB;PRS()<iHM k5IJ]I^^_`e_ffghqgrrv3wx	ww~~()o.Bo78h+E7!I;>STU<>NP\^c
WYWYMOc
ACZ\UWh2GuO"5\MEl]NiikO
  )&':&;;LM^_bLcde%--eR8@@bQ!#k=QR_Q``abgahhijsittx;y!z77>>01++&<=$+LLO$7$78KeTYl]$[!<=P<QQSTefiSjjwxy [4HI\H]]^_d^eefgpfqqu2vw	ww~~'(	 kk*;<AA!DO!&':':>3'O!P ,//EM(*]E2RWdhuWu(-m(<%&*#IJ_`cId  eD  E  F 1nq() 1^$4D9::: IIK/9M!!djj4&7=%HIO1//2R1STU%--eR8@@bQ[4J=/YZ[`Zaabclbmmq2rs77>>-(IIm$YY[
 &&79KL
yy{Z/ bn  qr  brOefqOruvOv*;79JK  }N  R^  ^  xy#OL$A#B)DQUIVZK[[fgh&=Zef*UV$%%--eR8@@bQWW\\*0CM?RSTYSZZ[\e[ffj.kl
);J	Y]fl  @A  SW  S^  S^  *_&&  +/33NEJL044[#FM33(4%&:#"$'',,{>RS`Raabchbiijktjuu}<~"234;;OSX;YGUXGYYdersvdww|  ~R  ~V  ~V  Wb  de  ~f  gj  }k  kl  m  n  1$&(ggll;BVWdVeefglfmmnoxnyy}@~&OLL"6!78??W\?])*>{bgs|}&:O*.'XZjl*,H#^_K'){{9'=$/?/G/G/K/K/Q/Q/S$,!1!9!9935>>BRSYBZ`d3e3h3h3t3tuy3z(0 0 8K GL\]cLdhqLqr+;+?+?+E+J+J+L(%--/F,==>N>S>S>U`Y_`F-??T_`G56I5J!HLLYlmnLopsKttx  zA  zE  zE  FY  [\  z]  ^a  yb  c  d&-mmo
U(- '6"&K KHI0!4X\\.!45ll=!,\\*A.,,4nc2nc2 ]C8+-*5+[LY`adXeemnqrvmww  AC  DG  @H  HT  U[  T\  \j  kx  y|  j}  }~    @K 34BuSkgVY]Zeflmpeqqyz}  C  zD  DL  MO  PS  LT  T`  ag  `h  hv  wD  EH  vI  IJ  K  L"%66D519.;QU
 MaLl266{CHru-@1-D)(
!4q!8n'',,{6J=/YZ[`Zaabclbmmq4rs% *7%)?DXDd ';&>&>~u&U+/ #  3  N}7M  N#5T#A N#58M#M  LM_`cLd e44I#3NNnp q
 '2o%67>>V[>\-o}kafr{|LL*.55oU5S)*m[X]irs" *--?z~~VdfiGjAk)l&
 +&0O,-@,AM^_bLcchinorhs  tj  k}  ~A  jB  BE  F[  \_  E`  `a  b  cEFYEZZghyz}g~  F  GL  MP  FQ  QT  Ub  Tc  cq  r  s$)!8s  DL  M  N *o./66e6T%o}kY^jstLNQ;:RS*UV$%  2E+o)=ok}Dg  DF?G?SHLLd;Y]9J9Vv/45\^
+-*1#Q~.>l5QT+U^_efi^jjtu|  ~A  uB  BH  IL  MQ  HR  RX  Y[  \_  X`  `j  kq  jr  ry  zK  LO  yP  Q[  P\  ]h  \i  ik  l  m*1#Q~.>bAT@UUVW\]`Vaaklstwkxx~  @C  DH  I  IO  PR  SV  OW  Wa  bh  ai  ip  qB  CF  pG  HR  GS  T_  S`  `b  c  d  NNCNN,>?uM NNCNN,BINV[\||0I9U]bcNNCNN,DEUSNNCNN,NOW\]+A3b1D0EQugYW]V^_`1!J?@+s#q!YYq\N $ +>:~-YZ-Nk3'1		.!A6 ( q5JJqM

1u *x IIK/1M 7??NI  (
1. OOM2::022:(*Q@	
 0I	-	
'(	&M5'l 	 34B7H6M
NO&,-B3,G*..{A>sC1F 	G	"?=#A"B
CD	$YKqq=QZ[\P]]^
_`	&M	
<=(:;5I'//r:BB;PRS0)<(@AO 	^^?@	
5'9+ &,S1 2./q2 	
 	T4&:;e	
k
  f  "  		d ! KEaSIJJK| $# ('  (	^  s   "AA_ AA_0 BA`  E,A`SA`5TAaV	A=Aa ^AAa# _A_-_,A_-_0	A_=_<A_=` 	A``A``	A`2`A`-`-A`2`5A`?	aAa	aAa aAa a#	Aa/a.Aa/__main__)r   r   r{  )r  NNN)r   )^__doc__r   r8  r  rR  r  r%   r  rO  r.  r  rQ  r  r4  concurrent.futuresr   r   r   insertr  r  r  rS  rT  r  r   r   r   r   r   r	   r
   r   r   r   r   r#  r   r$  r   r  r   r   r   r   r   r   r  r7  r  r  r  r  r3  r2  r  r  r  r  r  r<  r  objectr!   r   r   r   r  r
  _NON_WEIGHT_PARAM_COLSr  r	  rL  rk  r  r  r  r$  r0  r1  rU  r  r  rv  r  r  r  r:  r;  r  r  r  r|  r5   r8   r.   r,   <module>r     s9   
    
     	   @ 277??277??277??83L#MN O ? Y  Y  Y  Y  Y 0!  /		DUG1YKW\] 	* * +V u9p&P,pj %%$$%$%$'!    +!77BMJ"JPd*!Z9v`IF
d
Oh ~  01  
|   34	 
  23  /  }   01  0   12   01     9:  0      12! " /# $ !22 23 45 23 23 34 2H= +} 23 -###?  F0f &R,^=@$&
GR IV zF r.   