
    j}B                    J   d Z ddlm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 ddlmZ  ee      j!                         j"                  j"                  Ze	j&                  j)                  d ee             g dZg dZdd	d
dddZedz  dz  dz  Zedz  dz  dz  Zej7                         r ee      ne	j8                  Zd dZd!dZd"d#dZ d$dZ!d"d%dZ"d&dZ#	 	 d'	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d(dZ$	 	 	 	 d)dZ%d*dZ&d+dZ'd,dZ(d-dZ)e*dk(  r e)        yy).u  
MLP training orchestrator — trains N seeds per asset/TF combo, sweeps thresholds,
optionally regenerates Pine presets and sends ntfy notification.

Replaces the ad-hoc shell scripts written to /tmp/ each session.

Usage:
    # Train BTC all TFs, 3 seeds, sweep + promote + notify
    python3 tools/run_mlp_train.py --assets COINBASE_BTCUSD --seeds 3 --sweep --promote --notify

    # Train all 4 assets, 4H only, 6 seeds, then generate presets
    python3 tools/run_mlp_train.py --tfs 4H --seeds 6 --sweep --promote --presets --notify

    # Extra seeds 404-606 for BTC 6H and 8H (specific seeds)
    python3 tools/run_mlp_train.py --assets COINBASE_BTCUSD --tfs 6H 8H --seed-start 404 --seeds 3

    # Dry run — show what would be launched without running
    python3 tools/run_mlp_train.py --assets COINBASE_BTCUSD --seeds 3 --dry-run

    # All 4 assets, all TFs, 3 seeds, full pipeline
    python3 tools/run_mlp_train.py --seeds 3 --sweep --promote --presets --table --notify
    )annotationsN)datetimetimezone)Path)COINBASE_BTCUSDCOINBASE_ETHUSDBINANCE_SOLUSDBINANCE_LINKUSD)4H6H8H12H1D240360480720r   
strategiesparamsmlpz.venvbinpython3c                    t        dt        j                  t        j                        j                  d       d|  d       y )N[z%H:%M:%Sz] T)flush)printr   nowr   utcstrftime)msgs    >/Users/jameslopez/projects/TradingBot25/tools/run_mlp_train.pylogr"   0   s2    	Ahll8<<(11*=>b
FdS    c                >    t         |   }t        dz  dz  |  d| dz  S )Ndatar   z, z.csv)	TF_PERIODREPO)assettfperiods      r!   	data_pathr+   4   s,    r]F&=5 eWBvhd#;;;r#   c           
     .    t         d|  d| d| d| d	z  S )Nmlp_weights___seedz.json)WEIGHTS_DIR)r(   r)   seedtags       r!   artifact_pathr3   9   s(    <wat1SEtfEJJJr#   c                J    t        |      D cg c]
  }| |dz  z    c}S c c}w )zAGenerate seeds as seed_start, seed_start+101, seed_start+202, ...e   )range)
seed_startn_seedsis      r!   
seed_ranger:   =   s'    */.9.QJS .999s    c           	         g }t         j                  d|  d| d| d      D ];  }	 t        |j                  j	                  d      d         }|j                  |       = t        |      S # t        $ r Y Tw xY w)zBReturn sorted list of seeds already trained for this asset/TF/tag.r-   r.   _seed*.jsonr/   )r0   globintstemsplitappend
ValueErrorsorted)r(   r)   r2   seedspss         r!   existing_seedsrH   B   s~    EUG1RD#kJK	AFFLL)"-.ALLO L %=  		s   8A++	A76A7c                    |dk(  r | j                  d      rt        d|  d      |dk7  r| dk(  r|  d| } |dk(  r| S |  d| S )	zDKeep non-dense experiments out of the production ``bb50`` namespace.hybrid_grouped)groupedrandom_sparsebb50_groupedbb50_random_sparsezArtifact tag 'zp' is reserved by an existing input-structure experiment; use an isolated hybrid tag such as 'hybrid_grouped_v1'.densebb50r.   all)
startswithrC   )r2   regimeinput_structures      r!   effective_artifact_tagrU   N   sz    **s~~ ? 0 SE "F F
 	
 '!cVmQ'(E/38#ax'88r#   c                   t        | |||      }t        | |      }|  d| d| }|j                         s|dd| fS t        ddt	        |      d| d|d	|d
t	        |      dg|D cg c]  }t	        |       c}dt	        |      dt	        |      dt	        |      dt	        |      }|
dk7  r|d|
gz  }|dk7  r|d|gz  }|dk(  r||ddfS |dt	        |      gz  }|r|dgz  }|	r"t        ddj                  |              |ddfS t        d|  d| d| d      }t        j                         }	 t        |d      5 }t        j                  |||t	        t                     }d d d        t        t        j                         |z
        }j                  d!k7  r|dd"|j                   d#| d$| fS |d| d%|j                   fS c c}w # 1 sw Y   ixY w# t         $ r}|dt	        |      fcY d }~S d }~ww xY w)&N z seedFzdata file missing: ztools/train_mlp.pyz--data--assetz--tf--fold-objective--l2--hiddenz--seed--es-workers--es-generationsz--outrQ   --regimerO   --input-structurerL   z"random_sparse requires a mask seedz--mask-seed--temporal-features  [dry-run] Tdry-runz/tmp/mlp_train_r.   r/   .logwstdoutstderrcwdr   exit  after 
   s — see u   s → )r3   r+   existsPYTHONstrr   joinr   timeopen
subprocessrunr'   r?   
returncodename	Exception)r(   r)   r1   hiddenfold_objectivel2
es_workerses_generationsr2   dry_runrS   rT   	mask_seedtemporal_featuresoutr%   labelhcmdlog_patht0fresultelapsedes                            r!   	train_oner   \   s   
 r4
-CUBDgQrd%v&E;;=e24&999 	$#d)5&"NB '--fc!ff- 	 d) 	 J 	  / 	 SC 
F##'!#_55/)%!EEEs9~..%&&SXXc]O,-dI%%oeWAbTtfDABH	B$(C A^^C!TKF !diikB&'!%5):):(;77):V^U_!```dwivchhZ8889 .. !   $eSV##$sC   %G9G  'G,AG  ;G  GG   	H)G<6H<Hc                
   |  d| }t        t        j                  d|  d| d| d            }|s|ddfS t        dd| d	|d
t	        |      dg	|D cg c]  }t	        |       c}}	|r|	j                  d       |r"t        ddj                  |	              |ddfS t        d|  d| d      }
t        j                         }	 t        |
d      5 }t        j                  |	||t	        t                    }d d d        t        t        j                         |z
        }j                  dk7  r|dd|j                   d| d|
 fS |d| dfS c c}w # 1 sw Y   ]xY w# t         $ r}|dt	        |      fcY d }~S d }~ww xY w)NrW   r-   r.   r<   Fzno artifacts to sweepztools/run_mlp_deep_sweep.pyrX   z--timeframes	--samplesz--extra-weights	--promotera   Trb   z/tmp/mlp_sweep_rc   rd   re   r   ri   rj   rk   rG   )listr0   r>   rm   rn   rB   r   ro   r   rp   rq   rr   rs   r'   r?   rt   rv   )r(   r)   r2   samplespromoter|   r   extrasr   r   r   r   r   r   r   s                  r!   	sweep_oner      s   gQrdOE+""\%"Qse;#OPQFe444 	-5S\
 .44VSVV4C 

;SXXc]O,-dI%%oeWAbT67H	B$(C A^^C!TKF !diikB&'!%5):):(;77):V^U_!```dwiqM))# 5 !   $eSV##$sC   EE! 'E9AE! E! EE! !	F*E=7F=Fc                ^   | rt        d       yt        j                  t        dgt	        t
              dd      }t        |j                  j                                |j                  dk7  r3t        |j                  j                         t        j                         |j                  dk(  S )Nz6  [dry-run] python3 tools/generate_pine_mlp_presets.pyTz"tools/generate_pine_mlp_presets.pyrh   capture_outputtextr   )file)r   rr   rs   rm   rn   r'   rf   striprt   rg   sys)r|   r   s     r!   run_presetsr      s    FG^^	56IdF 
&--


 Afmm!!##**5!!r#   c                    |rt        d       yg }| D ]Y  }t        j                  t        dd|gt	        t
              dd      }|j                  |j                  j                                [ dj                  |      S )Nz5  [dry-run] python3 tools/mlp_results_table.py --save tools/mlp_results_table.pyrX   Tr   
)
r   rr   rs   rm   rn   r'   rB   rf   r   ro   )assetsr|   linesr(   r   s        r!   	run_tabler      sr    EFE19eDD	$T
 	V]]((*+  99Ur#   c           	     d    t        j                  t        d|d| ddgt        t              d       y )Nztools/ntfy.pyz--titlez
--priorityhighTrh   r   )rr   rs   rm   rn   r'   )titler    s     r!   send_notifyr      s)    NN	#y%vNIdr#   c                 F   t        j                  dt         j                  t              } | j	                  ddt
        t
        dd       | j	                  ddt        t        d	d
       | j	                  dt        dd       | j	                  dt        dd       | j	                  ddd       | j	                  ddd       | j	                  dt        dddg       | j	                  ddg d !       | j	                  d"t        d#$       | j	                  d%t        d&d'       | j	                  d(t        d)$       | j	                  d*t        d+d,       | j	                  d-dd.       | j	                  d/t        d0d1       | j	                  d2dd3       | j	                  d4dd5       | j	                  d6dd7       | j	                  d8dd9       | j	                  d:dd;       | j	                  d<g d=d>d?@       | j	                  dAg dBdCdD@       | j	                  dEt        dFG       | j	                  dHddI       | j                         }|j                  dJk(  r|j                  | j                  dK       |j                  dLk(  r5|j                  s|j                  s|j                  r| j                  dM       |j                   r5|j                  s|j                  s|j                  r| j                  dN       |j                   r|j"                  dk(  rdO|_        t%        |j"                  |j&                  |j                        }||j"                  k7  r)t)        dP|j&                   dQ|j"                   dR| dS       |j*                  D cg c]  }|j,                  D ]  }||f  }}}t/        |j0                  |j2                        }|j                  dJk(  rt/        |j                  t5        |            nd gt5        |      z  }|D 	cg c]  \  }}t7        ||      D ]  \  }}	||||	f ! }
}}}}	t)        dTt5        |j*                         dUt5        |j,                         dVt5        |       dWt5        |
       dX	       |j8                  rR|
D 	cg c])  \  }}}}	t;        ||||      j=                         s||||	f+ }
}}}}	t)        dYt5        |
       dZ       |j>                  rt)        d[       tA        j@                         }|jB                  d+kD  r|jB                  ntE        d\t5        |
            }g }tF        jH                  jK                  |]      5 }|
D 	ci c]  \  }}}}	|jM                  tN        ||||jP                  |jR                  |jT                  |jV                  |jX                  ||j>                  |j&                  |j                  |	|j                         |||f }}}}}	tF        jH                  j[                  |      D ]I  }|j]                         \  }}}|rd^nd_}t)        d`| da| db|        |r4|j_                  | db|        K 	 d d d        t)        dct        tA        j@                         |z
         ddt5        |
      t5        |      z
   det5        |
       df       |r$t)        dgdhja                  di |D              z          |j                  rt)        dj       g }|j*                  D ]x  }|j,                  D ]g  }tc        ||||jd                  |j                  |j>                        \  }}}|rd^nd_}t)        d`| dk| db|        |rR|j_                  | db|        i z |r$t)        dldhja                  dm |D              z          |j                  r3t)        dn       tg        |j>                        }t)        d`|rd^nd_ do       dp}|jh                  r7t)        dq       tk        |j*                  |j>                        }tm        |       nY|j>                  sM|j                  dCk(  r>|j*                  D ]/  }to        jp                  tr        drds|gtu        tv              dtu       1 |jx                  r|j>                  st5        |
      t5        |      z
  }| det5        |
       dv}|j                  r|dwz  }|j                  r|dxz  }|rB|j{                         D cg c]  }dy|v sdz|v s| }}|r|dhdhja                  |d d{       z   z  }t}        d||       t)        d}       t)        d~       t        j                  d+       y c c}}w c c}	}}}w c c}	}}}w c c}	}}}w # 1 sw Y    xY wc c}w )NzMLP training orchestrator)descriptionformatter_classepilogz--assets+ASSETz Assets to train (default: all 4))nargsdefaultchoicesmetavarhelpz--tfsTFzTimeframes (default: all 5)z--seeds   z&Number of seeds per combo (default: 3))typer   r   z--seed-startr5   z8First seed value; subsequent seeds += 101 (default: 101)z--skip-existing
store_truez6Skip training if artifact already exists for that seed)actionr   z--tagrP   z.Artifact name tag, e.g. 'bb50' (default: bb50))r   r   r[         )r   r   r   rY   robust)meanminmean_minr   )r   r   rZ   g{Gz?)r   r   r\      zWCMA-ES worker processes per training job (default: 2, keeps headroom for parallel jobs)r]   i,  z--parallel-jobsr   z<Max parallel training jobs (default: 0 = all combos at once)z--sweepz"Run threshold sweep after trainingr   i8 z%Sweep samples per TF (default: 80000)r   z(Promote sweep winners (requires --sweep)z	--presetsz#Regenerate Pine presets after sweepz--tablez"Print regression table after sweepz--notifyz Send ntfy notification when donez	--dry-runz#Print commands without running themr^   )bullbearsidewaysrQ   rQ   zmFilter Phase-1 training to MVRV regime bars (requires mvrv_regime column). Auto-appends regime suffix to tag.)r   r   r   r_   )rO   rK   rJ   rL   rO   zBPass the first-layer connectivity experiment to each training run.z--random-mask-seed-startz~Required with random_sparse; one explicit mask seed per training seed, incremented by 101 in the same order as training seeds.)r   r   r`   zTExperimental causal EMA companions; cannot sweep, promote, or generate Pine presets.rL   zI--random-mask-seed-start is required with --input-structure random_sparserJ   zUhybrid_grouped does not support sweep, promote, or presets; use canonical replay onlyzXtemporal-features does not support sweep, promote, or presets; use canonical replay onlytemporal_ema_v1zregime=z: tag auto-suffixed 'u   ' → ''zPlan: u    assets × u    TFs × z	 seeds = z training jobsz  After skipping existing: z jobs remainingu    DRY RUN — no commands executed   )max_workersu   ✅u   ❌  rW   z: zTraining done in u   s — /z
 succeededz
Failures:
r   c              3  &   K   | ]	  }d |   ywr   N .0r   s     r!   	<genexpr>zmain.<locals>.<genexpr>E  s     &BAA3x   z3Starting threshold sweeps (sequential per combo)...z sweep zSweep failures:
c              3  &   K   | ]	  }d |   ywr   r   r   s     r!   r   zmain.<locals>.<genexpr>T  s     /Q.Q"QC.r   zRegenerating Pine presets...z Pine presetsr   zRunning regression table...r   rX   Tr   z trainedz + sweptz
 + presetsOOS%   zTradingBot25 MLPz	ntfy sentzDone.)AargparseArgumentParserRawDescriptionHelpFormatter__doc__add_argument
ALL_ASSETSALL_TFSr?   float
parse_argsrT   random_mask_seed_starterrorsweepr   presetsr~   r2   rU   rS   r"   r   tfsr:   r7   rE   lenzipskip_existingr3   rl   r|   rp   parallel_jobsmax
concurrentfuturesThreadPoolExecutorsubmitr   rw   rx   ry   rz   r{   as_completedr   rB   ro   r   r   r   tabler   r   rr   rs   rm   rn   r'   notify
splitlinesr   os_exit)parserargseffective_tagar)   combosrE   
mask_seedsr1   r}   jobsrG   t_trainr   failurespoolr   futr   okdetailstatussweep_failuresr(   table_outputn_okr    l	oos_liness                                r!   mainr     sR	   $$/ <<F
 
#z: '.P  R
sGW $+H  J
	QE  G
S#W  Y
),U  W
M  O 
C"aI
*H E  G
UD9
S!A  B *cB
)Q[  ] 	,A  C
#uD  F
LG  I
LB  D
	,A  C

<?  A
LB  D

,OY^a  b +5lv}a  c
2W  X -ls  uD.43N3N3V`a//TZZ4<<SWS_S_lm4::op$((f"4$ +488T[[$BVBVWM gdkk]"7zWXYZ#{{>{!TXXrq"gXg{F>4E))_< T88#e*ECG&3u:BU  EAr3uj3Ii 
Bi 3I 	! 	 
 &T[[!"+c$((m_HSZL QYK~	' (AE H*=!RI$QA}=DDF B9% H)#d)ODE||./ iikG(,(:(:Q(>$$$C3t9DUKH				.	.;	.	G4
 (,	
 (,#2q) KK	1b!T[[$:M:M$2E2E}dkk43G3GTXTjTjlnoqsuvmwx (,	 	 
 %%227;C #

E2v UeF"VHAeWBvh/05'F8 45 < 
H 
C		G 345Vt9S]"
#1SYKz	; < kTYY&B&BBBC zzAB[[Ehh$-eR.2llDLL$,,%X!r6"$%bwb9:"))UG2fX*>?  ! #dii/Q./Q&QQR ||*+&b"%(67 Lzz)* dll;l\\d22g=[[ENN5y%HId ! {{4<<TS]*63t9+X.:::C<<<C$0$;$;$=X$=q!sVWx$=IXtdii	"1666&,KLHHQKA ?H
 
H	GB YsD   e3$e9
%.f
-f5Bf	Affff	ff__main__)r    rn   returnNone)r(   rn   r)   rn   r  r   )rP   )
r(   rn   r)   rn   r1   r?   r2   rn   r  r   )r7   r?   r8   r?   r  	list[int])r(   rn   r)   rn   r2   rn   r  r  )r2   rn   rS   rn   rT   rn   r  rn   )rQ   rO   NF)r(   rn   r)   rn   r1   r?   rw   r  rx   rn   ry   r   rz   r?   r{   r?   r2   rn   r|   boolrS   rn   rT   rn   r}   z
int | Noner~   r  r  tuple[str, bool, str])r(   rn   r)   rn   r2   rn   r   r?   r   r  r|   r  r  r  )r|   r  r  r  )r   z	list[str]r|   r  r  rn   )r   rn   r    rn   r  r  )r  r  )+r   
__future__r   r   concurrent.futuresr   jsonr   rr   r   rp   r   r   pathlibr   __file__resolveparentr'   pathinsertrn   r   r   r&   r0   VENV_PYTHONrl   
executablerm   r"   r+   r3   r:   rH   rU   r   r   r   r   r   r  __name__r   r#   r!   <module>r     s  . #    	  
  ' H~&&-- 3t9 X
,eEN	\!H,u4Wnu$y0"-"4"4"6c+CNNT<
K:
	9" ;BFK	0$!0$',0$:=0$!0$(+0$6:0$ 0$ 580$ $	0$ @D	0$ Qf	0$f$$ 5$D"gT zF r#   