+
    i4                    !   R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIHu Ht ^ RIHtHt ^ RIHtHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt]P>                  ! R4       ^ RI H!t" ^ RI#H$t$  ^ RI%t%Rt& ^ R	I)H*t* Rt+ ^ RI,t,Rt- ^ RI.t.Rt/ ^ RI0t1Rt2 ^ RI3t3Rt4^ RI5H6t6H7t7 ^ RI8H9t9H:t: ^ RI;H<t< ^ RI=H>t> ^ RI?H@t@ ]P                  ! 4       tB]C! ^]D! ]B^4      4      tE]EtF]E]F,           tG]P                  P                  RR4      tJ]P                  P                  RR4      tK]P                  P                  RR4      tL]P                  P                  RR4      tM]P                  P                  RR4      tNRtORtPRtQRtR^tSR tTR!tUR"tV^tWERtXERtYERtZERt[ERt\Rt]R%t^^Zt_R& R' lt`R( R) ltaR*tbR+tcR,td^2te^dtfR-tgR.thR/tiR0tjR1tkR2tlR3tmR3tnR1toR4tp^tq^trR5tsR6ttR$tuR7tv]P                  P                  R8R4      tw]P                  P                  R9R4      txR:ty]P                  P                  R;R4      tzR<t{. EROt|R=t}R>t~R?tR@t. EROt. EROtRAtRBtRCtRDtREtRtRtRFtRGtRHtRIt^2tRJt^<t]EP"                  ! RK4      t]EP"                  ! RL4      t. EROt^;tRMt]]]bRNRORPRQ]c]d3	 F  t]EP0                  ! ]RRR7       K  	  ]EP0                  ! ]RRR7       ]EP0                  ! RSRRR7       ]EP0                  ! RORRR7       ]EP0                  ! ]bRRR7       ]P                  EP3                  RTRU4       ]P                  EP3                  RVRU4       ]P                  EP3                  RWRU4       RX t ! RY RZ]EP6                  4      t ! R[ R\]4      t]! R]R^R_7      t]! R`R^R_7      t]EP@                  ! ]EPB                  . Ra7       ]EPD                  ! ]4      t]EPK                  ]EPB                  4       ]EPL                  ! ]4      t]EPQ                  ]4       ]EPR                  ! 4       t]EPQ                  ]4       ]EPW                  ]4       ]EPW                  ]4       R]n        ]EPD                  ! Rb4      t]EPK                  ]EPB                  4       ]EPL                  ! ]4      t]EPQ                  ]4       ]EPW                  ]4       R]n        ]EP_                  RcRd]EP`                  ! 4       EPc                  Re4       Rc24      t]EPD                  ! Rf4      t]EPK                  ]EPh                  4       ]EPj                  EPm                  4        ]EPL                  ! ]RgRh7      t]EPQ                  ]4       ]EPW                  ]4       R]n        ]EPL                  ! ]RgRh7      t]EPQ                  ]4       ]EPW                  ]4       ]EPr                  ! 4       tRi tRj Rk lt. RlNRmNRnNRoNRpNRqNRrNRsNRtNRuNRvNRwNRxNRyNRzNR{NR|NR}NR~NRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNRNER NERNERNERNERNERNERNERNERNER	NER
NERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNER NER!NER"NER#NER$NER%NER&NER'NER(NER)NER*NER+NER,NER-NER.NER/NER0NER1NER2NER3NER4NER5NER6NER7NER8NER9NER:NER;NER<NER=NER>NER?NER@NERANERBNERCNERDNERENERFNERGNERHNERINERJNERKNERLNERMNERNNERONERPNERQNERRNERSNERTNERUNERVNERWNERXNERYNERZNER[NER\NER]NER^NER_NER`NERaNERbNERcNERdNEReNERfNERgNERhNERiNERjNERkNERlNERmNERnNERoNERpNERqNERrNERsNERtNERuNERvNERwNERxNERyNERzNER{NER|NER}NER~NERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNt]! ]EP                  ]4      4      ER,          t0 ERmt. EROtERER ltER t]! ]E]F4      tER ER ltER ER ltER ER lt ! ER ER4      t ! ER ER4      t ! ER ER4      t ! ER ER4      t ! ER ER4      t. ERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNt]! ]4      tERER ER llt ! ER  ER4      t ! ER ER4      tER ER ltER ER lt ! ER ER	4      t ! ER
 ER4      t ! ER ER]4      tER tERER ER llt ! ER ER4      t ! ER ER4      t ! ER ER4      t ! ER ER4      tER ER ltER ER ltERER ER lltERER ER  lltER! ER" ltER# ER$ ltERER% ER& lltER' ER( ltER) ER* ltER+ ER, lt ! ER- ER.4      tER/ ER0 ltER1 ER2 lt^<t0 ERmt ! ER4 ER54      t]! 4       t^tER6 tER7 tR#tER8tER9tR7tER9tER:t^ RItER; ER< lt^Xt^]tER= ER> ltER? ER@ lt ! ERA ERB4      Et . Et]EPr                  ! 4       EtERC ERD lEtERE Et ! ERF ERG4      EtE]! 4       Et]C! ^]D! ]B^4      4      EsE] ! ]BERH7      Et ! ERI ERJ4      Et	]ERK8X  Ed   ]4'       d   ]3EP                  ! 4        ](! ERL4       ^ REIEtE]EP                  ! ERMERNE]EP                  EROERP7      EtE]EP!                  ERQERRRERSERT7       E]EP!                  ERUER3ERVERWERX7       E]EP!                  ERYERZ. EROER]ER^7       E]EP!                  ER_E]RER`ERaERb7       E]EP!                  ERcE]RERdEReERb7       E]EP'                  4       EtE]EP*                  EP-                  ERf4       U u0 uF"  q EP/                  4       EP1                  4       kK$  	  up EtE]],
          EtE]'       d*   ](! ERgE] 24       ](! ERhE]! ]4       24       E]! ^4       ^ REIEtE]EP>                  P                  ]E]EP>                  ERK,          4      Et E]EPB                  e   E]! E]EPB                  ERi,          4      E] n        ](! ERjE]EPB                  ERk ERlE] EP                  ERf ERmE]! E] EP                  R#,          4      ERf ERnE]! E] EP                  ERo,          4      ERf ERp2	4       MRE] n        ](! ERq4       E]EPD                  e7   ]C! ^E]EPD                  4      E] n        ](! ERrE] EP                   ERs24       MRE] n        ](! ERt4       E]EPF                  '       dB   ](! ERu4       ](! ERvERwEPI                  E]! E]4      4       24       ](! ERx4       ](! ERy4       M#]J'       g   ](! ERz4       ](! ER{4       E]! ^4       E]EPF                  '       gt   ](! ER|E]EPJ                  EPM                  4        24       E]EPJ                  ER[8X  d   ](! ER}4       M'E]EPJ                  ER\8X  d   ](! ER~4       M	](! ER4       ](! 4        E]	! E]EPF                  E]E]EPJ                  ER7      EPO                  4        R# R#   ]' d    Rt&](! R4       ](! R4        ELi ; i  ]' d     ! R
 R4      t*Rt+ ELi ; i  ]' d	    Rt,Rt- ELi ; i  ]' d    Rt/ ELi ; i  ]' d    Rt1Rt2](! R4        ELi ; i  ]' d	    Rt3Rt4 EL#i ; iu up i (  u  
ML Stock Trading System v9 — Alpaca WebSocket + Finnhub Multi-Source Edition
=============================================================================
KEY IMPROVEMENTS OVER v6:
  BUG FIXES:
    - DB freeze fixed: dedup cache (5s buckets) replaces UNIQUE constraint so
      valid quotes are never silently dropped.
    - Training stall fixed: first train triggers as soon as 5+ symbols have
      enough data, not gated behind a 100-cycle counter.
    - Clone agents each get their own independent StockModel instance.
    - Quote polling is strict round-robin (not random weighted).
    - MetaLearner trains unconditionally at every retrain cycle.
    - Agent→agent knowledge sharing still requires profit (donor must be +ve).
    - Clone min_conf hard-capped at 0.62 after param nudging.
 
  DATA SOURCES:
    - Alpaca WebSocket (FREE): minute bars for ALL IEX symbols (~8,000-9,000).
      Subscribed with wildcard "*" — zero polling calls used.
      Pushes a bar every 60s per symbol automatically.
      No rate limit, no daily cap, 0 REST calls consumed.
    - Finnhub REST (FREE, 58/min): live quotes for your active 300-stock
      universe via strict round-robin. Now supplemental to Alpaca — used for
      sub-minute price freshness on symbols agents are holding or watching.
    - Alpha Vantage (FREE, 25/day): 5-min intraday bars, supplemental.
    - Polygon (FREE, 5/min): prev-day minute bars at market open.
 
  VELOCITY FEATURE (NEW):
    - Every bar arrival from Alpaca records the time since the last bar.
    - price_velocity = (close_now - close_prev) / seconds_elapsed
    - Added as "price_velocity" to FEATURE_COLS so models learn from it.
 
  DATA COVERAGE:
    - Alpaca free IEX wildcard: ~8,000-9,000 unique symbols per minute.
    - Finnhub 58/min round-robin: your 300-stock universe covered every ~5 min.
    - Combined: all 300 core stocks get sub-minute Alpaca bars PLUS Finnhub
      confirmation quotes, giving the densest free live dataset possible.
 
  BEST STOCK RANGE FOR PROFIT (see STOCK_UNIVERSE_PRIMARY comments):
    Sweet spot is $5-$200 mid-cap liquid stocks with tight spreads.
    Mega-caps (AAPL, MSFT) are too efficient — thin margins for ML edge.
    Penny stocks (<$5) are too volatile and often illiquid on IEX.
    Best performers empirically: $20-$80 range, daily volume >500k,
    sectors: Tech, Financials, Healthcare, Energy. ETFs excluded from trading.
 
  THOUGHT PROCESS / VISIBILITY:
    - All BUY/SELL decisions logged with full reasoning chain:
      own_conf, meta_conf, effective_conf, threshold, decision.
    - Hourly report includes WIN/LOSS summary: gross profit, gross loss,
      total P&L, win streaks, per-agent breakdown.
    - TRADE_LOG.csv written in real-time for external Excel/pandas analysis.
    - MetaLearner logs which symbols it's boosting and why.
 
  TRAINING:
    - Each agent has slightly different GBM hyperparams so models diverge.
    - Training is ONLINE: only live quotes collected during market hours.
    - Retrain every 15 min at :00/:15/:30/:45 during market hours.
    - Agents scale to 3x CPU cores, capped at 48 total.
 
Install:
    pip install finnhub-python scikit-learn numpy pandas joblib pytz                 matplotlib requests websocket-client
 
Usage:
    export FINNHUB_API_KEY=your_key_here
    export ALPACA_API_KEY=your_alpaca_key        # free at alpaca.markets
    export ALPACA_SECRET_KEY=your_alpaca_secret
    export ALPHA_VANTAGE_KEY=your_key_here       # optional
    export POLYGON_KEY=your_key_here             # optional
    python StockTrading_v7.py
Ndatetime	timedelta)dequedefaultdictAggTFzK[WARNING] websocket-client not installed. Run: pip install websocket-clientuB             Alpaca stream disabled — falling back to Finnhub only.)SentimentIntensityAnalyzerc                   &   a  ] tR t^it o R tRtV tR# )r   c                
    R R/# )compound         )selftexts   &&StockTrading.pypolarity_scores*SentimentIntensityAnalyzer.polarity_scoresj   s    $$    r   N)__name__
__module____qualname____firstlineno__r   __static_attributes____classdictcell____classdict__s   @r   r   r   i   s     	% 	%r   r   z;[WARNING] lightgbm not installed. Run: pip install lightgbm)ThreadPoolExecutoras_completed)GradientBoostingClassifierGradientBoostingRegressor)StandardScaler)train_test_split)accuracy_scoreFINNHUB_API_KEY(d6c79h9r01qsiik11kt0d6c79h9r01qsiik11ktgALPACA_API_KEYPKLNUNIF76AZQBULGIKCRYLKQ2ALPACA_SECRET_KEY,FNqvcb93Vb7C5U1t6vuafNkjR61zhxqkPq7as8qYnSm8ALPHA_VANTAGE_KEYCKDWGTR0PKRWHEBUPOLYGON_KEY g     @@皙?Q?333333?皙?皙?      ??皙?zdata/db/trading_datac                $    V ^8  d   QhR\         /#    returnstr)formats   "r   __annotate__r<      s     F F Fr   c                 ^    \          R\        P                  ! 4       P                  R4       R2# )z(Return the DB filename for today's date._%Y%m%d.db)DB_FILE_PREFIXr   nowstrftimer   r   r   _today_db_pathrD      s(    Qx||~66x@AEEr   c                $    V ^8  d   QhR\         /# r6   list)r;   s   "r   r<   r<      s      t r   c                 d   ^ RI p \        P                  ! 4       \        \        R7      ,
          P                  R4      p. p\        V P                  \         R24      4       F  pVP                  \         R2R4      P                  RR4      pWA8  d   VP                  V4       KE   R FL  p\        P                  P                  W5,           4      '       g   K0  \        P                  ! W5,           4       KN  	  K  	  \        4       pWb9  d   VP                  V4       V#   \         d     K  i ; i)	z]Return all daily DB paths sorted oldest-first.
Auto-deletes files older than DB_HISTORY_DAYS.Ndaysr?   _????????.dbr>   r,   r@   r,   -wal-shm)globr   rB   r   DB_HISTORY_DAYSrC   sortedrA   replaceappendospathexistsremove	ExceptionrD   )rO   cutoffpathspdate_strsuffixtodays          r   _all_db_pathsr_      s     llnyo>>HHRFEDII 0=>?99/q126>>ubILLO2Fww~~aj11		!*- 3 @ EUL  s   '-D  D  D/.D/backupzfeatures/dailyzfeatures/weeklyi	  ,  zdata/db/sentiment_data.db      Q i        ?       @      ?REDDIT_CLIENT_IDREDDIT_CLIENT_SECRETzStockTradingBot/9.0STOCKTWITS_TOKENiX  zphttps://efts.sec.gov/LATEST/search-index?q=%22{symbol}%22&dateRange=custom&startdt={start}&enddt={end}&forms=8-Kzfhttps://efts.sec.gov/LATEST/search-index?q=%22{symbol}%22&forms=8-K&hits.hits._source=period_of_reportzMhttps://financialmodelingprep.com/api/v4/senate-disclosure?page=0&apikey=demozMhttps://news.google.com/rss/search?q={symbol}+stock&hl=en-US&gl=US&ceid=US:enlogs/trading_data.loglogs/hourly_report.loglogs/TRADE_LOG.csvlogs/train_checkpoint.jsonlogs/train_done.jsonzlogs/debug/debug.logmodelslogs/agent_state.jsonchartsgQ?zAmerica/New_YorkAmerica/Chicagoz'wss://stream.data.alpaca.markets/v2/iexdatalogsz
logs/debugopsexist_okzdata/dbOMP_NUM_THREADS4OPENBLAS_NUM_THREADSMKL_NUM_THREADSc                 N  a4 \        ^4       \        P                  R4       ^ RIp ^dp \        P
                  ! \        4      P                  R4      p\        P                  ! 4       p^ p^ RI	pVP                  \         R24       FV  p \        P                  ! V^R7      ;_uu_ 4       pVP                  R4       RRR4       \        P                  RV 24       KX  	  \$        P&                  ! \$        P(                  P+                  \,        R
4      RR7       \$        P&                  ! \$        P(                  P+                  \,        R4      RR7       \$        P&                  ! \$        P(                  P+                  \,        RR4      RR7       \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      \$        P(                  P+                  \,        R4      .	p	V	 FX  p
\$        P(                  P/                  V
4      '       g   K*  \$        P0                  ! V
4       \        P3                  RV
 24       KZ  	  RRRRRRRR \4        \6        \8        \:        3 EFP  p\$        P(                  P/                  V4      '       g   K+  \        P                  ! 4       p\$        P(                  P+                  \,        \$        P(                  P=                  V4      4      p\$        P&                  ! VRR7       V P?                  V\$        P(                  P+                  \,        V4      4       \$        P(                  PA                  V4      pWN,          p\C        \        P                  ! 4       V,
          R!,          4      pVR"8  g   EK*  \        P#                  R#V R	VR$,           R%V R&24       EKS  	  VP                  \         R24       EFy  pRP EFn  pVV,           p\$        P(                  P/                  V4      '       g   K4  \$        P(                  PA                  V4      pVR'8X  dD   WR$,          R$,          8  d0   \        P#                  R(V R	VR$,          R$,           R)V R*24       K  \        P                  ! 4       pV P?                  V\$        P(                  P+                  \,        \$        P(                  PE                  V4      4      4       WN,          p\C        \        P                  ! 4       V,
          R!,          4      pVR!8  g   EKA  \        P#                  R+V R	VR$,          R$,           R,V R&24       EKq  	  EK|  	  \$        P(                  P/                  R-4      '       dp   \$        P&                  ! \$        P(                  P+                  \,        R4      RR7       V P?                  R-\$        P(                  P+                  \,        RR-4      4       \$        P(                  P+                  \,        R.4      p\$        P&                  ! VRR7       \$        PF                  ! \H        4       FU  pV P?                  \$        P(                  P+                  \H        V4      \$        P(                  P+                  VV4      4       KW  	   / p\$        PF                  ! V4       F<  pVPK                  R/4      ^ ,          pVPM                  V. 4      PO                  V4       K>  	  VPQ                  4        FW  w  pp\S        VRR07      pVR1,           F7  p\$        P0                  ! \$        P(                  P+                  VV4      4       K9  	  KY  	  \$        P(                  P+                  \,        R34      p\$        P&                  ! VRR7       \        P                  ! 4       RQ,
          o4\$        P(                  PU                  \V        4      '       dk   \X        ;QJ d7    V43R4 l\$        PF                  ! \V        4       4       F  '       g   K   RM.	  R5M*! V43R4 l\$        PF                  ! \V        4       4       4      MR5pV'       d   \$        PF                  ! \V        4       FU  pV P?                  \$        P(                  P+                  \V        V4      \$        P(                  P+                  VV4      4       KW  	  \        P3                  R64       M\        P                  R74       V^ ,          p \$        P(                  P+                  RR4      p\$        P(                  PU                  V4      '       d   \        P                  ! 4       RR,
          p\$        PF                  ! V4       F  pVP[                  R84      '       g   K  VP]                  R94      '       g   K5  \$        P(                  P+                  VV4      p \$        P(                  P_                  V 4      V8  g   K{  \$        P0                  ! V 4       K  	   ^ RI	p"\        P                  ! 4       RS,
          p#\$        P(                  P+                  \,        R;4      \$        P(                  P+                  \,        R4      .p$T$ F  p%T"P                  T%4       Fx  p&\$        P(                  P_                  T&4      T#8  g   K)  RP FI  pT&T,           p'\$        P(                  P/                  T'4      '       g   K3  \$        P0                  ! T'4       KK  	  Kz  	  K  	   \        P                  ! 4       RT,
          p)\        P                  ! 4       RU,
          p*\`        T)R=3\b        T*R>33 F  w  p+pp,\$        P(                  PU                  T+4      '       g   K.  \$        PF                  ! T+4       Fz  p-\$        P(                  P+                  T+T-4      p \$        P(                  P_                  T 4      T8  g   KI  \$        P0                  ! T 4       \        P3                  R?T, R@T- 24       K|  	  K  	   RV F  pX"P                  \         RT 24       Fg  p/T/R\e        T4      )  p0\$        P(                  P/                  T04      '       d   K9  \$        P0                  ! T/4       \        P3                  RBT/ 24       Ki  	  K  	  \C        \        P                  ! 4       T,
          R!,          4      p2\f        P3                  RD\,         RET RF24       \        P3                  RGT RHTR$,          R$,           RIT2 R&24       T2RJ8  d   \        P#                  RKT2 RL24       R# R#   + '       g   i     ELl; i  \          d(   p\        P#                  RT R	T 24        Rp?EK  Rp?ii ; i  \          d$   p\        P#                  R2T 24        Rp?ELWRp?ii ; i  \          d$   p!\        P#                  R:T! 24        Rp!?!ELRp!?!ii ; i  \          d$   p(\        P#                  R<T( 24        Rp(?(ELRp(?(ii ; i  \          d$   p.\        P#                  RAT. 24        Rp.?.EL1Rp.?.ii ; i  \          d$   p1\        P#                  RCT1 24        Rp1?1ELRp1?1ii ; i  \          d>   p3\f        P#                  RMT3 24       \        Pi                  RNT3 2RRO7        Rp3?3R# Rp3?3ii ; i)Wad  
Local backup of important files to backup/

WAL FIX: The trading_data DB WAL file grew to 2.9 GB. Copying 2.9 GB
in a background thread saturated disk I/O for 20-30 seconds, delaying
all threads including the WebSocket ping thread.
Now: WAL files > WAL_BACKUP_CAP_MB are skipped -- they will be
checkpointed at the next PRAGMA wal_checkpoint call anyway.
local_backup_startN%Y%m%d_%H%M%SrK   timeoutPRAGMA wal_checkpoint(PASSIVE)zBACKUP_WAL_CHECKPOINT | zBACKUP_WAL_CKPT_FAIL |  | ru   Trx   rv   debugzagent_state.jsonz	debug.logzhourly_report.logzTRADE_LOG.csvztrading_data.logzsentiment_data.dbtrading_data.dbztrading_data.db-shmztrading_data.db-walzBACKUP_GHOST_CLEAN | removed rr   rm   rn   rl   logs/human_report.txtlogs/claude_handoff.jsonlogs/bot_dashboard.htmlrp       zBACKUP_SLOW_FILE |    zKB | msrM   zBACKUP_WAL_SKIPPED | MB > z1MB cap -- too large to copy safely during tradingzBACKUP_SLOW_DB | zMB | trading.logrs   r>   )reverse:
   NNzCHART_PRUNE_ERR | saved_modelsc              3      <"   T Fb  pVP                  R 4      '       g   K  \        P                  P                  \        P                  P	                  \
        V4      4      S8  x  Kd  	  R# 5i).pklN)endswithrT   rU   getmtimejoinMODEL_SAVE_DIR).0f_model_cutoffs   & r   	<genexpr>run_backup.<locals>.<genexpr>  sJ       
/zz&! NBGGRWW\\.!<=M/s   A-AA-Fz)BACKUP_MODELS | copied (recently trained)z,BACKUP_MODELS | skipped (no recent training)debug_.logzDEBUG_LOG_CLEANUP_ERR | ztrading_data_????????.dbzBACKUP_DB_CLEANUP_ERR | 
DAILY_FEATWEEKLY_FEATzFEAT_RETENTION_CLEAN | z | removed zFEAT_RETENTION_ERR | zORPHAN_SIDECAR_CLEAN | removed zORPHAN_SIDECAR_ERR | zBackup complete -> z/  (z CST)zBACKUP_COMPLETE | ts=z	 | bytes=zMB | elapsed=i  zBACKUP_SLOW_TOTAL | z3ms -- disk I/O pressure may delay WebSocket thread!zBackup error: zBACKUP_ERROR | exc_inforL   i0*  i ' i:	 i u i  )rN   rM   )5	_set_nice_resource_guardyield_p4shutilr   rB   
DISPLAY_TZrC   timerO   rA   sqlite3connectexecutedebug_loggerr   rX   warningrT   makedirsrU   r   
BACKUP_DIRrV   rW   infoSENTIMENT_DB_FILEDATA_LOG_FILEREPORT_LOG_FILEDEBUG_LOG_FILEdirnamecopy2getsizeintbasenamelistdir
CHARTS_DIRsplit
setdefaultrS   itemsrQ   isdirr   any
startswithr   r   FEATURES_DAILY_DIRFEATURES_WEEKLY_DIRlenloggererror)5r   WAL_BACKUP_CAP_MBtst_startbytes_copied_glob_db_c_e_ghost_files_gffnamet0dest_dirszelapsed_sfx_srcbackup_chartsr   _chart_by_type_cf_ctype_cfiles_sorted
_old_chart_ce3backup_models_any_model_recent
_debug_dir_cutoff_f_fp_ce_g2
_db_cutoff_db_patterns_pat_old_p_ce2_feat_daily_cutoff_feat_weekly_cutoff_fdir_label_ff_fe_side_main_oetotal_mser   s5                                                       @r   
run_backupr   ]  s#    bM12CA\\*%..?))+ 	:: 0=>CM__S!44JJ?@ 5""%=cU#CD	 ? 	BGGLLV4tD
BGGLLV4tD
BGGLLVW=M GGLL%78GGLL[1GGLL%89GGLL_5GGLL%78GGLL%89GGLL%67GGLL%:;GGLL%:;

  Cww~~c""		#!!$A#"GH   $&> &=#&@%&<?N
E ww~~e$$YY[77<<
BGGOOE4JKHt4UBGGLLU$CDWW__U+"tyy{R/478S= ((+>ugST
RWX_W``b)cd%
* :: 0=>C,Tzww~~d++WW__T*6>bt+Cd+J&J ((/vSt8T>*%0A/B CBC
 YY[T277<<
BGG<L<LT<R#ST"tyy{R/478T> ((+<TF#b$hPTnEUUZ[bZcce)fg# - ?( 77>>-((KKZ84HLLZ(WX Z:
MD1J'ALLj!4bggll=RS6TU (
	>#%Nzz-03*))&"5<<SA 1 $2#7#7#9 $7")#,,JIIbggll=*EF #/ $: Z@
MD1		h.
 WW]]>**	  C  
ZZ/ 
CCC  
ZZ/ 
 
 16	 	
 ZZ/RWW\\.!<bggll=Z[>\] 0IJMNAL
	Cfg6Jww}}Z(())+
2**Z0B}}X..2;;v3F3F ggll:r:77++C07:IIcN	 1	Dy0JZ)CDZ):;L %HHTNDww''-
:$8D!%B!ww~~b11 "		" %9 + %	@"&))+
":"&))+">#&8<H$&9=I+&w ww}}U++::e,C'',,uc2Cww'',w6		#$)),CF8;WZV[*\]	 -+	@( XX(8TF&KLE!+CI:.E77>>%00		%($)),KE7*ST	 M ) 		g-56)*T"UCD#B4 (!4'-.mH:RI	
 d?  &xj 1@ A g 544  M$$'>se3rd%KLLMl  	>  #5dV!<==	>>  	C  #;C5!ABB	C&  	D  #;D6!BCC	D(  	@  #8!>??	@  	@  #8!>??	@  As+,_QC04@@As  A} 	 x2)x; x2H} 7A6} 2C9} 1F} ;A} D} 6Cy' 9B} ,} 49} .B'} Az A	z )z Az z #B"{	 
0{	 ?"{	 "C{: 99{: 3A|+ 6|+ B} x/)	x22y$=y} y$$} 'z2z
} z} {#{;} {} 	{7{2,} 2{77} :|(|#} #|((} +}6}} }} ~$'2~~$c                   R   a  ] tR tRt o Rt]P                  ! R4      tRR ltRt	V t
R# )_CSTFormatteri<  z?Log formatter that outputs timestamps in CST (America/Chicago).rt   Nc                    \         P                  ! VP                  V P                  R 7      pTP	                  T;'       g    R4      # )tz%Y-%m-%d %H:%M:%S)r   fromtimestampcreated_CSTrC   )r   recorddatefmtdts   &&& r   
formatTime_CSTFormatter.formatTime@  s4    ##FNNtyyA{{799&9::r   r   N)r   r   r   r   __doc__pytztimezoner  r  r   r   r   s   @r   r   r   <  s!     I==*+D; ;r   r   c                   .   a  ] tR tRt o RtRR ltRtV tR# )_CSTFormatterMsiD  z.CST formatter with milliseconds for debug.log.Nc                    \         P                  ! VP                  V P                  R 7      pVP	                  R4      pV R\        VP                  4      R 2# )r   r   .03d)r   r  r  r  rC   r   msecs)r   r  r  r  bases   &&&  r   r  _CSTFormatterMs.formatTimeF  sH    ##FNNtyyA{{./qV\\*3/00r   r   r	  )r   r   r   r   r
  r  r   r   r   s   @r   r  r  D  s     81 1r   r  z'%(asctime)s [%(levelname)s] %(message)sr   )r  z8%(asctime)s [%(levelname)s] [%(threadName)s] %(message)s)levelhandlersreportr   r>   r   r   w)modec                     \         P                  P                  \        4      '       gO   \	        \        R RR7      ;_uu_ 4       p \
        P                  ! V 4      pVP                  . RO4       RRR4       R# R#   + '       g   i     R# ; i)r  r,   newlineN)	timestampagenttypesymbolsharesentry_price
exit_pricepnlpnl_pctpredicted_pctdisc_ppreason	held_secsown_conf	meta_confeff_conf)rT   rU   rV   TRADE_LOG_FILEopencsvwriterwriterow)r   r  s     r   _init_trade_logr2  {  s[    77>>.)).#r22a

1AJJ   32 *222s   *A::B	c                $    V ^8  d   QhR\         /# )r7   rowdict)r;   s   "r   r<   r<     s     O O Or   c                     \         ;_uu_ 4        \        \        R RR7      ;_uu_ 4       p\        P                  ! V4      pVP                  V P                  RR4      V P                  RR4      V P                  RR4      V P                  RR4      V P                  R^ 4      R	 V P                  R
^ 4      R	 V P                  R^ 4      R	 V P                  R^ 4      R V P                  R^ 4      R V P                  R^ 4      R V P                  R^ 4      R V P                  RR4      V P                  R^ 4      V P                  R^ 4      R V P                  R^ 4      R V P                  R^ 4      R .4       RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i  \         d+   p\        P                  RT R\         24        Rp?R# Rp?ii ; i)ar,   r  r  r  r  SELLr   r!  .4fentryexitr$  z+.4fr%  +.2fr&  r'  .3fr(  r)  r*  r+  r,  NzTRADE_LOG_WRITE_ERR | z | file=)
_trade_log_lockr.  r-  r/  r0  r1  getrX   r   r   )r4  r   r  _wtles   &   r   write_trade_logrB    s   O_nc266!JJqM

GGK+0CGGF6*0Dwwx*3/wwwq)#.CGGF14Ec3JwwuQ'-3779Q3G2Mwwq1$7wwy+C0GGHR(A0Fwwz!,S1ww{1-c2wwz!,S1  7 _66 __   O-eWH^<LMNNOsL   F0 FEF		7F?F0 	FFF-	'F0 -F0 0G%;G  G%AMDINTCCRMADBEORCLQCOMTXNMUAMATLRCXKLACMRVLAVGOCSCOIBMHPQHPEDELLWDCSNPSCDNSANSSDDOGZSCRWDPANWFTNTNETOKTATEAMHUBSNVDAGOOGLMETAMSFTAAPLJPMBACGSMSWFCCVMAAXPCOFDFSBKSTTUSBPNCTFCFITBKEYCFGHBANMTBRFZIONCMASCHWRJFNTRSICECMECBOESPGIMCOBLKTROWIVZBENJNJUNHPFEABBVMRKCVSMDTABTTMODHRISRGBSXEWSYKZBHBDXBAXHOLXALGNIDXXIQVLHDGXHCACNCMOHHUMCIELVMCKABCCAHWBAXOMCVXCOPSLBOXYEOGPXDMPCVLOPSXHESDVNFANGBKRHALNOVMROAPACTRAAREQTTPLDINOSMMTDRAMZNTSLAHDMCDNKESBUXLOWTJXROSTBBYKSSMJWNDRICMGYUMQSRTXRHEATDPZWENBURLGPSANFAEOURBNPVHHBIVFCLEVISKXWMTPGKOPEPCOSTMDLZGISKCPBCAGHRLMKCCHDCLXCLKMBNWLPOSTLANCBGSINGRSJMTHSCATBAGEMMMHONUPSFDXLMTRTXNOCGDETNEMRROKPHITWDOVXYLGNRCCARROTISTTJCISWKFASTGWWMSMALLERXOCHRWEXPDXPOSAIAODFLJBHTKNXLINAPDECLSHWPPGNEMFCXAANUESTLDRSCMCATICFMOSALBFMCRPMHUNEMNCEOLNSEETREXAVNTAMTPLDCCIEQIXPSAEXRAVBEQRMAAUDRCPTESSNNNOWPCKIMREGBRXSPGIRMVICIGLPINEEDUKSODAEPEXCSREPEGEDFEETRPPLCMSNIWECDTECNPAESESEIXAWKLNTEVRGNFLXDISCMCSATVZTMUSCHTRSIRIFOXANWSPARAWBDSPYQQQIWMDIAMDYXLFXLEXLKXLVXLIXLUXLPXLBXLREXLCGLDSLVTLTIEFHYGLQDUSOEEMVWOEFA:Ni,  Nc           	          \        \        P                  ! V \        P                  P	                  V) V4      W!,
          ,          ,           W4      4      # r	  )floatnpcliprandomuniform)vallohiscales   &&&&r   _mutater    s7    ryy00%?27KKRTUUr   c                 J   \         P                  ! ^*4      p. p\        V 4       F  p\        V\	        \        4      ,          ,          pVP                  RV^ ,          RV^,          RV^,          RV^,          RV^,          RRRV^,          R	R
RVP                  ^R4      R\        VP                  RR4      ^4      RVP                  ^^4      /4       K  	  \        V4       EF<  pW4V ,          ,          p\        P                   P                  V^d,           4       VP                  RRVR,           RV^,            2R\        VR,          .\        O5!  R\        VR,          .\        O5!  R\        \        VR,          .\        O5!  R4      RVR,          \        P                   P                  RR4      ,          R\        R.\         O5!  RVR,          R	RRVP                  ^R4      R\        VP                  RR4      ^4      RVP                  ^^4      /4       EK?  	  V# )*   namestop_loss_pcttake_profit_pctmin_confidencetake_profit_multmax_position_pctr-   risk_toleranceis_cloneFn_estimators  learning_rate{Gz?{Gz?	max_depthClone_r>   ףp=
?皙?333333?Ti^  r1   )r  Randomrange_BASE_PROFILESr   rS   randintroundr  r  seedr  STOP_LOSS_RANGETAKE_PROFIT_RANGEminMIN_CONF_RANGEMAX_POS_PCT_RANGE)n_basen_clonesrngconfigsir[   r  s   &&     r   generate_agent_configsr    s   
--
CG6]1s>223!!!!!!C 5ckk$&=q AAq 1
 	  8_6z"
		q3w&fa!u =_(= Q Q->(? TBS TGD1A,B$T^$TVZ [%7 8299;L;LSRU;V V A/@ A%5 6C 5ckk$&=q AAq 1
 	   Nr   c                $    V ^8  d   QhR\         /# r6   bool)r;   s   "r   r<   r<   %  s     # # #r   c                      \         P                  ! \        4      p V P                  4       ^8  d   R# V P	                  ^	^^ ^ R7      pV P	                  ^^ ^ ^ R7      pYu;8*  ;'       d    V8  # u # )   Fhourminutesecondmicrosecond)r   rB   	MARKET_TZweekdayrR   )rB   open_tclose_ts      r   is_market_openr  %  sd    
,,y
!C
{{}kkq"QAkFFkkr!QAkFG""7""""r   c                $    V ^8  d   QhR\         /# r6   r  )r;   s   "r   r<   r<   -  s     ' 'E 'r   c                     \         P                  ! \        4      p V P                  ^	^^ ^ R7      pW8  d   V\	        ^R7      ,          pVP                  4       ^8  d   V\	        ^R7      ,          pK*  W,
          P                  4       # )	   r  rI   )r   rB   r  rR   r   r  total_seconds)rB   nxts     r   seconds_until_openr  -  sh    
,,y
!C
++1Rq+
AC
zya  
++-1
ya  I$$&&r   c                $    V ^8  d   QhR\         /# r6   r  )r;   s   "r   r<   r<   6  s     : :% :r   c                      \         P                  ! \        4      p V P                  ^^ ^ ^ R7      p\	        RW,
          P                  4       R,          4      # )   r  r         N@)r   rB   r  rR   maxr  )rB   closes     r   market_minutes_remainingr  6  sC    
,,y
!CKKR!KCEsU[//1D899r   c                      a  ] tR tRt o V 3R lR ltR tR tRR ltV 3R lR ltV 3R	 lR
 lt	V 3R lR lt
RR ltRV 3R lR lltV 3R lR ltRtV tR# )Databasei?  c                    < V ^8  d   QhRS[ /# )r7   rU   r9   )r;   r   s   "r   r<   Database.__annotate__@  s      S r   c                    Wn         \        P                  ! 4       V n        \        P                  ! 4       V n        V P                  4        / V n        R # r	  )_path	threadinglocal_localLock_lock_init_schema_dedupr   rU   s   &&r   __init__Database.__init__@  s6    
oo'nn&
r   c                ,   \        V P                  R 4      '       d   V P                  P                  f   \        P                  ! V P
                  RR7      pVP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R	4       VP                  R4       WP                  n        V P                  P                  # )
connFcheck_same_threadPRAGMA journal_mode=WALPRAGMA synchronous=NORMALPRAGMA cache_size=-32768PRAGMA mmap_size=268435456PRAGMA temp_store=MEMORYPRAGMA busy_timeout=5000PRAGMA cache_size=-32000)hasattrr  r  r   r   r  r   r   r  s   & r   _connDatabase._connG  s    t{{F++t{{/?/?/G??4::GD LL23LL45LL34LL56LL34LL34LL45LL34LL34#KK{{r   c                H   \         P                  ! V P                  4      ;_uu_ 4       pVP                  R 4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R4       VP                  R	4       VP	                  4        R
R
R
4       R
#   + '       g   i     R
# ; i)r  r  r  r  r  r  r  aH  
                CREATE TABLE IF NOT EXISTS quotes (
                    id         INTEGER PRIMARY KEY AUTOINCREMENT,
                    symbol     TEXT    NOT NULL,
                    ts         INTEGER NOT NULL,
                    ts_micro   INTEGER NOT NULL DEFAULT 0,
                    price      REAL    NOT NULL,
                    open       REAL,
                    high       REAL,
                    low        REAL,
                    prev_close REAL,
                    volume     REAL,
                    source     TEXT    DEFAULT 'finnhub'
                )z:CREATE INDEX IF NOT EXISTS idx_sym_ts ON quotes(symbol,ts)a  
                CREATE TABLE IF NOT EXISTS accuracy_log (
                    id           INTEGER PRIMARY KEY AUTOINCREMENT,
                    ts           INTEGER NOT NULL,
                    agent        TEXT    NOT NULL,
                    discrepancy  REAL,
                    profit_rate  REAL,
                    trades       INTEGER,
                    gross_profit REAL DEFAULT 0,
                    gross_loss   REAL DEFAULT 0
                )N)r   r   r  r   commitr  s   & r   r  Database._init_schema\  s    __TZZ((DLL23LL45LL34LL56LL34LL34LL45LL34LL34LL   LLUVLL 
 
 KKMI )(((s   CDD!	c
                   W^,          3p
V P                   ;_uu_ 4        WP                  9   d    RRR4       R# RV P                  V
&   \        V P                  4      R8  dA   \        V P                  P	                  4       4      R,          pV F  pV P                  V K  	   V P                  4       pVP                  RW\        \        P                  ! 4       R,          4      R,          W4WVWxV	3
4       VP                  4        RRR4       R#   \         d&   p\        P                  RT RT 24        Rp?L5Rp?ii ; i  + '       g   i     R# ; i)	r  NTiP  :Ni'  NzoINSERT INTO quotes(symbol,ts,ts_micro,price,open,high,low,prev_close,volume,source) VALUES(?,?,?,?,?,?,?,?,?,?)@B zDB insert error : )r  r  r   rG   keysr  r   r   r   r  rX   r   r   )r   r   r   priceopen_highlow
prev_closevolumesourcebucketoldestkr  r   s   &&&&&&&&&&     r   insertDatabase.insert  s   '"ZZZ$ Z #'DKK4;;&(dkk..01':AA  
?zz|3TYY[9%<!=	!I4j&J ! Z"  ?/xr!=>>?# ZZs6   EA)E%A"DED<7E<EEE	c                &   < V ^8  d   QhRS[ RS[/# )r7   rowsr8   )rG   r   )r;   r   s   "r   r<   r    s        r   c                   V'       g   ^ # ^ pV P                   ;_uu_ 4         V P                  4       pV F  pV^ ,          V^,          reWV^,          3pWpP                  9   d   K0  RV P                  V&   TP                  RV^ ,          V^,          ^ V^,          V^,          V^,          V^,          V^,          V^,          \	        V4      ^8  d
   V^,          MR3
4       V^,          pK  	  VP                  4        RRR4       V#   \         d#   p\        P                  RT 24        Rp?L2Rp?ii ; i  + '       g   i     T# ; i)    TzyINSERT OR IGNORE INTO quotes(symbol,ts,ts_micro,price,open,high,low,prev_close,volume,source) VALUES(?,?,?,?,?,?,?,?,?,?)externalzDB bulk insert error: N)	r  r  r  r   r   r  rX   r   r   )	r   r
  nr  rsymr   r  r   s	   &&       r   bulk_insertDatabase.bulk_insert  s   ZZZ;zz|AdAaD!7^F, *.DKK'LL71qtQ!adAaD!A$!ad!$Q!1= FA  ! &   ;5aS9::;# Z& s/   D8CDD5D0+D80D55D88E		c                :   < V ^8  d   QhRS[ RS[P                  /# r7   r   r8   r:   pd	DataFrame)r;   r   s   "r   r<   r    s     
" 
" 
" 
"r   c                     V P                  4       p\        P                  ! R W!3R7      pV#   \         d    \        P                  ! 4       u # i ; i)zZSELECT ts,price,open,high,low,prev_close,volume FROM quotes WHERE symbol=? ORDER BY ts ASCparamsr  r  read_sql_queryrX   r  )r   r   r  dfs   &&  r   
get_seriesDatabase.get_series  sN    		"::<D""2YB
 I 	"<<>!	"s   *-  AAc                    < V ^8  d   QhRS[ /# r6   r5  )r;   r   s   "r   r<   r    s      D r   c                     V P                  4       pVP                  R 4      P                  4       pV Uu/ uF  q3^ ,          V^,          bK  	  up# u upi   \         d    / u # i ; i)z3SELECT symbol, COUNT(*) FROM quotes GROUP BY symbol)r  r   fetchallrX   )r   r  r
  r  s   &   r   
row_countsDatabase.row_counts  se    	::<D<<Ehj  )--1aD!A$J--- 	I	s"   3A AA A A&%A&c                6   V P                   ;_uu_ 4         V P                  4       pVP                  R WW4WVV34       VP                  4        RRR4       R#   \         d#   p	\
        P                  RT	 24        Rp	?	L2Rp	?	ii ; i  + '       g   i     R# ; i)zoINSERT INTO accuracy_log(ts,agent,discrepancy,profit_rate,trades,gross_profit,gross_loss) VALUES(?,?,?,?,?,?,?)zlog_accuracy error: N)r  r  r   r  rX   r   r   )
r   r   r  discprofit_ratetradesgross_profit
gross_lossr  r   s
   &&&&&&&&  r   log_accuracyDatabase.log_accuracy  s}    ZZZ	9zz|-6T
  Z  93A37889 ZZs.   B6AB"A?:B?BBB	c                @   < V ^8  d   QhRS[ RS[RS[P                  /# )r7   r  limitr8   )r:   r   r  r  )r;   r   s   "r   r<   r    s&     	" 	"# 	"c 	"BLL 	"r   c                     V P                  4       p\        P                  ! R W1V3R7      #   \         d    \        P                  ! 4       u # i ; i)zySELECT ts,discrepancy,profit_rate,trades,gross_profit,gross_loss FROM accuracy_log WHERE agent=? ORDER BY ts DESC LIMIT ?r  r  )r   r  r.  r  s   &&& r   get_accuracy_historyDatabase.get_accuracy_history  sO    	"::<D$$LU^ 
  	"<<>!	"s   ),  AAc                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r    s       r   c                     \         P                  P                  V P                  4      R ,          #   \         d     R# i ; i)i   r   )rT   rU   r   r  rX   r   s   &r   size_mbDatabase.size_mb  s5    	77??4::.:: 		s   /2 A A)r  r  r  r  N)finnhub)r   r   )d   )r   r   r   r   r  r  r  r  r  r  r#  r+  r0  r5  r   r   r   s   @r   r  r  ?  sV       *%N?, 2
" 
" 9	" 	" r   r  c                   n   a  ] tR tRt o V 3R lR ltR tV 3R lR ltV 3R lR ltV 3R	 lR
 ltRt	V t
R# )FinnhubClienti  c                    < V ^8  d   QhRS[ /# r7   api_keyr9   )r;   r   s   "r   r<   FinnhubClient.__annotate__  s     ' ' 'r   c                    \         P                  ! VR 7      V n        \        4       V n        \
        P                  ! 4       V n        R# ))r=  N)r7  Clientclientr   _timesr  r  r  r   r=  s   &&r   r  FinnhubClient.__init__  s)    nnW5gnn&
r   c                X    V P                   ;_uu_ 4        \        P                  ! 4       pV P                  '       d;   WP                  ^ ,          ,
          R8  d   V P                  P                  4        KL  \	        V P                  4      \
        8  d:   V P                  P                  \        P                  ! 4       4        RRR4       R# RWP                  ^ ,          ,
          ,
          pRRR4       X^ 8  g   K  \        P                  ! V4       EK    + '       g   i     L2; iTr  Ng     N@)r  r   rB  popleftr   FH_CALLS_PER_MINrS   sleepr   rB   waits   &  r   	_throttleFinnhubClient._throttle  s    iikkkkcKKN&:T&AKK'')t{{#&66KK&&tyy{3  s[[^34  ax

4  s   'DBD DD)	c                    < V ^8  d   QhRS[ /# r6   r   )r;   r   s   "r   r<   r>    s     B B3 Br   c                   a \         P                   ! 4       oV P                  ;_uu_ 4        \        V3R  lV P                   4       4      uuRRR4       #   + '       g   i     R# ; i)c              3   H   <"   T F  pSV,
          R 8:  g   K  ^x  K  	  R# 5i)r  Nr   )r   trB   s   & r   r   2FinnhubClient.calls_this_minute.<locals>.<genexpr>   s     A+QqDqq+s   "
"N)r   r  sumrB  r   rB   s   &@r   calls_this_minuteFinnhubClient.calls_this_minute  s5    iikZZZA$++AA ZZZs   AA&	c                    < V ^8  d   QhRS[ /# r7   r   r9   )r;   r   s   "r   r<   r>    s      C r   c                   V P                  4         V P                  P                  V4      pV'       d   VP                  R ^ 4      ^ 8  d   V# R#   \         d'   p\
        P                  RT RT 24        Rp?R# Rp?ii ; i)cNzQuote error r  )rL  rA  quoter@  rX   r   r   )r   r   qr   s   &&  r   r\  FinnhubClient.quote  so    	!!&)AaeeCma/19T9 	LL<xr!56	s"   "A A A BA<<Bc                    < V ^8  d   QhRS[ /# rY  r9   )r;   r   s   "r   r<   r>    s      c r   c                    V P                  4         V P                  P                  VR 7      #   \         d'   p\        P                  RT RT 24        Rp?R# Rp?ii ; i)r   zProfile error r  N)rL  rA  company_profile2rX   r   r   )r   r   r   s   && r   profileFinnhubClient.profile  sU    	;;//v/>> 	LL>&A378	s   . AAA)r  rB  rA  N)r   r   r   r   r  rL  rV  r\  rc  r   r   r   s   @r   r:  r:    s4     ' '
!B B
  r   r:  c                      a  ] tR tRt o RtV 3R lR ltR tR tV 3R lR ltR	 t	R
 t
R tR tR tV 3R lR ltRtV tR# )AlpacaWebSocketClienti   a  
Connects to Alpaca's free IEX data stream and subscribes to minute bars
for ALL symbols using the "*" wildcard.

Received bars are written directly to the shared Database and prices dict.
price_velocity is computed from the time delta between consecutive bars
for each symbol and stored alongside the price for use as a feature.

Runs in a background daemon thread. Reconnects automatically on dropout.
c                *   < V ^8  d   QhRRRS[ RS[ /# )r7   dbr  pricesvelocityr5  )r;   r   s   "r   r<   "AlpacaWebSocketClient.__annotate__,  s"     
& 
&: 
&t 
&t 
&r   c                    Wn         W n        W0n        R V n        RV n        RV n        / V n        ^ V n        \        P                  ! 4       V n
        R# FN)rh  ri  rj  _running_thread_ws	_last_bar_bars_receivedr  r  r  )r   rh  ri  rj  s   &&&&r   r  AlpacaWebSocketClient.__init__,  sC     !^^%
r   c           
     P   \         P                  R 4       \        P                  ! 4       V n        V P                  V n        \        P                  RV P                   R\        V R^ 4       24       \        P                  ! RRR\        R\        /4      pVP                  V4       R# )	z'Alpaca WS: connected, authenticating...zWS_OPEN | bars_so_far= | consec_fails=_consec_failsactionauthkeysecretN)r   r   r   _connect_timerr  _bars_at_connectr   getattrjsondumpsr%   r'   send)r   wsauth_msgs   && r   _on_openAlpacaWebSocketClient._on_open8  s    => "YY[ $ 3 3243F3F2GGWX_`detuvXwWxyz::fn'
 
 	r   c           	     T    \         P                  ! V4      p\        V\        4      '       g   V.pV EF?  pVP	                  R 4      pVR8X  d   VP	                  R4      R8X  dD   \
        P                  R4       \         P                  ! RRRR./4      pVP                  V4       Ku  VP	                  R4      R	8X  d   \
        P                  R
4       K  K  VR8X  d7   \        VP	                  R. 4      4      p\
        P                  RV R24       K  VR8X  d   V P                  V4       K  VR8X  g   EK  \
        P                  RVP	                  R4       RVP	                  R4       R24       EKB  	  R#   \         d$   p\
        P                  RT 24        Rp?R# Rp?ii ; i)rh  successmsgauthenticatedu8   Alpaca WS: authenticated — subscribing to all bars (*)rw  	subscribebars*	connectedz!Alpaca WS: connection establishedsubscriptionu   Alpaca WS: subscribed — bars=z (wildcard active)br   Alpaca WS error: z (code=code)zAlpaca WS message error: N)r~  loads
isinstancerG   r@  r   r   r  r  r   _handle_barr   rX   r   )	r   r  messageru   r  msg_typesub_msg	bar_countr   s	   &&&      r   _on_message!AlpacaWebSocketClient._on_messageI  s`   	:::g&DdD))v773<y(wwu~8$^_"&**$k"se. # (;6$GH 7 / #CGGFB$7 8IKK"A)L^ _`_$$S)(LL#4SWWU^4DGCGGTZOK\\]!^_/ 2  	:LL4QC899	:s   D0E9 8?E9 9F'F""F'c                    < V ^8  d   QhRS[ /# )r7   r  r5  )r;   r   s   "r   r<   rk  j  s     63 63t 63r   c                    VP                  RR4      pV'       g   R# \        VP                  R^ 4      4      pV^ 8:  d   R# \        VP                  RV4      4      p\        VP                  RV4      4      p\        VP                  RV4      4      p\        VP                  R^ 4      4      pVP                  R	R4      p \        P                  ! VP	                  R
R4      4      p	\        V	P                  4       4      p
V P                  ;_uu_ 4        V P                  P                  V4      pVe'   Vw  r\        W,
          ^4      pW=,
          V,          pMRpW3V P                  V&   RRR4       W P                  9   d&   V P                  P                  V^ V34      ^,          MTpV P                  P                  W*W4WVWRR7	       W0P                  V&   XV P                  V&   V P                  ;_uu_ 4        V ;P                   ^,          un        V P                   R,          ^ 8X  d%   \"        P%                  RV P                   R R24       RRR4       R#   \         d#    \        \        P                  ! 4       4      p
 ELi ; i  + '       g   i     EL); i  + '       g   i     R# ; i  \         d$   p\"        P'                  RT 24        Rp?R# Rp?ii ; i)z
Process a single minute bar from Alpaca.
Format: {T, S, o, h, l, c, v, t, n, vw}
  T  = message type ("b")
  S  = symbol
  o  = open, h = high, l = low, c = close
  v  = volume, t = bar timestamp (ISO), n = trade count, vw = vwap
Sr,   Nr[  ohlvrR  Zz+00:00r   alpaca)r  r   zAlpaca WS: ,z bars received totalzAlpaca bar error: )r@  r  r   fromisoformatrR   r   r  rX   r   r  rq  r  rh  r  ri  rj  rr  r   r   r   )r   r  r  r  r  r  r   volt_strbar_dtr   prevprev_tsr  r   rj  r   s   &&               r   r  !AlpacaWebSocketClient._handle_barj  sI   -	3GGC$C#''#q/*Ez3773./E3773./D3773./C3773?+CWWS"%E&!//c80LMV--/0
 ~~))#.#*.'G!",2G % 2g=H"H')ks#  DG..CX++C!U<Q?^cJGGNN3E$ZU]N^ "'KK!)DMM###q(#&&-2KK+d.A.A!-DDX YZ -  &%& $ 
  	3LL-aS122	3s   J4 "J4 A>J4 ?I  J4 AJ,BJ4 <AJ J4 )J	J4 J		J4 J		J4  J1	+J4 1J4 4K"?KK"c                    \         P                  R V 24       \        P                  RV RV P                  R R\        P
                   R\        P                   R\        P                   R24       R# )	r  zWS_ERROR |  | bars=r   | resource= | load= | ram=MBN)r   r   r   rr  r   statusload_str_ram_used_mb)r   r  r   s   &&&r   	_on_errorAlpacaWebSocketClient._on_error  su    *5'23%)<)<Q(? @'../ 0#,,- ."//04	
r   c                   \         P                  R V RV 24       \        P                  RV RV RV P                  R RV P                   R\
        P                   R\
        P                   R	\
        P                   R
24       R# )zAlpaca WS closed (code=z): zWS_CLOSE | code=z | msg=r  r  ru  r  r  r  r  N)	r   r   r   rr  rv  r   r  r  r  )r   r  close_status_code	close_msgs   &&&&r   	_on_closeAlpacaWebSocketClient._on_close  s    01B0C3ykRS01 D''**:4;M;M:N O'../ 0#,,- ."//0	4	
r   c                   ^p\        R4       V P                  '       EdK   \        '       d   \        '       g   \        P                  R4       R#  \        V R^ 4      V n        V P                  V n	        \        P                  RV P                  ^,            RV P                   24       \        P                  R\         24       \        P                  ! \        V P                  V P                   V P"                  V P$                  R7      V n        V P&                  P)                  ^^R7       V P                  \        V R	V P                  4      ,
          pV^28  d"   ^ V n        \        P                  R
V R24       MLV ;P                  ^,          un        \        P                  RV P                   RV RV P                   24        V P                  '       g   EK  \3        V\5        ^V P                  ,          R4      4      p\        P                  RV RV P                   R24       \        P                  RV RV P                   24       \6        P8                  ! V4       EK]  \        P                  R4       R#   \*         dm   p\        P-                  RT 24       \        P-                  R\/        T4      P0                   RT 2RR7       \        T R^ 4      ^,           T n         Rp?EL)Rp?ii ; i)a  Reconnect loop with smart backoff -- restarts the WebSocket if it drops.

KEY CHANGES FROM v8:
  - Minimum reconnect wait is 30s regardless of fail count.
    Previously 10s * consec_fails with consec_fails resetting on WS_OPEN
    meant every reconnect after a rate-limit drop waited only 10s, causing
    Alpaca to ban the connection immediately on re-auth. Alpaca has a
    server-side rate limit on rapid reconnects from the same account.

  - _consec_fails only resets if we received 50+ bars in the session.
    A session that connects and drops within 90 seconds without bars is
    a rate-limit bounce -- we should keep backing off, not restart at 10s.

  - ping_interval=20, ping_timeout=15: pings more often (catches network
    stalls faster) but gives a longer window for the pong reply, reducing
    spurious timeouts under heavy DB load.

  - Max wait is 5 minutes (300s) instead of 2 minutes (120s).
    This gives Alpaca enough time to lift a temporary connection ban.
z.Alpaca WS: no API keys set -- stream disabled.Nrv  zWS_CONNECT_ATTEMPT | attempt=z | bars_so_far=zAlpaca WS: connecting to )on_open
on_messageon_erroron_close)ping_intervalping_timeoutr|  z'WS_DROPPED_HEALTHY | bars_this_session=z | consec_fails reset to 0zWS_DROPPED | consec_fails=z | bars_this_session=zAlpaca WS exception: zWS_EXCEPTION | r  Tr   ra   zAlpaca WS: reconnecting in zs (consec_fails=z)...zWS_RECONNECT_WAIT | zs | consec_fails=zWS_LOOP_EXITED | _running=False)r   rn  r%   r'   r   r   r}  rv  rr  r|  r   r   ALPACA_WS_URL	websocketWebSocketAppr  r  r  r  rp  run_foreverrX   r   r  r   r  r  r   rI  )r   MIN_RECONNECT_WAITbars_this_sessionr   rK  s   &    r   _run_forever"AlpacaWebSocketClient._run_forever  s   .  "mmm!>):):OP)K%,T?A%F"(,(;(;%!!3D4F4Fq4H3I J##'#6#6"79 7GH$11!!%!%!1!1!%!% $$2B$G %)$7$7'$HZ\`\o\o:p$p!$* *+D& %%ABSAT U2 3 &&!+& ((4T5G5G4H I-->,? @''+':':&;= }}} -s28J8J3JC/PQ9$?OPTPbPbOccghi!!$8>OPTPbPbOc"de

4 ;<  K4QC89""_T!W5E5E4Fb#LW["\%,T?A%F%J""Ks!   D-J ?AJ K9A!K44K9c                   \         '       g   \        P                  R 4       R# RV n        \        P
                  ! V P                  RRR7      V n        V P                  P                  4        \        P                  R4       R# )z;Alpaca WS: websocket-client not installed, stream disabled.NTAlpacaWebSockettargetdaemonr  z Alpaca WebSocket thread started.)
_WS_AVAILABLEr   r   rn  r  Threadr  ro  startr   r4  s   &r   r  AlpacaWebSocketClient.start  s[    }NNXY!((0A0A$.?A67r   c                    R V n         V P                  '       d    V P                  P                  4        R# R#   \         d     R# i ; irm  )rn  rp  r  rX   r4  s   &r   stopAlpacaWebSocketClient.stop  s>    888    s   9 AAc                    < V ^8  d   QhRS[ /# r6   rO  )r;   r   s   "r   r<   rk    s     # #s #r   c                    V P                   # r	  )rr  r4  s   &r   bars_received#AlpacaWebSocketClient.bars_received  s    """r   )r|  rr  r{  rv  rq  r  rn  ro  rp  rh  ri  rj  N)r   r   r   r   r
  r  r  r  r  r  r  r  r  r  r  r   r   r   s   @r   rf  rf     sO     	
& 
&":B63 63p

N=^8# #r   rf  c                   ^   a  ] tR tRt o RtV 3R lR ltV 3R lR ltRV 3R lR lltR	tV t	R
# )AlphaVantageClienti  z!https://www.alphavantage.co/queryc                    < V ^8  d   QhRS[ /# r<  r9   )r;   r   s   "r   r<   AlphaVantageClient.__annotate__   s     - - -r   c                    Wn         ^ V n        \        P                  ! 4       P	                  4       V n        \        P                  ! 4       V n        R# r  N)	ry  _calls_todayr   rB   date_last_resetr  r  r  rC  s   &&r   r  AlphaVantageClient.__init__   s4    #$LLN//1%NN,
r   c                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r  &  s     = =4 =r   c                @   V P                   ;_uu_ 4        \        P                  ! 4       P                  4       pWP                  8w  d   ^ V n        Wn        \        V P                  4      ;'       d    V P
                  ^8  uuRRR4       #   + '       g   i     R# ; ir  )r  r   rB   r  r  r  r  ry  r   r^   s   & r   	_can_callAlphaVantageClient._can_call&  sc    ZZZLLN'')E((($%!$) ><<d&7&7"&< ZZZs   AB2BB	c                ,   < V ^8  d   QhRS[ RS[ RS[/# )r7   r   intervalr8   r:   rG   )r;   r   s   "r   r<   r  .  s"     " "3 "# "4 "r   c                R   V P                  4       '       g   . #  \        P                  ! V P                  R RRVRVRRRV P                  /^
R7      pVP                  4       pRV R	2pWT9  d   . # . pWE,          p\        VP                  4       4      p\        V4       F  w  p	w  r\        \        P                  ! V
R
4      P                  4       4      p\        VR,          4      pV	^,           \        V4      8  d'   \        W^,           ,          ^,          R,          4      MTpVP                  WV\        VR,          4      \        VR,          4      \        VR,          4      V\        VR,          4      R3	4       K  	  V P                   ;_uu_ 4        V ;P"                  ^,          un        RRR4       \$        P'                  RV R\        V4       RV R	24       V#   + '       g   i     L:; i  \(         d(   p\$        P+                  RT RT 24       . u Rp?# Rp?ii ; i)functionTIME_SERIES_INTRADAYr   r  
outputsizecompactapikeyr  r   zTime Series (r  r   z4. closez1. openz2. highz3. lowz	5. volumealphavantageNz  AlphaVantage:  z bars (zAlphaVantage error r  )r  requestsr@  BASEry  r~  rG   r   	enumerater   r   strptimer  r  r   rS   r  r  r   r   rX   r   )r   r   r  r  ru   ry  r
  ts_dataprices_listr  dt_strbarr   r  r  r   s   &&&             r   get_intradayAlphaVantageClient.get_intraday.  s   ~~I	TYY4fhidhh0 A 668D"8*A.C	DiGw}}/K$-k$: =FH--f6IJTTVWc*o.BCA#KHXBXkA#.q1*=>^c#i.)5Y+@#h-(4#k*+^	 	 %; !!Q&! KK*6(!CI;ghZqQRK   	LL.vhb<=I	s=   AG4 /D&G4 G!/1G4 !G1	,G4 4H&?H!H&!H&)r  r  r  ry  N)5min)
r   r   r   r   r  r  r  r  r   r   r   s   @r   r  r    s-     .D- -= =" " "r   r  c                   T   a  ] tR tRt o RtV 3R lR ltR tR tV 3R lR ltR	t	V t
R
# )PolygonClientiS  z%https://api.polygon.io/v2/aggs/tickerc                    < V ^8  d   QhRS[ /# r<  r9   )r;   r   s   "r   r<   PolygonClient.__annotate__V  s     . . .r   c                    Wn         \        4       V n        \        P                  ! 4       P                  4       V n        \        4       V n        \        P                  ! 4       V n        R # r	  )ry  set_fetched_todayr   rB   r  r  r   rB  r  r  r  rC  s   &&r   r  PolygonClient.__init__V  s?    $#&5%\\^002"W&^^-
r   c                P    V P                   ;_uu_ 4        \        P                  ! 4       pV P                  '       d;   WP                  ^ ,          ,
          R8  d   V P                  P                  4        KL  \	        V P                  4      ^8  d:   V P                  P                  \        P                  ! 4       4        RRR4       R# RWP                  ^ ,          ,
          ,
          pRRR4       X^ 8  g   K  \        P                  ! V4       EK    + '       g   i     L2; irF  )r  r   rB  rG  r   rS   rI  rJ  s   &  r   rL  PolygonClient._throttle]  s    iikkkkcKKN&:T&AKK'')t{{#a'KK&&tyy{3  s[[^34  ax

4  s   'DBD DD%	c                   \         P                  ! 4       P                  4       pV P                  ;_uu_ 4        WP                  8w  d!   V P
                  P                  4        Wn        R R R 4       R #   + '       g   i     R # ; ir	  )r   rB   r  r  r  r  clearr  s   & r   _reset_if_new_dayPolygonClient._reset_if_new_dayj  sO    ##%ZZZ(((##))+#(  ZZZs   1A33B	c                &   < V ^8  d   QhRS[ RS[/# r  r  )r;   r   s   "r   r<   r  q  s     # #s #t #r   c                z   V P                  4        V P                  '       d   WP                  9   d   . # V P                  4         \        P
                  ! \        4      P                  4       pV\        ^R7      ,
          pVP                  4       ^8  d)   V\        VP                  4       ^,
          R7      ,          pVP                  R4      pV P                   RV RV RV 2p\        P                  ! VRRRRR	R
RV P                  /^R7      pVP                  4       pVP                  R4      R9  g   RV9  d   . # . pVR,          p	\        V	4       F  w  r\!        VR,          R,          4      p\#        VR,          4      pV
^ 8  d    \#        W^,
          ,          R,          4      MTpVP%                  WV\#        VR,          4      \#        VR,          4      \#        VR,          4      V\#        VP                  R^ 4      4      R3	4       K  	  V P&                  ;_uu_ 4        V P                  P)                  V4       RRR4       \*        P-                  RV R\/        V4       RV 24       V#   + '       g   i     L9; i  \0         d(   p\*        P3                  RT RT 24       . u Rp?# Rp?ii ; i)   rI   %Y-%m-%d/z/range/1/minute/adjustedtruesortascr.  r   apiKeyr  r  resultsrR  r   r[  r  r  r  r  polygonNz  Polygon: r  z
 bars for zPolygon error r  )OKDELAYED)r  ry  r  rL  r   rB   r  r  r   r  rC   r  r  r@  r~  r  r   r  rS   r  addr   r   r   rX   r   )r   r   r^   r  r\   urlr  ru   r
  r  r  r  r   r  prev_cr   s   &&              r   get_prev_day_minute_bars&PolygonClient.get_prev_day_minute_barsq  s5    xxx6%8%88I	||I.335Eya00D||~"	t||~'9::}}Z0HYYKq(8
!H:NC,,sJ,3S(DHH,NWY[A668Dxx!)::it>S	D9oG#G,SX_-s3x56Uws|C01#c(OU3s8_#c(OV#''#q/*I	 	 - ##''/ KK+fXQs4ykH:NOK   	LL>&A378I	s>   C9J  C(J (I50J 5J	 J J:J5/J:5J:)r  r  r  rB  ry  N)r   r   r   r   r  r  rL  r  r!  r   r   r   s   @r   r  r  S  s(     2D. .!)# #r   r  ret_1ret_3ret_5ret_10ret_20rsirsi_diffmacdmacd_sig	macd_hist
macd_crossbb_pct_b	bb_bwidthvs_sma_5	vs_sma_10	vs_sma_20	vs_sma_50	vol_ratiovol5vol10vol20hl_range
body_ratiogap_openret_skew
autocorr_1	vol_trendprice_accelprice_velocityadxadx_posobv_norm	vwap_distatr_pctstoch_kstoch_dmfinews_sentiment
news_countsec_flagreddit_mentionsreddit_sentimentcongress_boughtstocktwits_bullishstocktwits_mentionsslope_8slope_20trend_cons_8trend_cons_20momentum_ageslope_accelyang_zhang_volvol_imbalancecorwin_schultzsentiment_decayatr_zc                T    V ^8  d   QhR\         P                  R\        R\        RR/# )r7   r  velocity_mapsentiment_scoresr8   pd.DataFrame | None)r  r  r6  )r;   s   "r   r<   r<     s4     K' K'r|| K'4 K'%)K'5JK'r   c           	     +   \        V 4      ^78  d   R# \        P                  ! V P                  R7      pV R,          P	                  \
        4      pV R,          P                  V4      P	                  \
        4      pV R,          P                  V4      P	                  \
        4      pV R,          P                  V4      P	                  \
        4      pV R,          P                  ^ 4      P	                  \
        4      pR\ F  w  rVP                  V	4      W:&   K  	  VP                  4       pVP                  ^ R	7      P                  ^^R
7      P                  4       pVP                  ^ R7      ) P                  ^^R
7      P                  4       p^d^d^WR,           ,          ,           ,          ,
          VR&   VR,          P                  4       VR&   VP                  ^RR7      P                  4       pVP                  ^RR7      P                  4       pW,
          pVP                  ^	RR7      P                  4       pVVR&   VVR&   VV,
          VR&   VV8  P	                  \        4      VR&   VP                  ^4      P                  4       pVP                  ^4      P                  4       pVV^V,          ,
          ,
          ^V,          R,           ,          VR&   ^V,          VR,           ,          VR&   R] F?  pVP                  V4      P                  4       pVV,
          VR,           ,          VRV 2&   KA  	  VP                  ^4      P                  4       pVVR,           ,          VR&   VP                  4       pR^ F'  w  pp
VP                  V4      P                  4       W:&   K)  	  WV,
          VR,           ,          VR&   WG,
          P                  4       WV,
          R,           ,          VR&   WtP!                  ^4      ,
          VP!                  ^4      R,           ,          VR&   VP                  ^4      P#                  4       VR&   VP                  ^4      P%                  R RR7      VR&   VP                  ^4      P                  4       pVP                  ^4      P                  4       pVVR,           ,          VR &   VP                  4       P                  ^4      P                  4       VR!&   R"V P&                  9   dg   V R",          P	                  \
        4      pVP                  4       P)                  ^ ^<4      P                  ^<4      pVP                  4       V,          VR#&   MVP                  4       R$,          VR#&   \*        '       EdM    \,        P.                  P1                  WVV^R%R&7      pVP3                  4       VR'&   VP5                  4       VR(&    \,        P8                  P;                  WHR%R*7      P=                  4       pVVP                  ^4      P                  4       ,
          VP                  ^4      P                  4       P)                  ^ ^4      ,          VR+&    WV,           V,           ^,          pVV,          P                  ^4      P?                  4       VP                  ^4      P?                  4       P)                  ^ \@        PB                  4      ,          pVV,
          VR-,           ,          VR.&    \,        PD                  PG                  WVV^R%R&7      PI                  4       p V VR-,           ,          VR/&    \,        PJ                  PM                  WVV^^R%R17      p!V!PO                  4       R2,          VR3&   V!PQ                  4       R2,          VR4&    \,        P8                  PS                  WVWH^R%R67      PU                  4       R2,          VR7&   EMVP                  4       p"V"P                  ^4      P                  4       ^d,          P                  ^ ^d4      VR'&   R)VR(&   \@        PV                  ! VP                  4       4      V,          PY                  4       p#V#V#P                  ^4      P                  4       ,
          V#P                  ^4      P                  4       ^,           ,          VR+&   WDP                  ^4      P                  4       ,
          VP                  ^4      P                  4       R-,           ,          VR.&   WV,
          VR-,           ,          P                  ^4      P                  4       VR/&   VP                  ^4      P[                  4       VP                  ^4      P]                  4       p%p$VV$,
          V%V$,
          R-,           ,          P                  ^4      P                  4       VR3&   VR3,          P                  ^4      P                  4       VR4&   R5VR7&   T;'       g    / p&\        V4      p'\        V&P_                  R8R,4      4      VR8&   \        V&P_                  R9^ 4      4      VR9&   \        V&P_                  R:^ 4      4      VR:&   \        V&P_                  R;^ 4      4      VR;&   \        V&P_                  R<R,4      4      VR<&   \        V&P_                  R=^ 4      4      VR=&   \        V&P_                  R>R54      4      VR>&   \        V&P_                  R?^ 4      4      VR?&   R_ F  w  p(p)V(VP&                  9  g   K  V)VV(&   K   	  VP                  4       P!                  R`4      VR@&   VR@,          ^ 8  P	                  \        4      VRA&   \        V4      ^8  Ed   VR,          PY                  4       p*VR,          P                  R,4      p+RB p,V,! V+^4      P                  R,4      VRC&   V,! V+^4      P                  R,4      VRD&   V+^ 8  P	                  \
        4      p-V+^ 8  P	                  \
        4      p.\@        P`                  ! VRC,          ^ 8  V-P                  ^4      P                  4       V.P                  ^4      P                  4       4      P                  ^ ^4      VRE&   \@        P`                  ! VRD,          ^ 8  V-P                  ^4      P                  4       V.P                  ^4      P                  4       4      P                  ^ ^4      VRF&   VRE,          P                  R54      VRE&   VRF,          P                  R54      VRF&   V*P                  ^RR7      P                  4       p/V*V/8  P	                  \        4      p0\@        Pb                  ! \        V4      4      ^ p2p1\e        \        V04      4       FF  p3V0Pf                  V3,          ^8X  d   \]        ^ V24      ^,           M\[        ^ V24      ^,
          p2V2V1V3&   KH  	  V1RG,          VRH&   VRC,          VRD,          P)                  ^ \@        PB                  4      ,          P                  Ra^4      P                  R,4      VRI&   MRb F  p4R,VV4&   K
  	   ^p5VP%                  \@        Ph                  4      p6VP%                  \@        Ph                  4      p7VP%                  \@        Ph                  4      p8VP%                  \@        Ph                  4      p9V7P!                  ^4      p:RJRKV5^,           V5^,
          ,          ,           ,          p;V6V:,
          P                  V54      Pk                  4       p<V7V6,
          P                  V54      Pk                  4       p=V8V6,
          V8V7,
          ,          V9V6,
          V9V7,
          ,          ,           P                  V54      P                  4       p>\@        Pl                  ! V<V;V=,          ,           ^V;,
          V>,          ,           P                  ^ R	7      4      VRL&    WV,           V,           ^,          p?V?V,          P                  ^4      P?                  4       VP                  ^4      P?                  4       P)                  ^ \@        PB                  4      ,          p@WV,
          P                  ^4      P                  4       P)                  ^ \@        PB                  4      pAVV@,
          VAR-,           ,          P                  Ra^4      VRM&    VP%                  \@        Ph                  4      pBVP%                  \@        Ph                  4      pCVBVC,
          ^,          VBP!                  ^4      VCP!                  ^4      ,
          ^,          ,           pD\@        Pp                  ! VBVBP!                  ^4      4      \@        Pr                  ! VCVCP!                  ^4      4      ,
          ^,          pERcpFRdVDR5,          ,          VF,          VEVF,          R5,          ,
          pG^\@        Pt                  ! VGP                  ^4      P                  4       4      ^,
          ,          ^\@        Pt                  ! VGP                  ^4      P                  4       4      ,           ,          pHVHP                  ^ RP4      P                  RQ4      VRR&    \        V&P_                  R8R,4      4      RS,          \        V&P_                  R<R,4      4      RT,          ,           \        V&P_                  R>R54      4      R5,
          RN,          RU,          ,           \        V&P_                  R:R,4      4      RN,          ,           \        V&P_                  R=R,4      4      RO,          ,           RV,          pI\        V&P_                  RW\v        Pv                  ! 4       RX,
          4      4      pJ\v        Pv                  ! 4       VJ,
          R$,          pK^VK) RY,          ,          pL\        VIVL,          4      VRZ&    R/VP&                  9   d
   VR/,          MWV,
          VR-,           ,          pMVMP                  ^4      P                  4       pNVMP                  ^4      P                  4       P)                  ^ ^4      pOVMVN,
          VO,          P                  Ra^4      VR[&   VP)                  \@        Px                  \@        Px                  ) .\@        PB                  4      P{                  4       p\        V4      ^8  d   V# R#   \6         d    R)TR'&   R)TR(&    ELi ; i  \6         d
    R,TR+&    ELi ; i  \6         d
    R,TR.&    ELi ; i  \6         d
    R0TR/&    ELi ; i  \6         d    R5TR3&   R5TR4&    ELi ; i  \6         d
    R5TR7&    ELpi ; i  \6         d:    TP_                  R/\        Pn                  ! R0TP                  R7      4      TRL&    ELi ; i  \6         d
    R,TRM&    ELi ; i  \6         d
    RQTRR&    ELZi ; i  \6         d
    R,TRZ&    ELi ; i  \6         d
    R,TR[&    ELi ; i)eu  
Builds the full feature matrix for a single symbol.
Accepts optional sentiment_scores dict from SentimentEngine.get_scores().
All sentiment features default to 0 if no scores are available yet —
the model will treat the stock as neutral until data arrives.
Nindexr  r  r   r.  r  r#  )lower)commin_periods)upper绽|=r(  r)  F)spanadjustr*  r+  r,  r-  r.  r/  vs_sma_r4  r8  r9  r:  r;  c                 J    \        V 4      ^8  d   V P                  ^R7      # R# )r7   )lagr   )r   autocorrxs   &r   <lambda> build_features.<locals>.<lambda>  s!    s1vz!***#:s:r   )rawr<  r=  r>  r   r?  r  T)r  r   r  windowfillnar@  rA  g      9@)r  r  rs  rB  r   g:0yE>rC  rD  {Gz?)r  r   r  rr  smooth_windowrs        Y@rE  rF  r2   )r  r   r  r  rr  rs  rG  rH  rI  rJ  rK  rL  rM  rN  rO  
target_ret
target_dirc                    \         P                  ! V\         P                  R 7      p\         P                  ! \	        V 4      \         P
                  4      p\        V^,
          \	        V 4      4       FN  p\         P                  ! W P                  WA,
          ^,           V^,            P                  ^4      ^ ,          W4&   KP  	  \        P                  ! W0P                  R7      # )dtyper`  )r  arangefloat32fullr   nanr  polyfitilocvaluesr  Seriesra  )sr  _x_o_js   &&   r   _slopebuild_features.<locals>._slopen  s    1BJJ/BQ(BAE3q6*BrtAvbd(;(B(BAFqI +99Rww//r   rP  rQ  rR  rS        4@rT  rU  g(\?gq=
ףp?rV  rW  rg   rh   r0   gMb`?rX  rf   r4   333333?      @last_update_tsrb         >@rY  rZ  ))r  r#  )   r$  )r  r%  )r   r&  )   r'  )r  r   r  2   ))r  r5  )r   r6  )r  r7  ))r@        ?)rA  r  )rB  r   )rC  r   )rD  rt  )rE  r2   )rF  r2   )rG  r2   )rP  rQ  rR  rS  rT  rU  g0C?g4y?)>r   r  r  ra  astyper  rs  
pct_changediffr  ewmmeanr   rollingstdabsshiftskewapplycolumnsrR   TA_OKtatrendADXIndicatorr@  rA  rX   r  OnBalanceVolumeIndicatoron_balance_volumerT  r  r  
volatilityAverageTrueRangeaverage_true_rangemomentumStochasticOscillatorstochstoch_signalMFIIndicatormoney_flow_indexsigncumsumr  r  r@  wherezerosr  r  logvarsqrtr  maximumminimumexpr   infdropna)Pr  r\  r]  r   r[  r  r  opvodr  deltaagale12e26r*  sigsma20std20r  smavmar1	vol_shortvol_longts_sr  adx_indobvtpvwapatrr  ret_sobv_slo14hi14r  n_rows_col_defr   _retr  _up_dn_ema8_above_age_cntr  _sf_Nr  _c2_h_l_cprev_k_ov_cv_rs_tp_vwap_atr14_lnh_lnl_beta_gamma_k_cs_alpha_spread_raw_last_ts_age_min_decay_atr_s_mu_sdsP   &&&                                                                             r   build_featuresr    s    2w|	BHH	%A	G		E	"A	F		1		$	$U	+B	E		!		#	#E	*B	F		1		$	$U	+B	H		Q		&	&u	-BQ||A R FFHE	!		 	 RR	 	8	=	=	?B::A:
	#	#	#	;	@	@	BB#R:%6!677AeHeHMMOAjM55b5',,.C55b5',,.C9D8858)..0CAfIAjMSjAkNcz))#.AlOIIbM EIIbME51U7?+%%@AjMg%%-0AkNiil!Ge4GA3-  **R.


C3;'AkN	
B61zz!}  " 7 w1u9-AjMvlln%8AlOGGAJ1771:+=>AjMzz"~**,AjMzz"~++: , AlO zz!}((*Izz"~))+H Hu$45AkNwwy((+002Am rzzD'$$Q+2226ffhm
ffho

 u	?xx,,"A57 - FG";;=AeH"??,AiL	.yy994 : 11B1B1D  3;;r?#7#7#99 [[_002::1a@BAjM	/GaK1$BG$$R(,,.B1C1C1E1M1MaQSQWQW1XXD$h4$;7AkN	.--00qD 1   "  !d(+AiL	A{{77q1T 8 SE ;;=50AiL --/%7AiL	)yy--qBt .  5)AeH r*..036<<QD%)*R/779r!2!7!7!99emmB>O>S>S>UXY>YZ*YYr]//11aiim6H6H6JT6QR+'a$h/88<AAC)

2**,bjjn.@.@.Bdd(td{T'9:CCAFKKM)),,Q/446)% 	BAVF "!%%(8C"@AA!!%%A">?AlO!!%%
A">?AjM$QUU+<!%DEA$QUU+=#%FGA$QUU+<!%DEA$QUU+?#%FGA$QUU+@!%DEAF
d qyy AdG	F lln**2.AlO*2237AlO 1v|z  "z  %	0 tQ..s3)tR(//4*ax&ax&XXa	lq&8KKN!CKKN$7$7$9;;?41: 	
.XXa
mq&8KKO  "CKKO$8$8$:<<@DAJ 	
/~.55c:./66s;/Qu-224u*$$S)XXc!f%qdF$B)/RA)=C4L1$C4LSTDTDDH % !4K.iL1Z=00BFF;;
$r1+ffSk 	
-BCAcFBO   1Q26223f%%b)--/r""2&**,r'b3h'27rCx*@@II"MRRT ggsR#X~R3'F&L&LST&L&UV
!'A+"(##B'++-

20B0B0D0L0LQPRPVPV0WW7##B',,.77266B 5yVd];AA"aH/
$xxxx+!TZZ]TZZ]%BQ$FF**T4::a=1BJJtTZZPQ]4SSVWW,u47LLrvvfnnQ/4467!;<BFF6>>Z[K\KaKaKcDd@de%ll1d3::5A
#!%%(C01C7!%%*C01C78155-s34s:cACGH !%%
C01C78 !%%)C01C7	8
  !%% 0$))+2DEFYY[8+t38)d*+$TF]3
!*aii!79bg!d(=S#((*#'')11!Q7|s*00Q7'
 	
		266BFF7#RVV,335AA"1&$&s >T!E($1Y<> -#!J--
 .3!K.. -!I,- @!I,Sa	l@
 (S!E((@  OeeIryyQWW/MN
O  ! /!  $#
$&  #"
#  '
s  
A	AS BAS !BAS6 :AAT ?AAT$ ;AU  :FAU C+AV CF+AV5 I/EAW OB!AW# SASSASSAS3S2AS3S6AT
T	AT
TAT!T AT!T$AT=T<AT=U AUUAUUA AVVAVVAV2V1AV2V5AW	WAW	WAW WAW W#AW7W6AW7c                   |   a  ] tR tRt o Rt]3V 3R lR lltR tRV 3R lR lltV 3R lR	 lt	V 3R
 lR lt
RtV tR# )SentimentDatabasei  ue  
Lightweight SQLite store for sentiment scores.
Separate from the price DB so sentiment writes never block trading writes.
Schema:
  sentiment(symbol, source, score, count, flag, ts, raw_text)
    symbol  — ticker e.g. "AAPL"
    source  — "news" | "sec" | "reddit" | "congress"
    score   — float [-1, 1] composite sentiment
    count   — int   number of items contributing to this score
    flag    — int   special signal flag (e.g. 1=negative 8-K, 2=positive)
    ts      — int   unix timestamp of when this score was computed
    raw_text— text  most recent headline/title for debug inspection
c                    < V ^8  d   QhRS[ /# )r7   db_pathr9   )r;   r   s   "r   r<   SentimentDatabase.__annotate__  s       r   c                    Wn         \        P                  ! 4       V n        \        P
                  ! V P                   R R7      V n        V P                  P                  R4       V P                  4        R# )Fr  r  N)	rU   r  r  r  r   r   r  r   _init_db)r   r  s   &&r   r  SentimentDatabase.__init__  sI    	^^%
 __TYY%H


45r   c                    \         P                  ! V P                  4      ;_uu_ 4       pVP                  R 4       VP                  R4       VP	                  4        RRR4       R#   + '       g   i     R# ; i)a  
                CREATE TABLE IF NOT EXISTS sentiment (
                    symbol   TEXT NOT NULL,
                    source   TEXT NOT NULL,
                    score    REAL DEFAULT 0.0,
                    count    INTEGER DEFAULT 0,
                    flag     INTEGER DEFAULT 0,
                    ts       INTEGER NOT NULL,
                    raw_text TEXT DEFAULT '',
                    PRIMARY KEY (symbol, source)
                )
            z7CREATE INDEX IF NOT EXISTS idx_sym ON sentiment(symbol)N)r   r   rU   r   r  r  s   & r   r  SentimentDatabase._init_db  sO    __TYY''4LL   LLRSKKM ('''s   3A&&A7	c                >   < V ^8  d   QhRS[ RS[ RS[RS[RS[RS[ /# )r7   r   r  scorecountflagraw_text)r:   r  r   )r;   r   s   "r   r<   r     s:      S # e !$03r   c                   \        \        P                  ! 4       4      pV P                  ;_uu_ 4        \        P                  ! V P
                  4      ;_uu_ 4       pVP                  RW\        V^4      WEWvR,          34       VP                  4        RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i)z=Insert or update a sentiment record for a symbol+source pair.a  
                    INSERT INTO sentiment(symbol,source,score,count,flag,ts,raw_text)
                    VALUES(?,?,?,?,?,?,?)
                    ON CONFLICT(symbol,source) DO UPDATE SET
                        score=excluded.score, count=excluded.count,
                        flag=excluded.flag,  ts=excluded.ts,
                        raw_text=excluded.raw_text
                Ni  NN)	r   r   r  r   r   rU   r   r  r  )	r   r   r  r  r  r	  r
  r   r  s	   &&&&&&&  r   upsertSentimentDatabase.upsert  s     ZZZ++t  eE!ne2PT~VX  , Z++ ZZs#   )B98B&	B9&B61B99C
	c                &   < V ^8  d   QhRS[ RS[/# r  r:   r6  )r;   r   s   "r   r<   r   /  s     + +# +$ +r   c                R   V P                   ;_uu_ 4         V P                  P                  RV34      P                  4       pRRR4       RRR^ R	^ R
^ RRR^ RRR^ /pX FS  w  rErgVR8X  d   WSR&   WcR&   K  VR8X  d   WsR	&   K$  VR8X  d   WcR
&   WSR&   K5  VR8X  d   WsR&   KB  VR8X  g   KK  WSR&   WcR&   KU  	  V#   \        P
                   dH    \        P                  ! T P                  RR7      T n        T P                  P                  R4       . p Li ; i  + '       g   i     L; i)z
Returns a dict of all sentiment scores for a symbol.
Keys: news_sentiment, news_count, sec_flag, reddit_mentions,
      reddit_sentiment, congress_bought
Returns zeros/defaults if no data exists yet.
z<SELECT source,score,count,flag FROM sentiment WHERE symbol=?Fr  r  NrH  r   rI  rJ  rK  rL  rM  rN  r2   rO  newssecredditcongress
stocktwitsr  r  r   r"  r   OperationalErrorr   rU   )r   r   r
  resultr  r  r  r	  s   &&      r   r@  SentimentDatabase.get/  sB    ZZZ	zz))RI (*   311131 3!1	
 +/&F5+0'(+0|$5+/z"8#-2()-2)*:%-1()<'05+,05,- +/ = ++ $__TYY%P


""#<=	 Zs)   D+B77ADDDDD&	c                    < V ^8  d   QhRS[ /# r6   rF   )r;   r   s   "r   r<   r   \  s     
 
 
r   c                   V P                   ;_uu_ 4         V P                  P                  R 4      P                  4       pV Uu. uF  q"^ ,          NK  	  upuuRRR4       # u upi   \        P
                   dR    \        P                  ! T P                  RR7      T n        T P                  P                  R4       . u uuRRR4       # i ; i  + '       g   i     R# ; i)z%SELECT DISTINCT symbol FROM sentimentNFr  r  r  )r   r
  r  s   &  r   get_all_symbols!SentimentDatabase.get_all_symbols\  s    ZZZzz));(*  '++d!d+ Z
 ,++ $__TYY%P


""#<=	 Z ZZs;   C-A'A"A'"A''AC CCCC!	)r  r  rU   Nr,   )r   r   r   r   r
  r   r  r  r  r@  r  r   r   r   s   @r   r  r    s=      '8  "  + +Z
 
r   r  c                      a  ] tR tRt o RtV 3R lR ltR tR tR tV 3R lR	 lt	R
 t
V 3R lR ltR tR tR tR tR tV 3R lR ltV 3R lR ltRtV tR# )SentimentEngineii  a  
Orchestrates all four sentiment data pipelines.
Each pipeline runs in its own background daemon thread so they never
block the main trading loop. Results are written to SentimentDatabase
and read by build_features() when constructing feature vectors.

Usage:
    engine = SentimentEngine(symbols=["AAPL","MSFT",...])
    engine.start()   # launches all background threads
    # Later, from feature builder:
    scores = engine.db.get("AAPL")
c                    < V ^8  d   QhRS[ /# )r7   symbolsrF   )r;   r   s   "r   r<   SentimentEngine.__annotate__w  s     R R Rr   c           
        Wn         \        4       V n        R V n        \        '       d   \        4       MRV n        / V n        RV n        RV n	        RV n
        / V n        \        P                  R\         R\         R\        V4       24       R# )FNr   zSENTIMENT_ENGINE_INIT | vader=z | feedparser= | symbols=)r#  r  rh  rn  VADER_OKr   _vader
_last_news	_last_sec_last_reddit_last_congress_last_stocktwitsr   r   FEEDPARSER_OKr   )r   r#  s   &&r   r  SentimentEngine.__init__w  s    )+8@24d!"!$!$!#:8* E((5k#g,Q 	Rr   c                   RV n         \        P                  ! V P                  RRR7      P	                  4        \        P                  ! V P
                  RRR7      P	                  4        \        '       d?   \        '       d3   \        P                  ! V P                  RRR7      P	                  4        M\        P                  R4       \        P                  ! V P                  RRR7      P	                  4        \        P                  ! V P                  RRR7      P	                  4        \        P                  R	\        '       d   R
MR R\        '       d   R
MR R\        '       d   RMR 24       R# )z&Launch all sentiment pipeline threads.TSentNewsr  SentSEC
SentRedditz.SENTIMENT_REDDIT_DISABLED | no credentials setSentCongressSentStockTwitsu"   Sentiment engine started — news=ONzOFF(no feedparser)z | sec=ON | reddit=zOFF(no key)z | congress=ON | stocktwits=ONz(auth)r,   N)rn  r  r  
_news_loopr  	_sec_loopri   rj   _reddit_loopr   r   _congress_loop_stocktwits_loopr   r.  rk   r4  s   &r   r  SentimentEngine.start  s    	D(	**/%' 	D'	)).  4 4D$5$5d".005NO 	 3 3D,	..3eg 	 5 5d.	005 $1MD7KL M&6&6dMJ K$0@0@Hb#IK 	Lr   c                    R V n         R# rm  )rn  r4  s   &r   r  SentimentEngine.stop  s	    r   c                D   ^ pV P                   '       d    V P                  V\        V P                  4      ,          ,          pV^,          pV P                  P	                  V^ 4      p\
        P
                  ! 4       V,
          \        8  d4   V P                  V4       \
        P
                  ! 4       V P                  V&   \
        P                  ! R4       K  R#   \         d;   p\        P                  RT 24       \
        P                  ! ^4        Rp?EK  Rp?ii ; i)z7Cycles through all symbols, fetching news RSS for each.rg   zSENTIMENT_NEWS_LOOP_ERR | N)rn  r#  r   r)  r@  r   SENTIMENT_NEWS_INTERVAL_fetch_newsrI  rX   r   r   r   idxr  lastr   s   &    r   r7  SentimentEngine._news_loop  s    mmmll3T\\):#:;q**3299;%(??$$S)+/99;DOOC(

3   ""%?s#CD

2   C C D%.DDc                    < V ^8  d   QhRS[ /# rY  r9   )r;   r   s   "r   r<   r$    s     7D 7D# 7Dr   c                V   \         '       d   \        '       g   R#  \        P                  VR7      p\        P
                  ! V4      pVP                  '       g   R# . p. pRp\        P                  ! 4       pVP                  R,           F  pVP                  RR4      p	VP                  R4      p
V
'       dB   \        P                  ! V
4      pW{,
          R,          p\        R^V) R	,          ,          4      pMR
pV P                  P                  V	4      pVP                  VR,          4       VP                  V4       V'       d   K  V	R,          pK  	  \        V4      \        8  d   \!        V4      p\!        R \#        WE4       4       4      V,          pV P$                  P'                  VRV\        V4      ^ VR7       \(        P+                  RV RVR R\        V4       RVR,           24       R# R#   \,         d'   p\(        P/                  RT RT 24        Rp?R# Rp?ii ; i)az  
Fetches Google News RSS for a single symbol and scores it.
Steps:
  1. Request RSS feed for "{symbol} stock"
  2. Parse up to 20 recent entries (feedparser handles XML)
  3. Score each headline with VADER -> compound score [-1, 1]
  4. Apply time decay: articles > 12h old weighted at 50%
  5. Weighted average -> single score for the symbol
  6. Upsert into SentimentDatabase
Nra  r,   Nr  Ntitlepublished_parsedg      @r1   g      (@r2   r   :Nx   Nc              3   6   "   T F  w  rW,          x  K  	  R # 5ir	  r   )r   r  r  s   &  r   r   .SentimentEngine._fetch_news.<locals>.<genexpr>  s      H3G413G   r  r  r  r	  r
  zSENT_NEWS | z	 | score=r>  z | articles=z | top=N<   NzSENT_NEWS_ERR | r   )r.  r'  GOOGLE_NEWS_RSSr;   
feedparserparseentriesr   r@  mktimer  r(  r   rS   r   SENTIMENT_MIN_ARTICLESrT  ziprh  r  r   r   rX   r   )r   r   r  feedscoresweightslatestnow_tsr;  rJ  	publishedpub_tsage_hweightvstotal_w	wgt_scorer   s   &&                r   rA  SentimentEngine._fetch_news  s    }HH*	D")))8C##C(D<<<FGFyy{Fc**		'2.!II&89	![[3F$o7E aUFTM&:;F F[[007bn-v&v"4[F! +$ 6{44 \  H3v3G HH7R	vv%.%([$%(.	  0
 """6()Ic? C  #F}GF3K=B 5  	D  #3F83qc!BCC	Ds%   =G7 C(G7 	B*G7 7H(H##H(c                V   V P                   '       d    \        P                  ! 4       V P                  ,
          \        8  d   \        P                  ! 4       V n        \	        ^ \        V P                  4      ^
4       FH  pV P                  W^
,            pV F*  pV P                  V4       \        P                  ! R4       K,  	  KJ  	  \        P                  ! ^<4       K  R#   \         d;   p\        P                  RT 24       \        P                  ! ^x4        Rp?EK"  Rp?ii ; i)z8Polls SEC EDGAR full-text search for recent 8-K filings.rf   zSENTIMENT_SEC_LOOP_ERR | N)rn  r   r*  SENTIMENT_SEC_INTERVALr  r   r#  
_fetch_secrI  rX   r   r   )r   r  batchr  r   s   &    r   r8  SentimentEngine._sec_loop  s    mmm 99;/2HH%)YY[DN"1c$,,&7< $Qt 4#(C OOC0 JJsO $) =
 

2    ""%>qc#BC

3 s   CC# #D(..D##D(c                    < V ^8  d   QhRS[ /# rY  r9   )r;   r   s   "r   r<   r$  !  s     <C <C <Cr   c                     ^ RI H pHp VP                  ! 4       pWC! ^0R7      ,
          P                  R4      pVP                  R4      pRV RV RV R2p\        P
                  ! V^
RR	/R
7      pVP                  ^8w  d   R# VP                  4       p	V	P                  R/ 4      P                  R. 4      p
V
'       g$   V P                  P                  VRR^ ^ RR7       R# V
^ ,          P                  R/ 4      p\        V4      P                  4       p^ p\        V4      R,          p\         F  pW9   g   K  ^p M	  V^ 8X  d   \         F  pW9   g   K  Rp M	  V P                  P                  VRR\        V
4      WR7       V^ 8w  d?   V^8X  d   RMRp\        P!                  RV RV R\        V
4       RVR,           24       R# R#   \"         d'   p\        P%                  RT RT 24        Rp?R# Rp?ii ; i)a  
Queries SEC EDGAR full-text search for recent 8-K filings.
The EDGAR full-text search API allows searching all filings by
company name or ticker. We look for 8-K forms in the last 48h.
Steps:
  1. Build EDGAR search URL for the symbol, last 48h, form=8-K
  2. Parse JSON response for filing titles and dates
  3. Keyword match title against positive/negative word lists
  4. Assign sec_flag: 1=negative, -1=positive, 0=neutral/none
  5. Upsert into SentimentDatabase
r   )hoursr  z.https://efts.sec.gov/LATEST/search-index?q=%22z'%22&forms=8-K&dateRange=custom&startdt=z&enddt=z;&hits.hits._source=period_of_report,file_date,display_names
User-Agentz!StockTradingBot admin@example.comr   headersNhitsr  r   r,   rP  _sourceN   NNEGATIVEPOSITIVEzSENT_SEC | r   z 8-K | filings=:NP   NzSENT_SEC_ERR | r  )r   r   utcnowrC   r  r@  status_coder~  rh  r  r:   rb  SEC_NEGATIVE_KEYWORDSSEC_POSITIVE_KEYWORDSr   r   r   rX   r   )r   r   r   r   rB   	start_strend_strr  respru   rr  
latest_srcfiling_titler	  rq  kwpolarityr   s   &&                r   ri  SentimentEngine._fetch_sec!  s   0	C4 )Cyr22<<ZHIZ0G"8 $009{''PRC <<R)57Z([]D3&IIKDHHVR(,,VR8DvuCq$%  4 q'++i4Jz?002LDz?40C ,%D ,
 qy/B)! 0
 GGNN653t9 $  4qy)-:
!!!&XJ 7"4ykSXJ8   	C  ?6(#aS!ABB	Cs8   B G 9G >!G !AG 8G A2G G=G88G=c                   V P                   '       ds    \        P                  ! 4       V P                  ,
          \        8  d+   \        P                  ! 4       V n        V P	                  4        \        P
                  ! ^<4       K  R#   \         d:   p\        P                  RT 24       \        P
                  ! ^x4        Rp?K  Rp?ii ; i)z0Scans configured subreddits for ticker mentions.zSENTIMENT_REDDIT_LOOP_ERR | N)	rn  r   r+  SENTIMENT_REDDIT_INTERVAL_fetch_reddit_mentionsrI  rX   r   r   r   r   s   & r   r9  SentimentEngine._reddit_loopo  s    mmm 99;!2!225NN(,		D%//1

2    ""%A!#EF

3    A/B C.CCc           
     .   \         '       g   R# \        V P                  4      p\        \        4      p\        \
        4      p\        P                  ! 4       pV\        ,
          pR\        /p\         EFf  p RV R2p\        P                  ! W^
R7      p	V	P                  ^8w  d   K6  V	P                  4       P                  R/ 4      P                  R. 4      p
V
 F  pVP                  R/ 4      p\        VP                  R^ 4      4      pW8  d   K8  VP                  R	R
4      pRVP                  4       ,           R,           pV Fv  pRV R2V9   g   RV 2VP                  RR4      9   g   K*  VV;;,          ^,          uu&   V P                   P#                  V4      pVV;;,          VR,          ,          uu&   Kx  	  K  	  \        P$                  ! R4       EKi  	  VP-                  4        Fo  w  ppV^ 8  d   VV,          V,          MRpV\.        8  g   K,  V P0                  P3                  VRVV^ V R2R7       \(        P5                  RV RV RVR 24       Kq  	  R#   \&         d(   p\(        P+                  RT RT 24        Rp?EK  Rp?ii ; i)a  
Uses Reddit's JSON API (no PRAW library needed) to fetch recent
posts from each subreddit, then scans titles for ticker mentions.
Reddit's public API allows basic requests with a user agent.
Steps:
  1. Fetch /r/{subreddit}/new.json (100 posts, last ~1-2 hours)
  2. Scan each post title for any of our ticker symbols
  3. Score each matching title with VADER
  4. Aggregate per-symbol: count + average sentiment
  5. Upsert all symbols into SentimentDatabase
Nro  zhttps://www.reddit.com/r/z/new.json?limit=100)rq  r   ru   childrencreated_utcrJ  r,   r  $ $r   rf   zSENT_REDDIT_ERR | r/r   r   r  z	 mentionsrP  zSENT_REDDIT | z | mentions=z | sentiment=r>  )r'  r  r#  r   r   r  r   SENTIMENT_LOOKBACK_REDDITREDDIT_USER_AGENTSENTIMENT_SUBREDDITSr  r@  rz  r~  re  rR   r(  r   rI  rX   r   r   r   SENTIMENT_MIN_MENTIONSrh  r  r   )r   sym_setmentions	sent_sumsr^  	cutoff_tsrq  subr  r  postspostru   r  rJ  title_ur  rc  r   r  avg_sents   &                    r   r  &SentimentEngine._fetch_reddit_mentions{  sI    xdll# % '	YY[77	!23''CI23%7JK||C"E##s*		377
BG!D"hhvr2D#DHH]A$>?G* "hhw3E!EKKM1C7G&se1:0auIQUWZA[4[$SMQ.M!%!<!<U!CB%cNbn<N	  ' " 

3) (2 #..*JC16y~-H..sH%-U$%5'0C  E ""$SEeW =!!)#0 +	  I$$';C5A3%GHHIs&   7/I"(CI".A*I""J-JJc                   V P                   '       ds    \        P                  ! 4       V P                  ,
          \        8  d+   \        P                  ! 4       V n        V P	                  4        \        P
                  ! R4       K  R#   \         d:   p\        P                  RT 24       \        P
                  ! R4        Rp?K  Rp?ii ; i)z@Fetches Senate stock disclosures from ProPublica/FMP once daily.rc   zSENTIMENT_CONGRESS_LOOP_ERR | N)	rn  r   r,  SENTIMENT_CONGRESS_INTERVAL_fetch_congress_tradesrI  rX   r   r   r  s   & r   r:  SentimentEngine._congress_loop  s    mmm!99;!4!447RR*.))+D'//1

4    !""%CA3#GH

4  !r  c           
         \         P                  ! \        ^R\        /R7      pVP                  ^8w  d%   \
        P                  RVP                   24       R# VP                  4       p\        P                  ! 4       \        ^R7      ,
          p\        4       pV F  p \        VP                  RR4      4      P                  4       P                  4       p\        VP                  RR4      4      P                  4       pVP                  R	R4      pV'       d	   V'       g   K  R F  p	 \        P                   ! W4      p
 M	  X
'       d%   W8  d   R
V9   d   VP%                  V4       K  K  K  K  	  \        V P(                  4      pV F1  pW9   d   ^M^ pV P*                  P-                  VRR^ VRV 2R7       K3  	  \
        P/                  R\1        V4       R\3        V4      R,           24       R#   \"         d    Rp
 K  i ; i  \&         d     EK}  i ; i  \&         d$   p\
        P                  RT 24        Rp?R# Rp?ii ; i)a  
Fetches Senate stock trading disclosures.
Uses Financial Modeling Prep's free demo endpoint which aggregates
senate disclosure JSON. Looks for BUY transactions in the last
30 days on any of our tracked symbols.
Steps:
  1. GET senate-disclosure endpoint (no key needed for demo)
  2. Filter for transactions in last 30 days, type=Purchase
  3. Extract ticker symbols that were purchased
  4. Set congress_bought=1 for each purchased symbol
  5. Clear flag for symbols NOT purchased (expire old signals)
ro  rp  zSENT_CONGRESS_HTTP | NrI   tickerr,   r  transactionDatepurchaser  r   zcongress_buy=rP  zSENT_CONGRESS | bought=z tickers | sample=Nr  NzSENT_CONGRESS_ERR | )r  z%m/%d/%Y)r  r@  PROPUBLICA_TRADESr  rz  r   r   r~  r   ry  r   r  r:   re  striprb  r  
ValueErrorr  rX   r#  rh  r  r   r   rG   )r   r  r(  	cutoff_dtboughttrader  tx_typetx_datefmtr  r  r  r	  r   s   &              r   r  &SentimentEngine._fetch_congress_trades  s   *	=<< 12)57H(IKD3&$$'<T=M=M<N%OP		F )I2,>>IF"599Xr#:;AACIIKF"599VR#89??AG$yy):B?G! 7&!)!2!27!@B!  8 bo*2G

6* 3Hor  ( $,,'GMqqsJc$(]4&3I  K 
 )#f+ 7v,r*+-  * &!%B& !   	=  #7s!;<<	=s{   AH AH  BH
"H $H
*G6 H
H
*B
H 6HH
HH

HH HH I(IIc                D   ^ pV P                   '       d    V P                  V\        V P                  4      ,          ,          pV^,          pV P                  P	                  V^ 4      p\
        P
                  ! 4       V,
          \        8  d4   V P                  V4       \
        P
                  ! 4       V P                  V&   \
        P                  ! ^4       K  R#   \         d;   p\        P                  RT 24       \
        P                  ! ^
4        Rp?EK  Rp?ii ; i)z9Cycles through all symbols fetching StockTwits sentiment.z SENTIMENT_STOCKTWITS_LOOP_ERR | N)rn  r#  r   r-  r@  r   SENTIMENT_STOCKTWITS_INTERVAL_fetch_stocktwitsrI  rX   r   r   rB  s   &    r   r;   SentimentEngine._stocktwits_loop	  s    mmm
||C#dll*;$;<q,,00a899;%(EE**3/15D))#.

1   ""%EaS#IJ

2rF  c                    < V ^8  d   QhRS[ /# rY  r9   )r;   r   s   "r   r<   r$  /	  s     0J 0J 0Jr   c                L    RV R2pRR/p/ p\         '       d
   \         VR&   \        P                  ! W#V^R7      pVP                  R8X  d1   \        P                  RV 24       \        P                  ! ^4       R	# VP                  R9   d   R	# VP                  ^8w  d   R	# VP                  4       pVP                  R
. 4      pV'       g   R	# \        R V 4       4      p\        R V 4       4      p	W,           p
V
^8  d	   W,          MRp\        V4      pV P                  P                  VR\        V^4      V^ RV RV	 RV 2R7       \        P                  RV RVR RV RV	 RV 2
4       R	#   \         d'   p\        P                  RT RT 24        R	p?R	# R	p?ii ; i)z;Fetch bullish/bearish ratio from StockTwits for one symbol.z0https://api.stocktwits.com/api/2/streams/symbol/z.jsonro  zStockTradingBot/8.1access_token)rq  r  r   i  zSENT_STOCKTWITS_RATE_LIMIT | Nmessagesc              3      "   T F_  pVP                  R 4      ;'       g    / P                  R4      '       g   K5  VR ,          R,          P                  R4      R8X  g   K[  ^x  Ka  	  R# 5i)entities	sentimentbasicBullishNr@  r   ms   & r   r   4SentimentEngine._fetch_stocktwits.<locals>.<genexpr>H	  X      P(Q55,2277D J-488AYN q(   A)A)!A)
A)c              3      "   T F_  pVP                  R 4      ;'       g    / P                  R4      '       g   K5  VR ,          R,          P                  R4      R8X  g   K[  ^x  Ka  	  R# 5i)r  r  r  BearishNr  r  s   & r   r   r  K	  r  r  r2   r  zbull=z bear=z total=rP  zSENT_STOCKTWITS | z | bullish=.2fz | bull=z msgs=zSENT_STOCKTWITS_ERR | r   )i  i  )rk   r  r@  rz  r   r   r   rI  r~  rT  r   rh  r  r  r   rX   )r   r   r  rq  r  r  ru   r  bullbeartotal_taggedbullish_pct	msg_countr   s   &&            r   r  !SentimentEngine._fetch_stocktwits/	  s   .	JHPUVC#%:;GF)9~&<<VQOD3&$$'DVH%MN

2:-3&yy{Dxx
B/H  P( P PD  P( P PD  ;L 4@13D4.#Kh-IGGNN6<!&{A!6!* !&+D6vWYK$P	  R $VHKC7H IvVD6	{<  	J  #9&QC!HII	Js6   E2 A!E2 =E2 E2 #)E2 B!E2 2F#=FF#c                &   < V ^8  d   QhRS[ RS[/# r  r  )r;   r   s   "r   r<   r$  a	  s     # # # #r   c                8    V P                   P                  V4      # )u   
Public interface for the feature builder.
Returns all sentiment scores for a symbol as a flat dict.
Values are always valid floats/ints — never None.
)rh  r@  )r   r   s   &&r   
get_scoresSentimentEngine.get_scoresa	  s     ww{{6""r   )	r,  r)  r+  r*  r-  rn  r(  rh  r#  N)r   r   r   r   r
  r  r  r  r7  rA  r8  ri  r9  r  r:  r  r;  r  r  r   r   r   s   @r   r!  r!  i  sx     R R!LF$7D 7DR "<C <C\
 8V
!7=Z 0J 0Jd# #r   r!  c                4    V ^8  d   QhRRR\         R\         /# )r7   r  zpd.DataFramestemr8   r9   )r;   s   "r   r<   r<   r	  s!     
 
> 
 
 
r   c                   a  RV 3R l3RV 3R l33 F  w  r# W,           pV! V4       Vu # 	  R#   \          d     K,  i ; i)zOSave a feature DataFrame to disk. Tries parquet first, falls back to pickle.gz..parquetc                 *   < SP                  V R R7      # )Fr`  )
to_parquetr[   r  s   &r   ro  $_save_feature_file.<locals>.<lambda>t	  s    r}}Qe}/Lr   .pkl.gzc                 &   < SP                  V 4      # r	  )	to_pickler  s   &r   ro  r  u	  s    r||Ar   r,   )rX   )r  r  extr0  rU   s   f&   r   _save_feature_filer  r	  sV    #%LM"%>?A	:D4LKA   		s   0??c                (    V ^8  d   QhR\         RR/# )r7   r  r8   r^  r9   )r;   s   "r   r<   r<   ~	  s      S %: r   c                J   R Fh  pW,           p\         P                  P                  V4      '       g   K2   VR8X  d   \        P                  ! V4      u # \        P
                  ! V4      u # 	  R#   \         d'   p\        P                  RT RT 24        Rp?K  Rp?ii ; i)z<Load a feature file from disk. Tries parquet then pickle.gz.r  zFEATURE_FILE_LOAD_ERR | r   N)r  r  )	rT   rU   rV   r  read_parquetread_picklerX   r   r   )r  r  rU   r   s   &   r   _load_feature_filer  ~	  s    &z77>>$N*$??400>>$// '   N$$'?vS%LMMNs   A1A11B"<BB"c                   4  a  ] tR tRt o R tR tR tV 3R lR ltV 3R lR ltR$V 3R	 lR
 llt	R t
R tR tV 3R lR ltR tV 3R lR ltV 3R lR ltV 3R lR ltR tV 3R lR ltR%V 3R lR lltR&V 3R lR lltV 3R lR  ltV 3R! lR" ltR#tV tR# )'DataManageri	  c                   \        4       V n         \        V P                   4      V n        . V n        V P	                  4        \        \        4      V n        \        \        4      V n
        \        \        4      V n        / V n        / V n        / V n        / V n        / V n        \'        4       V n        \+        \,        4      V n        ^ V n        \+        \,        R,          4      V n        ^ V n        \7        V P                  V P                  V P                   4      V n        \;        \+        \,        4      R7      V n        / V n        / V n         RV n!        / V n"        RV n#        RV n$        ^V n%        R# )r  :Nr  N)r#  r  r   r  N)&rD   r  rh  _history_dbs_load_history_dbsr:  r#   fhr  r)   avr  r+   polyfeaturesri  rj  
sector_mapsector_perfr  bad_symbolsrG   STOCK_UNIVERSE	_rr_queue_rr_idx	_av_queue_av_idxrf  	alpaca_wsr!  r  _feature_last_ts_feature_day_cache_TRADING_DAY_BARS_row_count_cache_row_count_cache_ts_ROW_COUNT_TTL_MAX_FEATURE_ROWSr4  s   &r   r  DataManager.__init__	  s   ,.&t':':;  (9-.?@(5	5/s 340$++t}}U*43GH ')(* "% ')*- %) "%r   c           
     z   ^ RI p^ RIpRpV P                  pVP                  \         R24       Uu. uF  pWT8w  g   K  VNK  	  pp\        P
                  P                  V4      '       Ed   VR,           F  p\        P
                  P                  V4      R8  g   K)   R FL  p\        P
                  P                  Wx,           4      '       g   K0  \        P                  ! Wx,           4       KN  	  VP                  V4       \        P                  RV 24       K  	  V'       Eg(   \        P                  ! 4       \        ^R7      ,
          P                  R4      p	\         R	V	 R
2p
 ^ RIpVP#                  V4      pVP%                  R4       VP'                  4        VP)                  W:4       R FN  p\        P
                  P                  W8,           4      '       g   K0  VP)                  W8,           W,           4       KP  	  \        P                  RV RV
 R\        P
                  P                  V
4      R,          R,           R24       . V n        V P                  p\-        4        FV  pW8w  g   K  \        P
                  P                  V4      '       g   K2  V P*                  P/                  \1        V4      4       KX  	  \        P                  R\        P
                  P3                  V4       R\5        V P*                  4       R24       R# u upi   \         d     EK  i ; i  \         d     ELi ; i)zOpen read-only handles to all daily DBs except today.
Handles one-time migration from legacy trading_data.db on first run.
Called at startup and after midnight rotation.Nr   rK   NNNr  z!DB migration: removed incomplete rI   r?   r>   r@   zPRAGMA wal_checkpoint(TRUNCATE)zDB migration:  ->  (r   MB)zDaily DB: today=z | history=z older DB(s)rL   )rM   rN   )rO   r   rD   rA   rT   rU   rV   r   rW   r   r   rX   r   rB   r   rC   r   r   r   r  r   r  r_   rS   r  r   r   )r   r   _shutillegacy
today_pathr[   dated_othersbadsfx	yesterdaymigrated_sqr   r^   rU   s   &              r   r  DataManager._load_history_dbs	  s    	0 #**
#(::0@.M#N ,#Na? #N ,77>>&!! $A77??3')3#7C!ww~~ci88 "		#) 4 $8 %++C0&Gu$MN '  <%\\^iQ.??II(S	-.a	{#>)V,BJJ@AHHJ f/+Cww~~fl33flHNC , nVHD
"RWW__U]E^`dEdfjEjDkknop ##!OD}!5!5!!(($8 $ 	rww//67 84,,-.l<	
O, %  ! s5   LL-LA	L)6L+ L('L(+L:9L:c                   \        4       pWP                   8X  d   R# \        P                  RV P                    RV 24       V P                  P	                  V P
                  4       Wn         \        V4      V n        V P
                  V P                  n        \        4        \        P                  R4       WP                   8w  d   RV n	        \        P                  R4       R# R# )zxSwitch to a new daily DB if the calendar date has changed.
Called at every market open so each trading day starts fresh.NzDaily DB rotation: r  zDaily DB rotation complete.r   z>DB_ROTATED | feature_cache_preserved | row_count_cache_cleared)rD   r   r   r  rS   rh  r  r  r_   r  r   )r   new_paths   & r   _rotate_db_if_needed DataManager._rotate_db_if_needed	  s     "#***)$*=*=)>d8*MN  )&8$ GG13 ***'*D$^_ +r   c                :   < V ^8  d   QhRS[ RS[P                  /# r  r  )r;   r   s   "r   r<   DataManager.__annotate__
  s#     A A# A",, Ar   c                   . pV P                    F9  pVP                  V4      pVP                  '       d   K(  VP                  V4       K;  	  V P                  P                  V4      pVP                  '       g   VP                  V4       V'       g   \
        P                  ! 4       # \
        P                  ! VRR7      pVP                  R.RR7      pVP                  R4      P                  RR7      # )zHFull price series across ALL daily DBs. Used for first-time builds only.Tignore_indexr   rD  subsetkeepdrop)r  r  emptyrS   rh  r  r  concatdrop_duplicatessort_valuesreset_index)r   r   frameshdbr  df_todaycombineds   &&     r   get_combined_seriesDataManager.get_combined_series
  s    $$C'B888b! % 77%%f-~~~MM(#<<>!99V$7++D6+G##D)5545@@r   c                @   < V ^8  d   QhRS[ RS[RS[P                  /# )r7   r   since_tsr8   )r:   r  r  r  )r;   r   s   "r   r<   r  
  s+     A AS AE Abll Ar   c                $   . pV P                   '       d   V P                   R	,          .M. V P                  .,           pV FS  p VP                  4       p\        P                  ! RWaV3R7      pVP
                  '       g   VP                  V4       KS  KU  	  V'       g   \        P                  ! 4       # \        P                  ! VRR7      pVP                  R.RR7      pVP                  R4      P                  RR7      #   \         d     K  i ; i)
z
v9: Incremental query -- only rows newer than since_ts.
Only queries today's DB and yesterday's DB (new bars can't appear
in older history files). Dramatically faster than full-history query.
zcSELECT ts,price,open,high,low,prev_close,volume FROM quotes WHERE symbol=? AND ts>? ORDER BY ts ASCr  Tr  r   rD  r  r  r  )r  rh  r  r  r  r  rS   rX   r  r  r  r  r  )	r   r   r&  r  dbs_to_checkrh  r  r  r"  s	   &&&      r   get_new_seriesDataManager.get_new_series
  s     373D3D3D**2./"QUQXQXPYYB
xxz&&?(!3
 xxxMM"%    <<>!99V$7++D6+G##D)5545@@  s   AD  DDc                &   < V ^8  d   QhRS[ RS[/# )r7   forcer8   )r  r6  )r;   r   s   "r   r<   r  .
  s      T d r   c                   \         P                   ! 4       pV'       g.   W P                  ,
          V P                  8  d   V P                  # / pV P                   FE  pVP                  4       P                  4        F   w  rVVP                  V^ 4      V,           W5&   K"  	  KG  	  V P                  P                  4       P                  4        F   w  rVVP                  V^ 4      V,           W5&   K"  	  W0n        W n        V# )z
Row counts across ALL daily DBs.
v9: Cached with 60s TTL -- avoids querying all DB files every cycle.
Was O(symbols x DB_files) every call; now O(1) within TTL window.
)	r   r  r  r  r  r#  r   r@  rh  )r   r,  rB   countsr   r  cnts   &&     r   get_combined_row_counts#DataManager.get_combined_row_counts.
  s     iik# 8 88D<O<OO((($$CNN,224$jja036 5 % **,224HC **S!,s2FK 5#)#& r   c                P   \         P                  R 4       \        R,           FT  pV\        9   d   K  V P                  P                  V4      pV'       g   K5  VP                  RR4      V P                  V&   KV  	  \         P                  R\        V P                  4       24       R# )z&Loading sector info (skipping ETFs)...rt  finnhubIndustryUnknownz  Sectors loaded: N)	r   r   r  _ETF_SETr  rc  r@  r  r   )r   r  r[   s   &  r   load_sectorsDataManager.load_sectorsA
  s|    <=!$''Ch$Aq'(uu->	'J$ ( 	(T__)=(>?@r   c                6   V P                  4        V P                  '       dG   \        P                  R \	        V P                  4       R24       V P                  P                  4        \        P                  ! V P                  RR7      P                  4        R# )u   Market open — clearing z bad_symbolsT)r  r  N)
r  r  r   r   r   r  r  r  _bulk_polygon_fetchr  r4  s   &r   on_market_openDataManager.on_market_openL
  sm    !!#KK3C8H8H4I3J,WX""$ 8 8FLLNr   c                D   \         '       g   R # \        P                  R4       \        R,           Fk  pV\        9   d   K  V P
                  P                  V4      pV'       g   K5  V P                  P                  V4      pV'       g   KZ  V P                  V4       Km  	  R # )Nz%Polygon burst fetch at market open...rQ  )
r+   r   r   r  r5  r  r!  rh  r  rebuild_features_forr   r  r
  r  s   &   r   r9  DataManager._bulk_polygon_fetchT
  ss    {;<!#&&Ch9955c:DtGG''-1--c2 'r   c                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r  a
  s      $ r   c           
        V P                    Uu. uF  qV P                  9  g   K  VNK  	  ppV'       g   R# V P                  \        V4      ,          V n        W P                  ,          pV ;P                  ^,          un        V P                  P                  V4      pVf   R# \        VP                  R^ 4      4      pV^ 8:  d   R# \        \        P                  ! 4       4      p\        VP                  RV4      4      p\        VP                  RV4      4      p\        VP                  RV4      4      p	\        VP                  RV4      4      p
\        VP                  R4      ;'       g    ^ 4      pV P                  P                  W6WWWW4       WPP                  V&   \        P                  RV R	VR
 24       R# u upi )u   
Strict round-robin Finnhub polling — covers all 300 universe stocks.
Supplemental to Alpaca: Alpaca gives minute bars on all symbols,
Finnhub gives sub-minute confirmation quotes for the active universe.
Fr[  r  r  r  pcr  z	FH Quote z: $r  T)r  r  r  r   r  r\  r  r@  r   r   rh  r  ri  r   r   )r   r  eligibler  r]  r  r   r  r  r   r  r  s   &           r   fetch_next_quoteDataManager.fetch_next_quotea
  sW     $~~K~!$:J:J1JAA~K||c(m3||$GGMM#9aeeCm$A:%155e,-155e,-155e,-155u-.
155:??+sdL CySs45- Ls
   GGc                ^   V P                   V P                  \        V P                   4      ,          ,          pV ;P                  ^,          un        V P                  P	                  VR4      pV'       d9   V P
                  P                  V4      pV'       d   V P                  V4       R# R# R# )r  r  N)r  r  r   r  r  rh  r  r=  r>  s   &   r   fetch_alpha_vantage_burst%DataManager.fetch_alpha_vantage_burst
  sx    ~~dllS-@@Aww##C0##D)A))#.  r   c                &   < V ^8  d   QhRS[ RS[/# r  r:   r  )r;   r   s   "r   r<   r  
  s     j j3 j4 jr   c           	        V P                   P                  V4      pV P                  P                  VR4      pV P                  P                  V4      pV P
                  P                  V4      pVR8X  g	   Ve   Vf   V P                  V4      pVP                  '       d   R# \        W`P                  VR7      pVf   R# VP                  V P                  4      P                  4       V P
                  V&   \        VR,          P                  R,          4      V P                  V&   \        V4      V P                   8  d   VP                  V P                   ) R pWpP                  V&   R# V P#                  WR7      pVP                  '       d   Ve   VP                  '       g   T;'       g    / p	\        V	P                  RR4      4      VR&   \        V	P                  R	R4      4      VR	&   \        V	P                  R
R4      4      VR
&   \        V	P                  RR4      4      VR&   \        \        V	P                  RR4      4      \        V	P                  R	R4      4      R,          ,           R,          4      VR&   R# \$        P&                  ! WX.RR7      p
V
P)                  R.RR7      p
V
P+                  R4      P-                  RR7      p
\        WP                  VR7      pVf   R# \        V4      p\        V4      V8  d   VP                  VR P                  4       pM(VP                  \        V4      4      P                  4       pVP                  '       d   R# Ve?   VP                  '       g-   \$        P&                  ! WM.RR7      pVP)                  RR7      pMTp\        V4      V P                   8  d   VP                  V P                   ) R pWP                  V&   \        VR,          P                  R,          4      V P                  V&   \$        P&                  ! WX.RR7      pVP                  V P                  4      P                  4       V P
                  V&   R# )ag  
v9: INCREMENTAL feature rebuild.

First call per symbol: full history query (unavoidable).
Subsequent calls: only queries new bars since last processed timestamp.
Uses last 100 rows as rolling-window context so RSI/SMA/etc compute correctly.

Cost: O(new_rows) not O(total_rows). Daily rebuild stays fast regardless
of how many months of history accumulate.
r   NF)r]  r   T)r&  rH  rL  rN  r2   rJ  r4   ffffff?rY  r  rD  r  r  )r  r  )r  r  r  r@  r  r  r#  r  r  rj  tailr  copyr  r  r   r  r)  r  r  r  r  r  )r   r   r  last_tscached_featday_ctxr  featnew_dfr  combined_dffeat_combinedn_ctxnew_featupdatednew_day_ctxs   &&              r   r=   DataManager.rebuild_features_for
  s    NN--f5	++//<mm''/--11&9c>[0GO ))&1Bxxx!"mmiPD| /1ggd6L6L.M.R.R.TD##F+.3BtHMM"4E.FD!!&)4y4111yy$"8"8!8!9:$(MM&! $$V$><<<&{/@/@/@OO49!%%@PTW:X4Y,-49!%%@RTW:X4Y./49!%%@TVY:Z4[0149!%%
C:P4QJ'49155!1378155!3S9:S@ADGH5-.  ii 1E!11$f1M!--d3??T?J&{MM8AC  G}%$))%&1668H %))#f+6;;=H>>> ";+<+<+<ii 7dKG--6-:GGw<$000llD$:$:#:#;<G 'f(-fTl.?.?.C(Df% ii 1E*5*:*:""+

$& 	' r   c                    < V ^8  d   QhRS[ /# r6   rO  )r;   r   s   "r   r<   r  
  s      S r   c                     \        R4       FC  pVP                  R4      '       g   K  \        VP                  4       ^,          4      R,          u # 	  ^ #   \         d     ^ # i ; i)z1Current process RSS in MB from /proc/self/status./proc/self/statusVmRSS:r   r.  r   r   r   rX   )r   lines   & r   _get_rss_mbDataManager._get_rss_mb
  s\    	01??8,,tzz|A/477 2
   		   "A (A A A%$A%c                    < V ^8  d   QhRS[ /# r6   rO  )r;   r   s   "r   r<   r  
  s     > >c >r   c                   \         e   \        \         R,          4      pMg \        \        R4      P                  4       P	                  R4      ^,          P	                  4       ^ ,          4      R,          p\        VR,          4      pV P                  4       p^ p^ p^ p^ pVP                  4        EF=  w  rV	^8  g   K  VR,          ^ 8X  d   V P                  4       p
\        P                  R	V R
V
 RV R24       W8  dw   \        P                  RV
 RV R24       ^ RIqP                  4        \        P                  ! ^4       V P                  4       pW8  d   \        P                  RV R24        MzWP                   9   ;'       d    V P                   V,          R8  pV P#                  V4      '       d*   V^,          pV'       d   V^,          pEK(  V^,          pEK4  V^,          pEK@  	  \        P                  RV RV RV RV R\%        V4       2
4       \'        RV R\%        V4       24       V#   \
         d    Rp ELi ; i)a	  
v9: Incremental rebuild. First run builds all symbols from scratch.
Subsequent runs only process new bars -- stays fast as history grows.
RAM guard: pauses rebuild if process RSS exceeds 5.5GB to prevent
OOM kills. The Linux kernel OOM limit on this VM is ~7.3GB.
Nr3   /proc/meminfoz	MemTotal:r   r  i|  r   z REBUILD_PROGRESS | symbols_done= | rss=z
MB | ceil=r  z FEATURE_REBUILD_RAM_GUARD | rss=r   z&MB | pausing 30s to let GC free memoryzFEATURE_REBUILD_RAM_BAIL | rss=z5MB still high | stopping rebuild early to prevent OOMr   zFEATURE_REBUILD_DONE | ok=z | full_builds=z | incremental=z | skipped=z | total_symbols=z#rebuild_all_features complete | ok=r  )
RAM_CAP_MBr   r.  readr   rX   r0  r   ra  r   r   r   gccollectr   rI  r  r=  r   _log_ram)r   RAM_CEIL_MB_sys_total_mbr.  okr~  incrementalskipped_ramr  r/  rssrj  rss2
was_cacheds   &             r   rebuild_all_features DataManager.rebuild_all_features
  sY    !j4/0K# #)..066{CAFLLNqQ!! "-$"67 ..0HCby8q=**,C %%:2$ ?"e:k]"> ($,,>se5 V@ A "::<

2#//1-(00"A$ HH !I "!%:%:: C C"&"7"7"<s"B ,,S11!GB!#q(	1$KA 'B 	( -&} ="m#4S[MC	

 	6rd!CK=IJ	]  #"#s   A&H: :I
Ic           
        / pV P                   P                  4        F  w  r#V P                  P                  V4      pVf   K&  \	        V4      ^8  g   K8  VR,          P
                  RR  P                  4       pVP                  V. 4      P                  \        V4      4       K  	  VP                  4        UUu/ uF%  w  rgV\        \        P                  ! V4      4      bK'  	  uppV n        R # u uppi )Nrw  )r  r   r  r@  r   r  rT  r   rS   r  r  r  r  )r   srr  r  rR  recentr  r  s   &       r   update_sector_perfDataManager.update_sector_perf>  s    --/HC==$$S)DCINl+006::<c2&--eFm<	 0
 >@XXZHZTQAuRWWQZ00ZHHs   :+C0c                    < V ^8  d   QhRS[ /# r6   r9   )r;   r   s   "r   r<   r  G  s     $ $S $r   c           
        \         P                  ! \        4      P                  R4      p. pV P                  P                  4        F[  w  r4Ve   VP                  '       d   K  VP                  V P                  4      P                  4       pW5R&   VP                  V4       K]  	  V'       g   \        P                  R4       R# \        P                  ! VRR7      p\        P                   P#                  \$        RV 24      p\'        Wg4      pV'       dc   \(        P+                  RV R	\-        V4      R
 R\-        V4       R24       \        P+                  RV R\-        V4       R\-        V4       24       V# )a  
v9: Save today's feature rows to disk as a permanent record.

Called after each EOD rebuild. Each file covers one trading day.
These files accumulate forever and are used for:
  - Daily incremental training (50 new trees from today's data)
  - Weekend deep training (Mon-Fri combined)
  - Monthly distillation (full historical rebuild of compact model)

Format: flat DataFrame with 'symbol' column + all FEATURE_COLS + targets.
r?   r   zDAILY_FEATURES_SAVE | no datar,   Tr  	features_zDaily features saved -> r   r  z rows, 	 symbols)zDAILY_FEATURES_SAVED |  | rows=r&  )r   rB   r  rC   r  r   r  rM  r  rN  rS   r   r   r  r  rT   rU   r   r   r  r   r   r   )	r   r^   r  r  feat_dfdailyr"  r  rU   s	   &        r   save_daily_featuresDataManager.save_daily_featuresG  s=    Y'00: MM//1LC'---LL!7!78==?E!(OMM%  2   !@A99V$7ww||.)E70CD!(1KK*4& 1M!$GCK=	C )$ 0Hk#f+@ r   Nc                &   < V ^8  d   QhRS[ RS[/# )r7   r\   r8   r  )r;   r   s   "r   r<   r  m  s      3 $ r   c           
        Vf*   \         P                  ! \        4      P                  R4      p\        P
                  P                  \        RV 24      p\        V4      pVe   VP                  '       d   / # / pVP                  R4       F*  w  rVVP                  R.R7      P                  RR7      WE&   K,  	  \        P                  RV R\        V4       R	\        V4       24       V# )
zs
Load a daily feature file as a symbol->DataFrame dict for training.
date_str: YYYYMMDD string. Defaults to today.
r?   r  r   r  Tr  zFEATURES_LOADED | date=r&  r  )r   rB   r  rC   rT   rU   r   r   r  r  groupbyr  r  r   r   r   )r   r\   r  r  r  r  groups   &&     r   load_features_for_training&DataManager.load_features_for_trainingm  s    
 ||I.77AHww||.)H:0FG%:I**X.JC**hZ*8DD$DOFK /%hZ 06{m8CG96	
 r   c                &   < V ^8  d   QhRS[ RS[/# )r7   max_daysr8   )r   r6  )r;   r   s   "r   r<   r    s     ) )S )$ )r   c           	        ^ RI p\        VP                  \        P                  P	                  \
        R4      4      VP                  \        P                  P	                  \
        R4      4      ,           4      pW1) R pV'       g   \        P                  R4       / # . pV FY  p\        VP                  RR4      P                  RR4      4      pVf   K4  VP                  '       d   KH  VP                  V4       K[  	  V'       g   / # \        P                  ! VRR	7      pR
VP                  9   d'   RVP                  9   d   VP                  RR
.RR7      pR
VP                  9   d$   VP!                  RR
.4      P#                  RR7      MTp\$        P'                  R\)        V4      R R\)        V4       RV R24       / pVP+                  R4       F*  w  rV
P-                  R.R7      P#                  RR7      W&   K,  	  V# )ak  
Load all available daily feature files for model distillation.
Combines up to max_days of history into one comprehensive training set.
Deduplicates on (symbol, ts) so overlapping saves don't inflate the dataset.

This is the 'complete memory' dataset -- everything the model has ever
seen, used to create a compact fresh model before incremental growth resumes.
Nzfeatures_????????.parquetzfeatures_????????.pkl.gzz.DISTILL_DATASET | no daily feature files foundr  r,   r  Tr  r   r   rD  r  r  zDistillation dataset: r   rows from z daily files (z day window)r  )rO   rQ   rT   rU   r   r   r   r   r  rR   r  rS   r  r  r  r  r  r  r   r   r   r  r  )r   r  r   filesr  r   r  r"  r  r  r  s   &&         r   load_distill_dataset DataManager.load_distill_dataset  s    	JJrww||$68STUJJrww||$68RSTU
 ij!  !QRIA#AIIj$<$D$DYr$RSB~bhhhb!  I99V$78###H4D4D(D// $'f 0 H UY\d\l\lTl8''4(89EE4EPrz$S]1$5 6J<~hZ|E	
 "**84JC**hZ*8DD$DOFK 5r   c                    < V ^8  d   QhRS[ /# r6   r5  )r;   r   s   "r   r<   r    s     = =d =r   c                T   ^ RI Hp \         P                  ! \        4      pVP	                  4       pV^8X  d   ^pMV^8X  d   ^pMTpW!! VR7      ,
          p. p^ p\        ^4       F  pWQ! VR7      ,           p	V	P                  4       VP                  4       8  d    MwV	P                  R4      p
V P                  V
4      pVP                  4        F*  w  rVP                  4       pWR&   VP                  V4       K,  	  V'       g   K  V^,          pK  	  V'       g   \        P                  R4       / # \        P                  ! VRR7      pRVP                   9   d$   VP#                  RR.4      P%                  RR	7      p\&        P)                  R
\+        V4      R RV R24       \,        P.                  P1                  \2        RVP                  R4       24      p\5        W4       / pVP7                  R4       F,  w  ppVP9                  R.R7      P%                  RR	7      VV&   K.  	  V# )as  
Build this week's combined training dataset from Mon-Fri daily files.

Loading the full week's bars gives models a 5-day context window.
Rolling features like ret_5, ret_10, slope_20 naturally capture
weekly patterns when computed over 5 days of data vs 1 day.

Called on Saturday during weekend deep train.
Returns symbol->DataFrame dict ready for init_model training.
)r   rI   r?   r   z3WEEKLY_DATASET | no daily files found for this weekTr  r   r  zWeekly dataset: r  r  z trading daysfeatures_week_r  )r   r   rB   r  r  r  r  rC   r  r   rN  rS   r   r   r  r  r  r  r  r   r   r   rT   rU   r   r   r  r  r  )r   _tdr^   dow	days_backmondayr  loaded_daysr  dayr\   day_datar  r  r"  	week_stemr  r  s   &                 r   build_weekly_dataset DataManager.build_weekly_dataset  s    	.Y'mmo!8IAXII),,qA3A;&CxxzEJJL(||H-H66x@H#>>+WWY"8b! , xq     !VWI99V$78###++Xt,<=IItITHs8}Q/ 0=/	
 GGLLV__X678
	 	8/"**84JC**hZ*8DD$DOF3K 5r   c                    < V ^8  d   QhRS[ /# r6   r9   )r;   r   s   "r   r<   r    s     
 
S 
r   c                   V P                  4       p\        VP                  4       4      p\        R  VP                  4        4       4      p\        R VP                  4        4       4      pV P                  P	                  4       pV P
                  P                  4       p\        V P                  4      pRV P                  P                  4       R RV RVR R\        V4       RV R	V R
V RVR 2# )c              3   >   "   T F  q\         8  g   K  ^x  K  	  R# 5ir  N)MIN_ROWS_TO_TRAINr   r  s   & r   r   *DataManager.status_line.<locals>.<genexpr>       O_=N8N!!_   
c              3   >   "   T F  q\         8  g   K  ^x  K  	  R# 5ir  )MIN_ROWS_TO_TRADEr  s   & r   r   r    r  r  zDB .1fzMB (+zhist) | total_quotes=r  z | symbols_in_db=z | trainable=z | tradeable=z | fh_calls/min= | alpaca_bars=)r0  rT  r  r  rV  r  r  r   r  rh  r5  )r   r.  total	trainable	tradeablefh_callsalpaca_bars
hist_counts   &       r   status_lineDataManager.status_line  s    224&--/*OV]]_OO	OV]]_OO	gg//1nn224$++,
$''//#C(j\9NuUVi X [Myk B"#3H: >&q/+	
r   )r  r  r  r  r  r  r  r  r  r  r  r  rD   r  r  r  rh  r  r  r  ri  r  r  r  rj  Fr	  )Z   )r   r   r   r   r  r  r  r#  r)  r0  r6  r:  r9  rD  rG  r=  ra  ru  r{  r  r  r  r  r  r   r   r   s   @r   r  r  	  s     '%X4
l`&A A A A6 &	AO3 </j jX > >@I$ $L () )V= =~
 
r   r  c                   >  a  ] tR tRt o RtR"V 3R lR lltV 3R lR ltV 3R lR	 ltR"V 3R
 lR lltR t	]
V 3R lR l4       tV 3R lR ltR#V 3R lR lltR$V 3R lR lltV 3R lR ltV 3R lR ltV 3R lR ltR tR#V 3R lR lltR tV 3R lR  ltR!tV tR# )%
StockModeli  a  
v9: LightGBM-backed model replacing sklearn GBM.
Key improvements:
- LightGBM releases the Python GIL during C++ prediction -- safe for ThreadPoolExecutor
- 5-10x faster training than sklearn GBM
- Incremental training via init_model (appends 50 trees per cycle, no full retrain)
- Native feature importance tracking (gain-based, per retrain cycle)
- PSI-based drift detection
- Rolling Information Coefficient (IC) for agent quality ranking and pruning
Nc                &   < V ^8  d   QhRS[ RS[/# )r7   r  cfgr  )r;   r   s   "r   r<   StockModel.__annotate__	  s     *' *'S *'t *'r   c                   Wn         T;'       g    / pR V n        RV n        RV n        . V n        . V n        / V n        \        P                  ! . 4      V n	        ^ V n
        RV n        RV n        VP                  RR4      V n        VP                  RR4      V n        VP                  R^4      V n        VP                  R^4      V n        VP                  R	R
4      V n        \&        '       gS   V P                  V P                  V P                   rTp\)        W4VR
^^*^RR7      V n        \-        W4VR
^^*^RR7      V n        MRV n        RV n        \1        4       V n        R# )Fr   Nr  ra   r  {Gz?r  
num_leavesfeature_fractionr  r/   )r  r  r  	subsamplemin_samples_leafrandom_staten_iter_no_changevalidation_fraction)r  trained	train_accval_accpreds
ic_historyfeat_importancer  array_pred_hist_baseline_train_countlgb_clflgb_regr@  r  r  r  r  r  LGB_OKr   clfr   regr    scaler)r   r  r  nelrmds   &&&   r   r  StockModel.__init__	  s=   	iiR
 "%'/1xx|   !$C @ #D A #A > #B ? #(:C @ v**D,>,>BB1R!#DH
 1R!#DH DHDH$&r   c                    < V ^8  d   QhRS[ /# r6   r5  )r;   r   s   "r   r<   r  5  s     
 
 
r   c                    R RRRRV P                   RV P                  RV P                  RV P                  RR	R
^R^RRR^R^*/# )	objectivebinarymetricbinary_loglossr  r  r  r  bagging_fractionr  bagging_freqmin_child_samples	verbositynum_threadsr  r  )r  r  r  r  r4  s   &r   _lgb_params_clfStockModel._lgb_params_clf5  s]    !1!3!3!6!6
 	
r   c                    < V ^8  d   QhRS[ /# r6   r5  )r;   r   s   "r   r<   r  E  s       r   c                :    V P                  4       pR VR&   RVR&   V# )
regressionr  rmser  )r  r   r[   s   & r   _lgb_params_regStockModel._lgb_params_regE  s'      "%+(r   c                ,   < V ^8  d   QhRS[ RS[ RS[/# )r7   r  r\  r8   r6  r  )r;   r   s   "r   r<   r  K  s'     i id iT iT ir   c                   . . . . 3w  r4rVVP                  4        F  w  rx\        V4      \        8  d   K  VP                  V\        ,          P
                  4       VP                  VR,          P
                  4       VP                  VR,          P
                  4       V'       d   \        VP                  VR4      4      MRp	VP                  \        P                  ! \        V4      V	4      4       K  	  V'       g&   \        P                  RV P                   R24       R# \        P                  ! V4      P                  \        P                  4      p
\        P                   ! V4      p\        P                   ! V4      p\        P                   ! V4      pV P"                  P%                  V
4      p\'        WWR^*R7      w  pppppppp\(        '       Ed   V P*                  R	J;'       d    V P,                  ^ 8  pV P/                  4       p\1        T R
V'       d   ^2MV P2                  4      VR&   V P5                  4       p\1        T R
V'       d   ^2MV P2                  4      VR&   \6        P8                  ! VVP                  \:        4      VRR7      p\6        P8                  ! VVP                  \:        4      VRR7      p\6        P8                  ! VVVRR7      p\6        P8                  ! VVVRR7      p\6        P<                  ! ^RR7      \6        P>                  ! R!4      .p\6        P@                  ! TTV.TV'       d   V P*                  MR	RR7      V n        \6        P@                  ! TTV.TV'       d   V PB                  MR	RR7      V n!        V P*                  PE                  V4      pVR8  P                  \:        4      p V P*                  PE                  V4      p!V!R8  P                  \:        4      p"\        \G        VV"4      4      V n$        \        \G        VV 4      4      V n%        V P*                  PM                  RR7      p#V#PO                  4       R,           p$\Q        \S        \        \        4      \        V#4      4      4       U%u/ uF(  p%\        V%,          \        V#V%,          V$,          4      bK*  	  up%V n*        V'       g   VV n+         ^ RI,H-p& V&! VV4      w  p'p\        P\                  ! V'4      '       gZ   V P^                  P                  \        V'4      4       \        V P^                  4      ^d8  d   V P^                  Pa                  ^ 4       T ;P,                  ^,          un        T'       d   RMRp(\        Pe                  RT P                   RT( RT PH                  R RT PJ                  R R\        T
4      R RT Pg                  4       R 24       MV Ph                  Pk                  VVVR7       V Pl                  Pk                  VVVR7       \        \G        VV Ph                  PE                  V4      4      4      V n$        \        \G        VV Ph                  PE                  V4      4      4      V n%        \        Pe                  RV P                   R V PH                  R RV PJ                  R R\        V
4      R 24       RV n7        R# u up%i   \b         d     ELi ; i)"z
v9: Incremental LightGBM training.
First call: full train (n_estimators trees).
Subsequent calls: appends 50 new trees via init_model.
rx  rw  rf     [z] No trainable features yet.Fr-   )	test_sizer  N_override_treesr  T)labelrb  free_raw_data)r  	referencer  )verbose)
valid_sets	callbacks
init_modelkeep_training_boosterr2   gain)importance_typerf  )	spearmanrINCREMENTALFULL] z train=r>  z val=z n=r   IC=)sample_weightz] train=r  )8r   r   r  rS   FEATURE_COLSr  r  r@  r  r~  r   r   r  vstackr  r}  concatenater  fit_transformr!   r  r  r  r  r}  r  r  lgbDatasetr   early_stoppinglog_evaluationtrainr  predictr"   r  r  feature_importancerT  r  r  r  r  scipy.statsr  isnanr  poprX   r   
rolling_icr  fitr  r  ))r   r  r\  XpYdpYrpWpr  rR  r  XYdYrWXsXtrXvYdtYdvYrtYrvWtr>   is_incremental
params_clf
params_reg	ds_tr_clf
ds_val_clf	ds_tr_reg
ds_val_regcbs	val_proba	val_predstr_probatr_predsraw_impr  r  _spic_valr  s)   &&&                                      r   r  StockModel.trainK  se    r2r>!)IC4y,,IId<(//0JJtL)001JJtL)00107gkk#s+,SAIIbggc$i+, * NNS+GHIYYr]!!"**-^^C ^^C ^^B[[&&q)-=BSr.
*Rc3R 6"ll$6PP4;L;Lq;PN--/J)07HP^"dhdudu)vJ~&--/J)07HP^"dhdudu)vJ~& S

3Z^_IR

39dhiJSBdSIRyX\]J%%b%8#:L:LR:PQC99I&<+94<<t&*DL 99I&<+94<<t&*DL --b1I#c/11#6I--c2H"S.005H">#x#@ADN">#y#ABDL ll55f5MGkkme+E s3|#4c'lCD$DA QwqzE'9!::D$D  "+4(8	3/	xx''OO**5=94??+c1++A. "$2=DKKdii[4&s/C D||C(CF1:T$//:KC9PR HHLLcL4HHLLcL4">#txx7G7G7L#MNDN">#txx7G7G7K#LMDLKK#dii[0DE$,,WZI[[^_bcd_efg^hijG$"  s   .[-[ <A[ [%$[%c                    ^ RI p^ RIpRV n        RV n        VP	                  4         VP                  R4      P                  ^ 4       R#   \         d     R# i ; i)a^  
v9: Fully release booster memory after save() so the OS reclaims it.

The problem: LightGBM allocates at the C level (glibc heap). Python's
gc.collect() and even lgb.free_dataset() don't return those pages to
the OS -- glibc holds them in its own pool for reuse. After training
32 agents sequentially this leaves 6+ GB of unreturned heap even though
the Python objects are gone.

The fix:
  1. Null lgb_clf/lgb_reg entirely -- Python releases its reference
  2. gc.collect() -- frees Python-level cyclic refs
  3. malloc_trim(0) via ctypes -- tells glibc to return free heap pages
     back to the OS immediately. This is the key step. Without it the
     RSS stays high even after gc.collect().

The booster is reloaded from pkl on the next predict() call or the
next training cycle's init_model. The pkl on disk is the source of
truth -- nulling RAM is safe.
N	libc.so.6)rj  ctypesr  r  rk  CDLLmalloc_trimrX   )r   rj  r5  s   &  r   release_training_data StockModel.release_training_data  sL    * 	


	KK$003 		s    A
 
AAc                    < V ^8  d   QhRS[ /# r6   rO  )r;   r   s   "r   r<   r    s      C r   c                n    \         '       d)   V P                  e   V P                  P                  4       # ^ # )zFTotal trees in the LightGBM model. Grows with each incremental update.)r  r  	num_treesr4  s   &r   
tree_countStockModel.tree_count  s(     6dll.<<))++r   c                &   < V ^8  d   QhRS[ RS[/# )r7   all_featuresr8   r  )r;   r   s   "r   r<   r    s     . .D .T .r   c                h   V P                   p\        P                  RV P                   RV R\         R\        V4       R2	4       V P                  pV P                  pRV n        RV n        V P                  V4      pV'       g2   W0n        W@n        \        P                  RV P                   R24       R# V P                   p\        P                  RV P                   R	V R
V RV P                  R RV P                  4       R 2
4       \        P                  RV P                   RV RV 24       R# )aI  
v9: Monthly distillation -- compact the accumulated trees.

When tree_count exceeds DISTILL_THRESHOLD (~44 days of growth):
1. Train a fresh 300-tree model on ALL historical feature data
2. This compact model encodes everything seen so far, efficiently
3. Daily incremental updates resume on top of the compact base
4. The agent 'evolves' -- same knowledge, leaner structure, room to grow

Over years this creates models with genuine multi-year market understanding.
Each distillation cycle is smarter than the last because the training
dataset grows richer with every passing month.
r  z%] DISTILLATION START | current_trees=z | threshold=z | training on  symbolsNz'] DISTILLATION FAILED -- kept old modelFz] DISTILLATION COMPLETE | z
 trees -> z (compact) | val=r>  r  zDISTILL_DONE | z | old_trees=z | new_trees=T)r=  r   r   r  DISTILL_THRESHOLDr   r  r  r  r   r  r  r   )r   r@  	old_count	saved_clf	saved_regr  	new_counts   &&     r   distillStockModel.distill  s4    OO	$)) &K}5F4G H|,-X7	
 LL	LL	 **\*$L$LNNS+RSTOO	$))6kI; /<<$D):3(?A	

 	dii[ )"==	
 r   c                &   < V ^8  d   QhRS[ RS[/# )r7   r  r8   )r   r  )r;   r   s   "r   r<   r    s     4 4C 4 4r   c                    \        V P                  4      ^8  d   R# \        \        P                  ! V P                  V) R 4      4      # )z@Rolling Information Coefficient -- key metric for agent pruning.r   N)r   r  r  r  r  )r   r  s   &&r   r  StockModel.rolling_ic  s7    t!#RWWT__aRS1233r   c                @   < V ^8  d   QhRS[ P                  RS[RS[/# )r7   current_proban_binsr8   )r  ndarrayr   r  )r;   r   s   "r   r<   r    s&       S % r   c           	        \        V P                  4      ^28  g   \        V4      ^
8  d   R#  \        P                  ! ^ ^V^,           4      p\        P                  ! V P                  VR7      ^ ,          \        V P                  4      ,          p\        P                  ! WR7      ^ ,          \        V4      ,          p\        P
                  ! VRR4      p\        P
                  ! VRR4      p\        \        P                  ! WT,
          \        P                  ! WT,          4      ,          4      4      #   \         d     R# i ; i)z
Population Stability Index -- detects prediction distribution drift.
PSI < 0.10: stable | 0.10-0.25: investigate | > 0.25: retrain now
r   )binsg-C6?N)
r   r  r  linspace	histogramr  r  rT  r  rX   )r   rN  rO  rR  r  currs   &&&   r   compute_psiStockModel.compute_psi  s    
 t''(2-]1Cb1H	;;q!VaZ0D<< 8 8tDQG#dNfNfJggD<<DQG#mJ\\D774t,D774t,Dt{0C CDEE 		s   DD4 4EEc                4   < V ^8  d   QhRS[ P                  /# )r7   rn  r  rP  )r;   r   s   "r   r<   r  '  s       r   c                   V P                   '       g   R	#  V P                  P                  VP                  ^R
4      4      P	                  \
        P                  4      p\        '       dt   V P                  ef   \        V P                  P                  V4      ^ ,          4      p\        V P                  P                  V4      ^ ,          4      pVR8  d   ^M^ pWTV3# V P                  e   \        V P                  P                  V4      ^ ,          4      p\        V P                  P                  V4      ^ ,          4      p\        \
        P                  ! V P                  P!                  V4      ^ ,          4      4      pWTV3# R	#   \"         dg   pR\%        T4      9   dQ   \'        T P                  RR4      p\(        P+                  RT P,                   RT R\/        T4       R24       R	u R p?# h R p?ii ; i)Nr2   r  n_features_in_?[z] Feature mismatch (model=z
 vs input=z() -- neutral. Delete models/ to retrain.)NNNr  )r  r  	transformreshaper  r  r}  r  r  r  r  r  r  r   r  r  predict_probar  r:   r}  r   r   r  r   )r   rn  xscfpctr  r   n_exps   &&      r   r  StockModel.predict'  s   |||##	&&qyyB'78??

KBv$,,2DLL004Q78DLL004Q788arz!%$((**2.q12DHH,,R034BFF488#9#9"#=a#@ABrz!## 	SV#-=sC$$		{"<UG:cRSfX V= >? ('	s2   CF B&F F G7AG2+G71G22G7c                4   < V ^8  d   QhRS[ P                  /# )r7   feat_matrixrY  )r;   r   s   "r   r<   r  @  s       r   c                   \        V4      p\        P                  ! V\        P                  R7      p\        P                  ! VR\        P
                  R7      pV P                  '       g   W43#  VP                  ^,          \        8w  d   W43# V P                  P                  V4      P                  \        P
                  4      p\        '       dk   V P                  e]   V P                  P                  V4      P                  \        P
                  4      pVR8  P                  \        P                  4      V3# V P                  ef   V P                  P!                  V4      pVR,          P                  \        P
                  4      pVR8  P                  \        P                  4      V3# W43#   \"         d&   p\$        P'                  RT 24       Y43u Rp?# Rp?ii ; i)zv
v9: Batch predict -- all symbols in one C call.
LightGBM releases GIL during predict(), safe for ThreadPoolExecutor.
rz  r2   NzPREDICT_BATCH_ERR | r  r  )r   r  r  int8r~  r}  r  shape
N_FEATURESr  r^  r  r  r  r  r  r`  rX   r   r   )	r   rg  r  _zd_zcscrb  prr   s	   &&       r   predict_batchStockModel.predict_batch@  s_   
 +hhq(ggaBJJ/|||8O	  #z1x&&{3::2::FBv$,,2\\))"-44RZZ@S((1255%XX++B/X__RZZ0S((12558O 	!5aS9:8O	s9   /F2 AF2 A)F2 <A2F2 /F2 2G"=GG"G"c                &   < V ^8  d   QhRS[ RS[ /# )r7   r&  
actual_pctr  )r;   r   s   "r   r<   r  Z  s     V VE Vu Vr   c                D    V P                   P                  R VRV/4       R# )r&  rt  N)r  rS   )r   r&  rt  s   &&&r   r  StockModel.recordZ  s    

?M<TUr   c                    V P                   '       g   R # V P                    Uu. uF*  p\        VR,          VR,          ,
          4      R,          NK,  	  pp\        \        P                  ! V4      4      # u upi Nr&  rt  rv  r  r  r  r  r  )r   r[   diffss   &  r   avg_discrepancyStockModel.avg_discrepancy]  sZ    zzzLPJJWJqQ'!L/9:UBBJWRWWU^$$ Xs   0A4c                    < V ^8  d   QhRS[ /# )r7   r  rO  )r;   r   s   "r   r<   r  c  s     % %C %r   c                    V P                   '       g   R # V P                   V) R  pV Uu. uF*  p\        VR,          VR,          ,
          4      R,          NK,  	  pp\        \        P                  ! V4      4      # u upi rx  ry  )r   r  rz  r[   rz  s   &&   r   last_n_discrepancyStockModel.last_n_discrepancyc  sg    zzzQBCMSTV#a(1\?:;eCCVTRWWU^$$ Us   0A:c                   \         P                  P                  \        V P                   R 24      p\
        P                  ! RV P                  RV P                  RV P                  RV P                  RV P                  RV P                  RV P                  RV P                  R	V P                  R
V P                   RV P"                  RV P$                  RV P&                  /V4       R# )r   r  r  r  r  r  r  r  var  r  feat_imptrain_countpred_baselineN)rT   rU   r   r   r  joblibdumpr  r  r  r  r  r  r  r  r  r  r  r  r  r  s   & r   saveStockModel.savej  s    ww||Ntyyk,>?T\\T\\TXXTXXT[[T\\T^^T\\TZZT__T11T..T55
 	r   c                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r  |  s      d r   c                B   \         P                  P                  \        V P                   R 24      p\         P                  P                  V4      '       g   R#  \        P                  ! V4      pVP                  R4      V n	        VP                  R4      V n
        VP                  R4      V n        VP                  R4      V n        VR,          V n        VR,          V n        VR,          V n        VR	,          V n        VP                  R
. 4      V n        VP                  R. 4      V n        VP                  R/ 4      V n        VP                  R^4      V n        VP                  R\*        P,                  ! . 4      4      V n        \0        P3                  RV P                   RV P                   R RV P5                  4       R RV P(                   R2	4       V P                  #   \6         d1   p\0        P9                  RT P                   RT 24        Rp?R# Rp?ii ; i)r   Fr  r  r  r  r  r  r  r  r  r  r  r  r  r  z] Loaded (val=r>  r  z train_count=r  z] Load error: N)rT   rU   r   r   r  rV   r  loadr@  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r  rX   r   )r   rU   r  r   s   &   r   r  StockModel.load|  s   ww||Ntyyk,>?ww~~d##	D!A()i(8DL()i(8DL()eDH()eDH()(DK())DL()$DN()$DL()gr(:DJ()lB(?DO()j"(=D ()mQ(?D()orxx|(LD$KKdii[t||C.@ Aoo',M$:K:K9LAOP << 	NNS>!=>	s   FG# #H.%HH)r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r	  )r  )r   )r   r   r   r   r
  r  r  r  r  r8  propertyr=  rH  r  rV  r  rq  r  r{  r  r  r  r   r   r   s   @r   r  r    s     	*' *'X
 
  i iV!F  . .`4 4 " 2 4V V%% %$ r   r  c                      a a ] tR tRt oV 3R ltV3R lR ltV3R lR ltV3R lR ltV3R	 lR
 ltR tV3R lR lt	Rt
VtV ;t# )MetaLearneri  c                4   < \         SV `  R 4       / V n        R# )r  N)superr  profitable_symbols)r   	__class__s   &r   r  MetaLearner.__init__  s    '(*r   c                    < V ^8  d   QhRS[ /# )r7   agentsrF   )r;   r   s   "r   r<   MetaLearner.__annotate__  s     ) )4 )r   c                    / pV FO  pVP                    F<  pVR ,          ^ 8  g   K  VP                  VR,          ^ 4      ^,           W$R,          &   K>  	  KQ  	  W n        R# )r$  r   N)historyr@  r  )r   r  r.  r8  rR  s   &&   r   absorb_agent_history MetaLearner.absorb_agent_history  sR    AYYU8a<*0**Qx[!*Dq*HFX;'   #)r   c                &   < V ^8  d   QhRS[ RS[ /# )r7   r  r8   r5  )r;   r   s   "r   r<   r    s      d t r   c                    / pV F;  pV P                   P                  V^ 4      pR\        V^4      R,          ,           W#&   K=  	  V# )r  rf   )r  r@  r  )r   r  r\  r  r/  s   &&   r   build_weightsMetaLearner.build_weights  sG    C))--c15CS!s!22GL  r   c                &   < V ^8  d   QhRS[ RS[/# )r7   r  r  rG   r6  )r;   r   s   "r   r<   r    s     	 	$ 	$ 	r   c                  a V P                  V4       V P                  V4      o\        R  SP                  4        4       4      p\	        SV3R lR7       Uu. uF  pSV,          R8  g   K  VSV,          3NK   	  upR,          p\
        P                  RV R24       V'       d3   \
        P                  RRP                  R	 V 4       4      ,           4       V P                  VSR
7       V P                  4        R# u upi )c              3   6   "   T F  qR 8  g   K  ^x  K  	  R# 5i)rf   Nr   r   r  s   & r   r   2MetaLearner.retrain_from_agents.<locals>.<genexpr>  s     <jG11js   
c                    < SV ,          ) # r	  r   )rn  r  s   &r   ro  1MetaLearner.retrain_from_agents.<locals>.<lambda>  s    qter   ry  rf   Nr   Nz  MetaLearner: z profitable symbols boostedz    Top boosts: r   c              3   6   "   T F  w  rV R VR 2x  K  	  R# 5i)rn  .0fNr   )r   r  r  s   &  r   r   r    s      7[SZ411#QqgSZrO  r\  N)
r  r  rT  r  rQ   r   r   r   r  r  )r   r  r  n_profitabler  boostedr  s   &&&   @r   retrain_from_agentsMetaLearner.retrain_from_agents  s    !!&)x(<ahhj<<&,QO&DS&D!s
9Aqt9&DSTWXol^3NOPKK*UZZ7[SZ7[-[[\

8Q
'		 Ts   C=,C=c                N   < V ^8  d   QhRS[ P                  RS[ P                  /# )r7   rg  r8   rY  )r;   r   s   "r   r<   r    s#     	? 	? 	?

 	?r   c                   V P                   '       d   V P                  f0   \        P                  ! \	        V4      \        P
                  R7      #  V P                  P                  V4      pV P                  P                  V4      pVR,          P                  \        P
                  4      #   \         d3    \        P                  ! \	        T4      \        P
                  R7      u # i ; i)zBBatch meta-confidence for all symbols. Returns shape (n_symbols,).rz  ri  )r  r  r  onesr   r}  r  r^  r`  r  rX   )r   rg  scaledprobas   &&  r   rq  MetaLearner.predict_batch  s    |||txx/773{+2::>>	?[[**;7FXX++F3E;%%bjj11 	?773{+2::>>	?s   AB- -:C*)C*c                   V P                   '       d   V P                  f1   \        P                  ! \	        V4      R\        P
                  R7      #  V P                  P                  V4      pV P                  P                  V4      R,          P                  \        P
                  4      #   \         d3    \        P                  ! \	        T4      \        P
                  R7      u # i ; i)Nr2   rz  ri  )r  r  r  r~  r   r}  r  r^  r`  r  rX   r  )r   rg  ro  s   && r   rq  r    s    |||txx/773{+S

CC	?&&{3B88))"-d3::2::FF 	?773{+2::>>	?s   AB, ,:C)(C)c                :   < V ^8  d   QhRS[ P                  RS[/# )r7   rn  r8   )r  rP  r  )r;   r   s   "r   r<   r    s     - - - -r   c                b    V P                   '       g   R # V P                  V4      w   r#Ve   V# R # r2   )r  r  )r   rn  r>   rb  s   &&  r   meta_confidenceMetaLearner.meta_confidence  s0     |||<<?1^r,,r   )r  )r   r   r   r   r  r  r  r  rq  r  r   r   __classcell__)r  r   s   @@r   r  r    sF     +) ) 	 		? 	??- - -r   r  c                 R    V w  rpVP                  W#4       VP                  4        V# r	  )r  r  )argsmodelr  r\  s   &   r   
_train_oner    s&    #EW	KK"	JJLLr   c                <    V ^8  d   QhR\         R\        R\        /# )r7   rq   r  r\  r  )r;   s   "r   r<   r<     s!     -/ -/4 -/4 -/$ -/r   c           
         \         P                  4        \        \        V 4      \         P                  4      p\
        P                  R \        V 4       RV R24       \        P                  R\        V 4       RV R\         P                  4        24       V  Uu. uF  qDW3NK  	  pp\        e   \        V\        \        4      pM\        V\        4      p\        VR7      ;_uu_ 4       p\        V4       UU	u/ uF  w  rVP                  \        V	4      VbK  	  p
pp	R.\        V4      ,          p\        V
4       F  pW,          p VP!                  4       W&   K   	  RRR4       \'        V X4       F  w  ppVf   K  \(        '       dh   VP*                  Vn        VP,                  Vn        VP.                  Vn        VP0                  Vn        VP2                  Vn        VP4                  Vn        M"VP6                  Vn        VP8                  Vn        VP:                  Vn        VP<                  Vn        VP>                  Vn        VP@                  Vn         K  	  \
        P                  R	4       R# u upi u up	pi   \"         d,   p\        P%                  RT RT 24       RY&    Rp?EKr  Rp?ii ; i  + '       g   i     ELa; i)
zParallel training z models on z processes...zPARALLEL_TRAIN_START | models=z | n_procs=r   Nmax_workerszTRAIN_THREAD_ERR | idx=zParallel training complete.)!_proc_allocrefresh_avail_ramr  r   training_procsr   r   r   r  MAX_WORKERS_CAP_dynamic_workersr   r  submitr  r   r  rX   r   rY  r  r  r  r  r  r  r  r  r  r  r  r  r  )rq   r  r\  n_safer  r  effective_workerspoolr  r8  futurestrained_resultsfutrC  r   origr  s   &&&              r   parallel_trainr    sC   !!#Vk889F
KK$S[MVHMRS
(V 6(#k0023	5 066v!8%vD6 "(8/J(89	(9	:	:d=Ft_M_TQ4;;z1-q0_M&3t9,(C,C,'*zz|$ ) 
; FO4f>6%~~DL%~~DL%00DO#)#9#9D #)#6#6D'-'A'AD$zzDHvzzDH))&..4< 5 KK-.K 7 N  ,""%<SEQC#HI'+$$, 
;	:	:sN   I2*J69"I7
,J6I=J67J6=J3	J.	'J6.J3	3J66K	c                   @   a  ] tR tRt o RtR	R ltR tR tR tRt	V t
R# )
Positionrc   c                B    Wn         W n        W0n        W@n        WPn        R # r	  r   r!  r;  r   r&  r   r   r!  r;  r   r&  s   &&&&&&r   r  Position.__init__      ##"
*r   c                H    WP                   ,
          V P                  ,          # r	  r;  r!  r  s   &&r   r$  Position.pnl  s    !jj.DKK!??r   c                B    WP                   ,          ^,
          ^d,          # r  r;  r  s   &&r   r%  Position.pnl_pct  s    !jj.1"4!;;r   c                (    V P                   V,          # r	  )r!  r  s   &&r   valuePosition.value  s    q0r   r;  r&  r!  r   r   Nr  r   )r   r   r   r   	__slots__r  r$  r%  r  r   r   r   s   @r   r  r    s     @I+ @;00r   r  c                   J   a  ] tR tRt o RtR
tRR ltR tR tR t	R t
RtV tR	# )ShortPositioni  zA short (borrowed-and-sold) position.
Profit = entry_price - current_price (inverse of long).
Stored in agent.short_positions dict, parallel to agent.positions (longs).
Capital locked = entry_price * shares (the proceeds from the short sale).
c                B    Wn         W n        W0n        W@n        WPn        R # r	  r  r  s   &&&&&&r   r  ShortPosition.__init__#  r  r   c                J    V P                   V,
          V P                  ,          # r	  r  r  s   &&r   r$  ShortPosition.pnl)  s    $**q.DKK!??r   c                D    V P                   V,          ^,
          ^d,          # r  r  r  s   &&r   r%  ShortPosition.pnl_pct*  s    $**q.1"4!;;r   c                <    V P                   V P                  ,          # r	  r  r  s   &&r   r  ShortPosition.value+  s    dkk!99r   c                B    WP                   ,          ^,
          ^d,          # r  r  r  s   &&r   risk_pctShortPosition.risk_pct,  s    1zz>A#5"<<r   r  Nr  r  )r   r   r   r   r
  r  r  r$  r%  r  r  r   r   r   s   @r   r  r    s)     
 AI+ @;9<<r   r  c                   H   a  ] tR tRt o RtRt. t/ tV 3R lR ltR t	Rt
V tR# )	_NeutralMetai0  z
Dummy meta for the MetaLearner's own TradingAgent.
The MetaLearner is its own model, so it doesn't need an external meta.
Returns 0.5 (neutral) so the agent trades purely on its own signal.
Effect: eff_cf = cf * 0.7 + 0.5 * 0.3 = cf * 0.7 + 0.15
Tc                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   _NeutralMeta.__annotate__;  s      E r   c                    R # r  r   )r   rn  s   &&r   r  _NeutralMeta.meta_confidence;  s    r   c                X    ^ RI pVP                  \        V4      RVP                  R7      # )r  Nr2   rz  )numpyr~  r   r}  )r   rg  _nps   && r   rq  _NeutralMeta.predict_batch>  s#    xxK(#S[[xAAr   r   N)r   r   r   r   r
  r  r  r  r  rq  r   r   r   s   @r   r  r  0  s2      GE B Br   r  c                   j  a  ] tR tRt o V 3R lR ltV 3R lR ltV 3R lR ltV 3R lR	 ltV 3R
 lR ltR&V 3R lR llt	V 3R lR lt
R'V 3R lR lltR(V 3R lR lltR)V 3R lR lltR(V 3R lR lltV 3R lR ltV 3R lR ltV 3R lR ltR*V 3R lR  lltV 3R! lR" ltV 3R# lR$ ltR%tV tR# )+TradingAgentiC  c                ,   < V ^8  d   QhRS[ RS[RS[/# )r7   r  r  meta)r6  r  r  )r;   r   s   "r   r<   TradingAgent.__annotate__D  s"     %& %&D %& %&; %&r   c                h   VR ,          V n         VR,          V n        VR,          V n        VR,          V n        VP	                  RR4      V n        VP	                  RR4      V n        W n        W0n        \        V n
        / V n        / V n        . V n        ^ V n        ^ V n        ^ V n        RV n        RV n        RV n        RV n        ^ V n        ^ V n        RV n        / V n        / V n        / V n        \6        V n        \:        V n        \>        V n         ^ V n!        ^ V n"        RV n#        RV n$        / V n%        R	# )
r  r  r  r  r  ?r  Fr   N)&r  risk_tolmax_pos_pctmin_confr@  tp_multr  r  r  STARTING_CAPITALcapital	positionsshort_positionsr  resetsr(  winsr)  r*  short_gross_profitshort_gross_lossshort_trades
short_wins	total_pnl
_last_sold_pending_predicted_pending_confsDEFAULT_STOP_LOSS_PCTr  DEFAULT_TAKE_PROFIT_PCTr  DEFAULT_MAX_POSITIONSmax_positions_kelly_wins_kelly_losses_kelly_avg_win_kelly_avg_loss_position_atr)r   r  r  r  s   &&&&r   r  TradingAgent.__init__D  s$   K	 01 23 01GG$6<GGJ6!
 	,%'%'%'	"%"%"%"%"#"#!#(*(*464 !" ! # ##%r   c                    < V ^8  d   QhRS[ /# r6   r5  )r;   r   s   "r   r<   r  k  s     
 
 
r   c           
     ~    R V P                   RV P                  RV P                  RV P                  RV P                  /# r  r  r  r	  r  r%  r4  s   &r   r  TradingAgent.paramsk  sA    t11t33t11t}}t//
 	
r   c                   < V ^8  d   QhRR/# )r7   donorr  r   )r;   r   s   "r   r<   r  t  s     5 5. 5r   c                   a \         oV3R  lpV! V P                  VP                  .\        O5!  V n        V! V P                  VP                  .\        O5!  V n        \        V! V P                  VP                  .\        O5!  4      V n        V! V P                  VP                  .\        O5!  V n        V! V P                  VP                  .\        O5!  V n
        V P                  '       d   \        V P                  R4      V n        R# R# )c           
      V   < \        V\        W0SW,
          ,          ,           4      4      # r	  )r  r  )curtgtr  r  r  s   &&&&r   nudge(TradingAgent.adopt_params.<locals>.nudgev  s!    r3rsy)9#9:;;r   r  N)PARAM_LEARNING_RATEr  r  r  r  r  r  MAX_POSITIONS_RANGEr	  r  r  r  r  r  )r   r(  r-  r  s   && @r   adopt_paramsTradingAgent.adopt_paramst  s     	<$T%7%75;N;NcSbc$T%9%95;P;PeSde$U4+=+=u?R?R%iUh%ij$T]]ENNcTbc$T%5%5E<M<MfTef ===t4DM r   c                &   < V ^8  d   QhRS[ RS[/# r7   ri  r8   r6  r  )r;   r   s   "r   r<   r    s     
 
4 
E 
r   c                   a V P                   \        V3R  lV P                  P                  4        4       4      ,           # )c              3      <"   T F9  qP                  SP                  VP                  VP                  4      4      x  K;  	  R # 5ir	  )r  r@  r   r;  )r   r[   ri  s   & r   r   ,TradingAgent.total_equity.<locals>.<genexpr>  s2      "
<SqGGFJJqxx122<Ss   AA)r  rT  r  r  r   ri  s   &fr   total_equityTradingAgent.total_equity  s5    ||c "
<@NN<Q<Q<S"
 
 
 	
r   c                &   < V ^8  d   QhRS[ RS[/# r4  r5  )r;   r   s   "r   r<   r    s     L Lt L Lr   c                \    \        R RV P                  V4      \        ,          ,
          4      # )r   rf   )r  r:  r  r9  s   &&r   drawdownTradingAgent.drawdown  s%    3d//7:JJJKKr   c                F   < V ^8  d   QhRS[ RS[P                  RS[RS[/# )r7   r  rR  r  allow_short)r:   r  rP  r  r  )r;   r   s   "r   r<   r    s.     !6 !6# !6RZZ !6 !6 !6r   c                p   \        V P                  R4      '       dJ   \        V P                  P                  4      ^8  d&   V P                  P	                  4       \
        8  d   R
# V P                  P                  V4      w  rVpVf   R
# V P                  P                  V4      pVR,          VR,          ,           p	WP                  8  d   RRWxV	3# V^8X  d   WP                  9   d   RWgW3# RWgW3# V^ 8X  d9   WP                  9   d   RWgW3# WP                  9   d   RRWxV	3# V'       d   R	WgW3# RRWxV	3# )zDecide action for a symbol.
Returns: (action, predicted_pct, own_cf, meta_cf, eff_cf)
Actions: BUY, SELL, SHORT, COVER, HOLD
allow_short: if True, d==0 with no long position can trigger SHORT
r  HOLDr   ffffff?333333?COVERBUYr9  SHORT)rC  r   r   r   r   )r  r  r   r  r  IC_MIN_VOTE_THRESHOLDr  r  r  r	  r  r  )
r   r  rR  r  rA  r  rc  rb  meta_cfeffective_cfs
   &&&&&     r   decideTradingAgent.decide  s.    4::|,,TZZ5J5J1Kq1Pzz$$&)>>11ZZ''-
9--yy006Cx'C-/--'3\996***>>#7886nn$s==***sB==>>sB55r   c                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r    s     D D5 Dr   c                   V P                   V P                  ,           pV^
8  g   V P                  R8  d   V P                  # V P                   V,          pV P                  V,          pV P                  \	        V P
                  R4      ,          p\	        R\        WB,          V,
          V,          R4      4      pVR,          p\        RVR,          4      pWv,          RV,
          V P                  ,          ,           # )zGQuarter-Kelly position sizing. Falls back to max_pos_pct if <10 trades.ư>r   r2         @rf   r  )r  r  r  r  r  r   r  )r   r  win_rate	loss_rater  f_star	f_quarterblends   &       r   _fractional_kellyTradingAgent._fractional_kelly  s    t111r6T((4/###$$q(&&*	#d&:&:D"AAS!,":a!?EFSL	CT" C%K43C3C#CCCr   c                2   < V ^8  d   QhRS[ RS[RS[RS[/# )r7   r  r  r&  rD  r:   r  )r;   r   s   "r   r<   r    s*     
 
s 
5 
 
@E
r   c                <   WP                   9   g   V^ 8:  d   R# \        V P                   4      V P                  8  d   R# \        P                  ! 4       V P                  P                  V^ 4      ,
          \        8  d   R# V P                  4       p\        V P                  V,          V P                  R,          4      p	V	R8  d   R# W,          p
V ;P                  V	,          un	        \        WV\        P                  ! \        4      V4      V P                   V&   W0P                  V&   WEV3V P                  V&   \!        VR4      V P"                  V&   \$        P'                  RV P(                   RV RV
R R	VR
 RV^d,          R RVR RVR RVR RVR 24       R# )r  Nr3   rf   {Gzt?z  BUY  [r   r  r:  sh @$r   pred=r=  % own=r>   meta= eff=z kelly=)r  r   r  r   r  r@  BUY_COOLDOWN_SECSrW  r  r  r  r   rB   r  r  r  r  r!  r   r   r  )r   r  r  r&  r*  r+  r,  rD  
kelly_fracinvestr!  s   &&&&&&&&   r   buyTradingAgent.buy  sl   .. EQJt~~$"4"4499;,,S!447HH++-
T\\J.t0CDD='/UHLLQZD[]j'ks'4$(0X'FC '*7E':3tyykC5&U5+ F!#%d+6(3 @c?%~WZ<LN	
r   c                ,   < V ^8  d   QhRS[ RS[RS[ /# r7   r  r  r(  rZ  )r;   r   s   "r   r<   r    s"     3 3 3E 33 3r   c                   WP                   9  d   R # V P                   P                  V4      pVP                  V4      pVP                  V4      R,          pV ;P                  VP                  V4      ,          un        V ;P                  V,          un        V ;P                  ^,          un        V^ 8  d   V ;P                  ^,          un        V ;P                  V,          un	        V ;P                  ^,          un
        V P                  pV P                  V^,
          ,          \        V4      ,           V,          V n        M}V ;P                  \        V4      ,          un        V ;P                  ^,          un        V P                  pV P                  V^,
          ,          \        V4      ,           V,          V n        V P                   P                  VR 4       \"        P"                  ! 4       V P$                  V&   V P&                  P                  WP(                  4      p	V P*                  P                  VR 4      w  rpV P,                  P/                  W4       \        W,
          4      R,          p\1        \2        P4                  ! \6        4      VP8                  ,
          P;                  4       4      pRVRVP<                  RVRVP>                  RVRVP                  V4      RV	R,          R	VR
VRV P@                  RVRV
RVRV/pV PB                  PE                  V4       \F        PI                  RV P@                   RV RV RVR RVP                  V4      R RVR RV
R RVR 24       \K        / R\2        P4                  ! \6        4      PM                  R4      bRV P@                  bRRbRVbRVP>                  bRVP<                  bRVbRVbRVP                  V4      bRV	R,          bR	VbRVbR
VbRV
bRVbRVb4       R # )!Nrv  r   r;  r<  r!  r$  r%  r&  r'  r)  r  r(  r*  r+  r,  z  SELL [r   r   pnl=$r=  r   +.1f%) disc=r  pp own=r>  r`  r  r   r  r9  r   r   r   )'r  r  r$  r%  r  r  r  r(  r  r)  r  r  r  r*  r  r   r!  r   r  r  r&  r  r  r  r   r   rB   r  r   r  r;  r!  r  r  rS   r   r   rB  rC   )r   r  r  r(  posr$  rt  nwnlr&  own_cfrJ  eff_cfr'  r)  	trade_recs   &&&&            r   sellTradingAgent.sell  s   nn$^^'',WWU^[['%/
#))E**#!7II"I$!!!B#'#6#6"q&#ACH#LPR"RDOOs3x'O!###B$($8$8BF$Cc#h$NRT#TD sD) $		//33C9J9JK"&"5"5"9"9#"O

-423e;i03669HHJK	c7CIIvucjj%s{{5)]U2wYTYY&Wj&
	 	I&tyykC5& 2:RE 248 9C=s|6'#H	

 	 
X\\)4==>QR
TYY
(.
8@#
 SZZ
 *1#))
 >DU
 S	
 #,S[[-?	

 ]U2
 W
 '/
 9DY
 V
 &1'
 <Fv
 	r   c                ,   < V ^8  d   QhRS[ RS[RS[/# )r7   r  r  r&  rZ  )r;   r   s   "r   r<   r  	  s"     
 
 
U 
5 
r   c                   WP                   9   g   WP                  9   g   V^ 8:  d   R# \        V P                  4      \        V P                   4      ,           V P                  8  d   R# \        P                  ! 4       V P
                  P                  VR,           ^ 4      ,
          \        8  d   R# \        V P                  V P                  ,          V P                  R,          4      pV\        ,          pVR8  d   R# Wr,          pV ;P                  V,          un	        \        WV\        P                  ! \        4      V4      V P                   V&   W0P                   VR,           &   WEV3V P"                  VR,           &   \$        P'                  RV P(                   RV RVR	 R
VR RV^d,          R RVR RVR RVR 24       R# )a  Open a short position. We borrow shares and sell them,
hoping to buy them back cheaper. Profit = entry - exit price.
Locked capital = entry_price * shares (SHORT_CAPITAL_RATIO of normal).
STOP LOSS: cover if price rises SHORT_STOP_LOSS_PCT (5%) against us.
N_shortr3   rf   _sz	  SHORT [r   r  r:  r]  r  r^  r=  r_  r>  r`  ra  )r  r  r   r  r   r  r@  rb  r  r  r  SHORT_CAPITAL_RATIOr  r   rB   r  r  r  r   r   r  )	r   r  r  r&  r*  r+  r,  rd  r!  s	   &&&&&&&  r   shortTradingAgent.short	  s|    &&&#*?5A:t~~T%9%9!::d>P>PP99;,,S8^Q??BSST\\D$4$44dllT6IJ%%D=$1Y 7%
S! /<d
+/7H.MC$J'		{"SE6#,eE#; G!#%d+6(3 @c?%~7	
r   c                ,   < V ^8  d   QhRS[ RS[RS[ /# rh  rZ  )r;   r   s   "r   r<   r  (  s"     . . .U .C .r   c                   WP                   9  d   R# V P                   P                  V4      pVP                  V4      pVP                  V4      R,          pV ;P                  VP                  V4      V,           ,          un        V ;P                  V,          un        V ;P                  ^,          un        V^ 8  d4   V ;P                  ^,          un        V ;P                  V,          un	        M"V ;P                  \        V4      ,          un
        \        P                  ! 4       V P                  VR,           &   V P                  P                  VR,           VP                  4      pV P                   P                  VR,           R#4      w  rp
V P"                  P%                  Wv4       \        Wv,
          4      R,          p\'        \(        P*                  ! \,        4      VP.                  ,
          P1                  4       4      pRVRVP2                  RVRVP4                  R	VR
VP                  V4      RVR,          RVRVRV P6                  RVRVRV	RV
/pV P8                  P;                  V4       \<        P?                  RV P6                   RV RV RVR RVP                  V4      R RVR RVR RV	R 24       \A        / R\(        P*                  ! \,        4      PC                  R 4      bRV P6                  bR!R"bRVbRVP4                  bRVP2                  bRVbR	VbR
VP                  V4      bRVR,          bRVbRVbRVbRVbRV	bRV
b4       R# )$zmCover (close) a short position by buying back the borrowed shares.
Profit if price fell, loss if price rose.
Nrv  ry  rz  r   r;  r<  r!  r$  r%  r&  r'  r)  r  r(  r*  r+  r,  z	  COVER [r   r  rj  r=  r   rk  rl  r  rm  r>  r`  r  r   r  rF  rn  )"r  r  r$  r%  r  r  r  r  r  r  r  r  r   r  r  r&  r  r  r  r   r   rB   r  r   r  r;  r!  r  r  rS   r   r   rB  rC   )r   r  r  r(  ro  r$  rt  r&  rr  rJ  rs  r'  r)  rt  s   &&&&          r   coverTradingAgent.cover(  s3    ***))--c2WWU^[['%/
#))E*S00#Q7OOq(O##s*#!!s3x/!*.))+h'//33C$J@Q@QR"&"5"5"9"9#*o"V

-423e;i03669HHJK	c7CIIvucjj%s{{5)]U2wYTYY&Wj&
	 	I&		{"SE6( 3:RE 248 9C=s|6'#H	

 	 
X\\)4==>QR
TYY
(.
9A3
 SZZ
 *1#))
 >DU
 S	
 #,S[[-?	

 ]U2
 W
 '/
 9DY
 V
 &1'
 <Fv
 	r   c                    < V ^8  d   QhRS[ /# r7   ri  r5  )r;   r   s   "r   r<   r  X  s     8 8$ 8r   c                   \        V P                  4       EF  pVP                  V4      pV'       g   K  V P                  V,          P                  V4      pV P                  P                  W P
                  R ,          4      p\        VR ,          ^d,          V P
                  ^d,          4      p\        W`P
                  ^2,          4      pWG) 8  d   V P                  W#R4       K  W@P                  ^d,          V P                  ,          8  g   K  V P                  W#R4       EK  	  \        V P                  4       F  pVP                  V4      pV'       g   K  V P                  V,          pVP                  V4      p	VP                  V4      p
V	\        ^d,          8  d   V P                  W#R4       Ky  V
\        ^d,          8  g   K  V P                  W#R4       K  	  R# )rg   stop_loss_atrtake_profitshort_stop_lossshort_take_profitN)rG   r  r@  r%  r!  r  r  r  ru  r  r
  r  r  SHORT_STOP_LOSS_PCTr  SHORT_TAKE_PROFIT_PCT)r   ri  r  r[   rc  	entry_atratr_stop_pcteffective_stopro  riskr  s   &&         r   exit_checksTradingAgent.exit_checksX  sc   'C

3A..%--a0C ..2238J8JS8PQI	C# 5t7I7IC7OPL /A/AB/FGN_$		#/2++c1DLL@@		#-0 ( ,,-C

3A&&s+C<<?D;;q>D)C//

3#45-33

3#67 .r   c                    < V ^8  d   QhRS[ /# r  r5  )r;   r   s   "r   r<   r  t  s     
 
$ 
r   c                   V P                  V4      pV\        8  d   \        P                  R V P                   RVR R24       \
        V n        \        V P                  4       Fx  pV P                  P                  V4       \        P                  ! 4       V P                  V&   V P                  P                  VR4       V P                  P                  VR4       Kz  	  V ;P                  ^,          un        R# R# )r]  u   ] DRAWDOWN RESET — z.1%z lost.N)r>  DRAWDOWN_RESET_PCTr   r   r  r  r  rG   r  r  r   r  r  r  r  )r   ri  ddr  s   &&  r   check_resetTradingAgent.check_resett  s    ]]6"##NNQtyyk)>r#hfMN+DLDNN+""3''+yy{$''++C6##''T2	 ,
 KK1K $r   c                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r    s     ? ?U ?r   c                d    V P                   '       d   V P                  V P                   ,          # R # r  )r(  r  r4  s   &r   r'  TradingAgent.profit_rate  s"    *.+++tyy4;;&>3>r   Nc                &   < V ^8  d   QhRS[ RS[ /# r4  r5  )r;   r   s   "r   r<   r    s      
  
  
  
r   c                0   V P                   pV'       di   V P                  '       dW   V P                  P                  4        F7  w  r4VP                  W4P                  4      pW$P                  V4      ,          pK9  	  MTV P                  '       dC   V P                  P                  4        F$  pW$P                  VP                  4      ,          pK&  	  V P                  '       d   V P                  P                  4        Fa  w  r4V'       d   VP                  W4P                  4      MVP                  pW$P                  V4      VP                  V4      ,           ,          pKc  	  R\        V^4      RV P                  RV P                  RV P                  RV P                  RV P                  RV P                  RV P                   R	V P"                  R
V P$                  RV P&                  RV P(                  RV P*                  RV P,                  P.                  R. /# )a  
Save agent state. Capital saved as TOTAL EQUITY (cash + mark-to-market
value of open positions) so unrealized P&L is properly captured.
On load, positions are NOT restored -- agent starts clean with correct equity.
This prevents silent loss-forgiveness on bot restart.
r  r  r(  r  r  r)  r*  	last_soldr  r  r  r	  r  model_predspositions_closed_on_exit)r  r  r   r@  r;  r  r  r  r$  r  r  r(  r  r  r)  r*  r  r  r  r  r	  r  r  r  )r   ri  equityr  ro  r+  s   &&    r   
save_stateTradingAgent.save_state  s    dnnn NN002jjii0))C.( 3 ^^^~~,,.))CII.. /  006684:fjjii0		))C.3773<77 9 uVQ'dnndkk6499hD--|T__T//1BDDXDXT//T]]4++]DJJ<L<L&

 
	
r   c                    < V ^8  d   QhRS[ /# )r7   stater5  )r;   r   s   "r   r<   r    s     ? ? ?r   c                   VP                  R \        4      V n        VP                  RR4      V n        VP                  R^ 4      V n        VP                  R^ 4      V n        VP                  R^ 4      V n        VP                  RR4      V n        VP                  RR4      V n        VP                  R/ 4      P                  4        UUu/ uF  w  r#V\        V4      bK  	  uppV n        VP                  R	V P                  4      V n        VP                  R
V P                  4      V n        \        VP                  RV P                  4      4      V n        VP                  RV P                   4      V n        VP                  RV P"                  4      V n        VP                  R. 4      V P$                  n        \)        V P                  \        ^,          4      V n        R# u uppi )r  r  r   r(  r  r  r)  r*  r  r  r  r  r	  r  r  N)r@  r  r  r  r(  r  r  r)  r*  r   r  r  r  r  r   r  r	  r  r  r  r  )r   r  r  r  s   &&  r   
load_stateTradingAgent.load_state  so   "YYy7GH"YY{s;"YYx:"YYv:	"YYx:"YY~<"YY|<6;iiR6P6V6V6XY6Xdaaqk6XY$yyD<N<NO$yy):D<P<PQ"599_d>P>P#QR$yydmmL$yyd>N>NO$yyrB

 4<<)9A)=> Zs   	G c                &   < V ^8  d   QhRS[ RS[ /# r4  r5  )r;   r   s   "r   r<   r    s     
 
d 
t 
r   c                   V P                   P                  4       pV P                   P                  ^4      p/ RV P                  bRV P                  bR\        V P                  ^4      bR\        V P                  V4      ^4      bR\        V P                  ^4      bRV P                  bR\        V P                  4       ^4      bRVe   \        V^4      MR	bR
Ve   \        V^4      MR	bRV P                  bR\        V P                  4      bR\        V P                  V4      ^4      bRV P                  bRV P                   bRV P"                  bRV P$                  bR\        V P&                  ^4      bR\        V P(                  ^4      /C# )r  r  r  r  r  r$  r(  r'  r{  Nroll_discrepancyr  r  r>  	stop_lossr  max_posr	  r)  r*  )r  r{  r  r  r  r  r  r:  r  r(  r'  r  r   r  r>  r  r  r  r	  r)  r*  )r   ri  r&  rolls   &&  r   summaryTradingAgent.summary  s   zz))+zz,,R0
		

 dllA 6
 d&7&7&? C	

 dnna 8
 
 d&6&6&8! <
 $2BdA
 $2BdA
 
 DNN 3
 dmmF&;Q ?
  2 2
  4 4
  2 2
  !
" d&7&7 ;#
$ dooq 9%
 	
r   )!r   r  r  r  r  r  r  r!  r  r*  r)  r  r  r  r  r  r	  r  r  r  r  r  r  r  r  r  r  r  r  r  r
  r(  r  r  )r   r   r   r   r   )signal)r   r   r   r   r	  )r   r   r   r   r  r  r1  r:  r>  rL  rW  re  ru  r|  r  r  r  r'  r  r  r  r   r   r   s   @r   r  r  C  s     %& %&N
 
5 5
 

L L!6 !6FD D
 
23 3j
 
>. .`8 88
 
? ? 
  
D? ?(
 
r   r  c                <    V ^8  d   QhR\         R\        R\        /# )r7   r  r  r  rG   r  r6  )r;   s   "r   r<   r<     s&     &b &bD &b &bt &br   c                    \        V 4      ^8  d   R# VP                  W4       \        V R RR7      pV^ ,          P                  '       d   V^ ,          P                  ^ 8:  d   \
        P                  R4       R# \        ^\        V4      ^,          4      pVRV pW4R p\
        P                  RV R\        V4       R24       V^ ,          VR,          rVP                   U	u0 uF  qR	,          ^ 8  g   K  V	R
,          kK  	  p
p	V
'       d   V'       d   VP                  ^ 8  d   V Uu/ uF  qW9   d   RMRbK  	  ppVP                  P                  W,R7       VP                  P                  4        \
        P                  RVP                   RVP                   R\        V
4       R24       V Uu. uF  qP                  ^ 8  g   K  VNK  	  ppV'       g   \
        P                  R4       R# V F  p\        P                  ! V4      pVP!                  4       pVP#                  V4       VP!                  4       pV Uu. uF>  p\%        \'        VV,          4      \'        VV,          4      ,
          4      R8  g   K<  VNK@  	  ppV'       g   K  \
        P                  RVP                   RVP                   RRP)                  V4       24       K  	  R# u up	i u upi u upi u upi )r7   Nc                     V P                   # r	  r  r8  s   &r   ro  !share_knowledge.<locals>.<lambda>  s    !++r   Try  r   u9   Agent→agent share skipped — no profitable agents yet.zKnowledge share: top z agents -> z othersr$  r   g      @rf   r  z  ML share: [z] -> [z]  rB  u3     Param share skipped — no profitable top agents.MbP?z  Param share: [z]: , r  )r   r  rQ   r  r  r   r   r  r   r  r  r  r  r  r  choicer  r1  r  r  r   )r  r  r  rankedn_top
top_agents
bot_agentsbestworstrR  goodr  r  r8  profitable_topr  r(  old_pnew_pr  changeds   &&&                  r   share_knowledger    sR   
6{Q 	V. F 5tDF!9q	 3 3q 8PQQFq()EJJ
KK'wk#j/9J'RS)VBZ%!%>A5AKAhKKD>TYY]5=>X	s*X>(.mDII;fUZZLCI;hWX!+?A{{QaaN?JKn-5!#Ves5q?U58_+L'MPU'U11eV7KK*5::,fUZZLDIIV]L^K_`a  ?>
 @ Ws*   $K8K,K!7K&K&9K+K+c                0    V ^8  d   QhR\         R\        /# )r7   r  rh  )rG   r  )r;   s   "r   r<   r<     s     l3 l3D l3h l3r   c                   aI \        ^
4       \        P                  R4        ^ RIp\        P
                  ! \        4      P                  R4      p\        \        P                  ! 4       4      pV  Fn  pVP                  P                  4       pVf   K#  VP                  WEP                  WeP                  4       VP                  VP                   VP"                  4       Kp  	  V  Uu. uFp  pRVP                  RVP$                  RVP&                  RVP(                  RVP                  R	VP                  4       ^d,          R
VP                   RVP"                  /NKr  	  ppV'       g   R# \+        R V 4       4      p\+        R V 4       4      p	\+        R V 4       4      p
V	^ 8  d   W,          ^d,          M^ p\+        R V 4       4      p\+        R V 4       4      p\+        R V 4       4      pV^ 8  d	   W,          M
\-        R4      p\        P
                  ! \        4      P                  R4      pRRpp\.        P0                  ! ^^RVR7      w  ppVP3                  RV 2R^RRR7       VP4                   FY  pVP7                  V4       VP9                  R^	R7       VP:                  P=                  4        F  pVP?                  R4       K  	  K[  	  VR,          pVPA                  R4       V\-        R4      8w  d   VR  R!2MRpR"R#VR$ 2R%3R&R#VR' 2V^ 8  d   R(MR)3R*VR+ R,2V^28  d   R(MR)3R-TVR.8  d   R(MR)3R/\        V	4      R0 R13R2R#VR$ 2R(3R3R#VR$ 2R)3R4\C        V4       R13.p\E        V4       F^  w  pw  pppR5VR6,          ,
          pVPG                  R7VVVPH                  R8^R97       VPG                  RVVVPH                  V^RR:R;7       K`  	  VPK                  R<R^^R=7       VR,          p\M        VR> R?R@7      pVRA,          pV U u. uF  p V R,          PO                  RBRC4      NK  	  p!p V U u. uF  p V R,          NK  	  p"p V" U#u. uF  p#V#^ 8  d   R(MR)NK  	  p$p#VPQ                  \S        \C        V!4      4      V"V$RDRE7      p%VPU                  \S        \C        V!4      4      4       VPW                  V!^RRF7       VPY                  ^ R8RGRHRI7       VP[                  RJR8^	RK7       VPK                  RLR^^R=7       \]        V%V"4       Fw  w  p&p'V'^ 8  d   RMMRp(V'^ 8  d   RNMR:p)VPG                  V&P_                  4       V(,           V&Pa                  4       V&Pc                  4       ^,          ,           R#V'RO 2RPV)R1^RQ7       Ky  	  VR,          p\M        V U u. uF  p V R,          ^8  g   K  V NK  	  up RR R?R@7      p*V* U u. uF  p V R,          PO                  RBRC4      NK  	  p+p V* U u. uF  p V R	,          NK  	  p,p V, U-u. uF  p-V-^78  d   R(M
V-^28  d   R%MR)NK  	  p.p-VPQ                  \S        \C        V+4      4      V,V.RDRE7       VPY                  ^2R)^RHRSRT7       VPY                  ^7R(RURVRWRT7       VPU                  \S        \C        V+4      4      4       VPW                  V+^RRF7       VP[                  RXR8^	RK7       VPe                  ^ ^d4       VPK                  RYR^^R=7       VPg                  ^RVRRZ7       VR,          pVRR RRR1,          p/V/ U u. uF  p V R,          PO                  RBRC4      NK  	  p0p V/ U u. uF  p V R,          NK  	  p1p V1 U#u. uF  p#V#^ 8  d   R(MR)NK  	  p2p#VPQ                  \S        \C        V04      4      V1V2RDRE7      p3VPU                  \S        \C        V04      4      4       VPW                  V0^RRF7       VPY                  ^ R8RGRHRI7       VP[                  RJR8^	RK7       VPK                  R[R^^R=7       \]        V3V14       Fw  w  p&p'V'^ 8  d   RMRMp(V'^ 8  d   R:MRNp)VPG                  V&P_                  4       V(,           V&Pa                  4       V&Pc                  4       ^,          ,           R#V'RO 2RPV)R1^RQ7       Ky  	  \.        Ph                  ! . ROR\7       \j        Pl                  Po                  \p        R]V R^24      p4\.        Pr                  ! V4^xR_VR`7       \.        Pt                  ! V4       \v        Py                  RaV4 24       / p5V  FR  pVP{                  VP                  ^<Rb7      p6V6P|                  '       d   K4  V6P                  Rc4      V5VP                  &   KT  	  V5'       g   \v        Py                  Rd4       R# \C        V54      p7\        ^V74      p8VP                  V7V8,          4      p9\.        P                  ! V8^,          V9Re,          ^,           3VR7      p:V:P3                  RfV 2R^RRgR7       \.        P                  P                  P                  V9V8V:RURhRi7      p;\S        V74       Uu. uF+  pV:P                  V;VV8,          VV8,          3,          4      NK-  	  p<p\M        V5P                  4       4      p=\]        V<V=4       EF=  w  poIV5SI,          p6\        P                  ! V6Rc,          RjRk7      p>V6Rl,          P<                  ^d,          p?V6R,          P<                  p@VP7                  V4       VP9                  R^R7       VP:                  P=                  4        F  pVP?                  R4       K  	  \C        V?4      ^ 8X  g   V?R,          ^28  d   R(MR)pAVP                  V>V?VARmRn7       \C        V?4      ^8  dU   TP                  T>T?^2R6V? U#u. uF  p#V#^28  NK
  	  up#R(Ro7       TP                  T>T?^2R6V? U#u. uF  p#V#^28  NK
  	  up#R)Ro7       VP                  ^2R8RGRHRI7       VP                  ^ ^d4       VP                  RpXA^RK7       VP                  4       pBVBP                  V>X@R%RDRVRGRq7       VBP                  RrR%^RK7       VBP9                  R^R7       VBP:                  P=                  4        F  pVP?                  R4       K  	  \C        V?4      ^ 8  d   V?R,          Rs R,2MRtpC\C        X@4      ^ 8  d   \        X@R,          4      M^ pD\        VI3Ru lV 4       ^ 4      pER#VERO 2pFSIPO                  RBRC4      pG\        ;QJ d    VI3Rv lV  4       F  '       g   K   R?M	  RwM! VI3Rv lV  4       4      '       d   RxMRypHVPK                  XG VH RzXC R{XF R|XD 2RR}^R=7       VP                  P                  \.        P                  P                  P                  R~4      4       VP                  P                  ^R7       EK@  	  \S        \C        V=4      \C        V<4      4       F  pV<V,          P                  Rw4       K  	  \M        V= UIu. uFF  pI\C        V5VI,          4      ^ 8  g   K  XIV5VI,          Rl,          P                  R,          ^d,          3NKH  	  upIR R?R@7      pJVJ'       d<   V:PG                  RRRRPo                  R XJR,           4       4      ,           R8^RR7       \j        Pl                  Po                  \p        RV R^24      pK\.        Pr                  ! VK^xR_VR`7       \.        Pt                  ! V:4       \v        Py                  RVK 24       R# u upi u up i u up i u up#i u up i u up i u up i u up-i u up i u up i u up#i u upi u up#i u up#i u upIi )r   chart_generationN%Y%m%d_%H%Mr  r  r  r$  r(  rR  r)  r*  c              3   2   "   T F  qR ,          x  K  	  R# 5i)r$  Nr   r   r  s   & r   r   *generate_accuracy_chart.<locals>.<genexpr>'  s     4)Q%)   c              3   2   "   T F  qR ,          x  K  	  R# 5i)r(  Nr   r  s   & r   r   r  (  s     7Y(Yr  c              3   \   "   T F"  qR ,          VR,          ,          ^d,          x  K$  	  R# 5i)r(  rR  Nr   r  s   & r   r   r  )  s#     M9a(a
m3c999s   *,c              3   2   "   T F  qR ,          x  K  	  R# 5i)r  Nr   r  s   & r   r   r  +  s     8i)ir  c              3   2   "   T F  qR ,          x  K  	  R# 5i)r)  Nr   r  s   & r   r   r  ,  s     =9a.))9r  c              3   2   "   T F  qR ,          x  K  	  R# 5i)r*  Nr   r  s   & r   r   r  -  s     ;A,r  r  %Y-%m-%d %H:%M CSTz#0d1117z#161b22)figsize	facecolorzTrading System Overview -- whiteboldg\(\?)colorfontsize
fontweightygray)colors	labelsizez#30363doffr  rn  zTotal Capitalr  ,.2fz#74c0fczNet PnLz+,.2fz#51cf66z#ff6b6bzWin Rater  %zProfit Factorrf   zTotal Tradesr  z#e9ecefzGross Profitz
Gross LosszAgents Runningq=
ףp?Q?r  z#8b949e)r^  r  r  right)r^  r  r  r  hazPortfolio Summary)r  r  padc                     V R ,          # r$  r   rm  s   &r   ro  )generate_accuracy_chart.<locals>.<lambda>Z  s    AeHr   Tr  :N   Nr  C_r  )r  alpha)r  r  r2   --)r  	linewidth	linestylezNet PnL ($))r  r  zTop 8 Agents by ProfitrE  leftrk  center)r  r  r  r  c                     V R ,          # )rR  r   rm  s   &r   ro  r  n  s    !J-r   z50% break-even)r  r  r  r  rD  :z
55% targetzWin Rate (%)zWin Rate by Agent (>= 5 trades))r  
labelcolorr  	edgecolorzBottom 8 Agents by PnL)rect	overview_.pngtight)dpibbox_inchesr  zOverview chart saved -> )r.  r   z'Detail chart skipped -- no history yet.g      @zAgent Win Rate History -- gGz?r4   )figurehspacewspacer  )unitr'  rh   r  r  )r  r  r  zWin %)r  r  r  r  Tradesr  N/Ac              3   T   <"   T F  qR ,          S8X  g   K  VR,          x  K  	  R# 5i)r  r$  Nr   )r   r  r  s   & r   r   r    s"     KIq6d9J(!E((Is   ((c              3   h   <"   T F'  qP                   S8H  ;'       d    VP                  x  K)  	  R # 5ir	  )r  r  )r   r8  r  s   & r   r   r    s&     Mfvv~<<!**<fs   22F+r,   z
Win=z  PnL=z  n=g      @%H:%Mrotationc                     V ^,          # r  r   rm  s   &r   ro  r    s    adr   rt  r\  zWin rate ranking:  z  |  c              3   X   "   T F   w  rVP                  R R4       RVR R2x  K"  	  R# 5i)r  r  r  r  r  N)rR   )r   r  r  s   &  r   r   r    s4      /"-$! 8D12!Ac7!<"-   (*r  bottom)r  r  r  	accuracy_zDetail chart saved -> )r  r   )r  r  )r  r  g333333ӿ)r  r  )r  r  r  )r  r  r  gQ?)Yr   r   yield_p3mathr   rB   r   rC   r   r   r  r{  r+  r  r'  r(  r)  r*  r  r  r  rT  r  pltsubplotssuptitleflatset_facecolortick_paramsspinesr  set_edgecoloraxisr   r  r   	transAxes	set_titlerQ   rR   barhr  
set_yticksset_yticklabelsaxvline
set_xlabelrY  	get_widthget_y
get_heightset_xlimlegendtight_layoutrT   rU   r   r   savefigr  r   r   r0  r  r  r  ceilr  
matplotlibgridspecGridSpecadd_subplotr  r  to_datetimeplotfill_betweenaxhlineset_ylim
set_ylabeltwinxnextr   xaxisset_major_formatterdatesDateFormatterset_tick_paramsset_visibler  )Lr  rh  _mathnow_strts_nowr8  r&  	summariesr  total_trades
total_wins
overall_wrtotal_capitaltotal_gross_ptotal_gross_lprofit_factornow_cstBGPANELfig1axes1axspinepf_strmetricsr  r  r  r  y_possorted_agentstop8r  names8pnls8r[   colors8r  r  r$  offsetr  tradednames_wrwrsr  	colors_wrbottom8names_bpnls_bcolors_bbars_bfname1
agent_datahistn_agentscolsr
  fig2gs2axes2agent_namestimesprofitr(  wr_colorax2curr_wrn_trades	agent_pnlpnl_strr|  clone_mr  r  fname2sL   &&                                                                       `  r   generate_accuracy_chartrs	    s1   bM/0
 ll:&//>G$))+Fww&&(OOFFFD--/188NNALL:  	 ! 	

		#-	   	 4)44I7Y77LM9MMJ9E9IZ.4qJ8i88M=9==M;;;M7Dq7H]2eTYlMll:&//0DEG9B
 ,,q!XDKD%MM/y9"4  Ijj

f2YY%%'E	* (  
tBGGEN(5u(Ec"!$5F	qt 45C	q5 12#q.Yi	9	
3/q1$*Y		;	V'3.YI	?	L 1!4C	qt 45C	qt 45C	I/CG %.g$6  E5%q4x
eUbll" 	 	.
eUbllbV 	 	I	 %7 LL$GbaLH 
tB9*<dKM2D9=>Aai$/F> $%1ahhE%;@A5aAFy	15GA775V%uG37GDMM%F$%v9JJq	SDJAMM-y1M=LL)21LMe$SqdaxVW
&(#))+8H18L*LC:8)a 	 	Q % 
tB	>	1Qx[A-=QQ	>/?F;AB6a&	!!(D16HB'-.v!*vC.Q  2gR9YN  GGE#h- #YcGBJJra4GWJXJJrcSJUMM%H&'x!7;MM.	AM>KK3LL2'BTULVIIqVu	IR 
tBRS!$B$'G;BC7a&	!!(D17GC")*'Q%'F*<BCFqQ!V	2FHCWWU3w<(&WLFMM%G%&w':JJq	SDJAMM-y1M=LL)21LM'SqcaWV
&(#))+8H18L*LC:8)a 	 	Q ( /*WW\\*	'$&?@FKKCWCIIdO
KK*6(34
 J&&qvvR&8zzz!%!1!1$!7Jqvv 
 =>:H1hDzz(T/*Dzz4!8TCZ!^"<KDMM.wi8"4  INN##,,d4C - 9C Ho'% c!t)QX"567% 
 ' *+K{+DD!T
5m$++c1h&&

f2YY%%'E	* ( "%V!1VBZ25E9I
vX=v;?OOE62T4:";Fq17F";9  NOOE62T39":6a1r66":9  N


2Y#
F
As
gX:hhji3c 	 	+xy1=v3ZZ&&(E	* ) ,/v;?fRj%Q',/K!O3vbz?KIKQO		$'(LL403MfM333MfMMMCSU
ggYfWIVG9D
KCQ 	 	
 	$$S^^%9%9%G%G%PQ
  " -U ,X 3{#SZ0aU# 1  	? TC
4(8$9A$= 
@$
4 /44R83>	? 	?DF
 		$',, /"(+/ // "A( 	 	< WW\\*	'$&?@FKKCWCIIdO
KK(12i	F ?%A ?B. D*CP'& #<":>	?sg   &A6|4"|99|>}}1}"}.}}"}}!}&1}+,}0}5(}:.}:c                <    V ^8  d   QhR\         R\        R\        /# )r7   r  r  ri  r  )r;   s   "r   r<   r<     s!     < < <[ <$ <r   c                   \        ^4       \        P                  R4       V  Uu/ uF  qDP                  VP	                  V4      bK   	  ppV'       d   VP	                  V4      VR&   RVP
                  RVP                  /VR&   \        \        R4      ;_uu_ 4       p\        P                  ! WV^R7       RRR4       \        P                  R	\         24       R# u upi   + '       g   i     L3; i)
zESave agent state. Pass prices so open positions are marked to market.agent_state_saver  r  r  __meta__r  indentNzAgent state saved -> )r   r   r   r  r  r  r  r.  AGENT_STATE_FILEr~  r  r   r   )r  r  ri  
meta_agentr8  r  r   s   &&&&   r   save_all_agent_stater|	    s     bM/039:6aVVQ\\&))6E:)44V<m $**.BDD[D[\E*		$	$		%1% 
%
KK'(8'9:; ; 
%	$s   $CC  C0	c                0    V ^8  d   QhR\         R\        /# )r7   r  r  )rG   r  )r;   s   "r   r<   r<     s     ; ; ;[ ;r   c           
         \         P                  P                  \        4      '       g   \        P                  R 4       R#  \        \        4      ;_uu_ 4       p\        P                  ! V4      pRRR4       V  Fu  pVP                  X9   g   K  VP                  WEP                  ,          4       \        P                  RVP                   RVP                  R RVP                  R 24       Kw  	  V'       dQ   RX9   dJ   VP                  VR,          4       \        P                  RVP                  R RVP                  R 24       XP                  R	/ 4      pVP                  R
. 4      Vn        VP                  R/ 4      Vn        \        P                  R4       R#   + '       g   i     EL;; i  \          d$   p\        P#                  RT 24        Rp?R# Rp?ii ; i)u(   No saved agent state — starting fresh.Nr  z] Restored: capital=$r  rj  r=  r  z#  [MetaLearner] Restored: capital=$rw	  r  r  zAgent state loaded.zCould not load agent state: )rT   rU   rV   rz	  r   r   r.  r~  r  r  r  r  r  r@  r  r  rX   r   )r  r  r{	  r   	all_stater8  meta_sr   s   &&&     r   load_all_agent_stater	    so   77>>*++>?;"##q		!I $Avv"Yvv./c!&&)>qyyoVTUT_T_`dSefg 
 -94!!)M":;KK=j>P>PQT=UU[\f\p\pqu[vwxz2."(**Wb"9
"(**-A2"F)* $##  ;5aS9::;s>   F6 F"0F6 A*F6 ;B%F6 "F3	-	F6 6G$GG$c                H    V ^8  d   QhR\         R\         R\         R\         /# )r7   
total_barsn_symsn_featws_barsrO  )r;   s   "r   r<   r<     s0     P; P;s P;C P;(+P;69P;r   c                   \         P                  ! \        4      P                  R4      p\	        4       p\        4       pV'       d   RMR\        4       R,          R R2p^Hp	RV	,          p
RV	,          pRPR	 lpT
R
V 2RV 2T
RRTRV! VR,          ^d4       RVR,          R RVR,          R RVR,          R RVR,          R 2
RV! VR,          ^d4       RVR,          R RVR,          R RVR,          R R2	R V! VR!,          ^d4       RVR!,          R RVR",          R R#VR$,          R R%2	R&VR',           R(VR),           2RR*TR+VR, 2R-VR, 2R.VR, 2R/VR, 2R0T\        ^\        \        P                  ! 4       R1,          ;'       g    R4      4      ,          R2 R32RR4R5RV
R6V R72V
.p \        R8R94      ;_uu_ 4       pVP                  R:P                  V4      4       R;R;R;4       \        P                  R<4       R>VR?\        P                  ! 4       R@RARBRCRDVREVR)\$        RF\&        RGRHVRIVRJVRKV//	p \        RLR94      ;_uu_ 4       p\(        P*                  ! VV^RM7       R;R;R;4       \        P                  RN4       R;#   + '       g   i     L; i  \         d#   p\         P#                  R=T 24        R;p?LR;p?ii ; i  + '       g   i     Lj; i  \         d$   p\         P#                  ROT 24        R;p?R;# R;p?ii ; i)Qz
v9: Human-readable report for --collect-only mode.
Simpler than full trading report since no agents/trades to show.
Written to logs/human_report.txt + logs/claude_handoff.json hourly.
%Y-%m-%d %H:%M:%S CSTOPENCLOSED (opens in rc   r  h)=-c           	          \        \        V \        VR 4      ,          V,          4      4      pW5,          WBV,
          ,          ,           # rP  r   r  r  )r  mxr  r   r   filleds   &&&&& r   r  '_write_collect_only_report.<locals>.bar+  s5    U3R.234zAV,,,r   z'  TRADING BOT  --collect-only MODE  |  
  Market: r,     VM RESOURCES  CPU  cpu_pctr  5.1f%  load=load_1mr  r  load_5mload_15m  RAM  ram_pct%  ram_used_mbr  MB / ram_total_mbr    DSK  disk_pctdisk_used_gbGB / disk_total_gbGB  Threads: active_threads  |  Dynamic workers: dynamic_workersz  DATA COLLECTION STATUSz  Bars collected (session) : z>12,z  Bars in DB (all time)    : z  Symbols tracked          : z  Symbols ready to trade   : z  DB bar rate (approx)     : re   z>8,z/hrz5  MODE: Data collection only -- no trades being made.z4  Switch to --mode long when ready to begin trading.  Generated:   |  Bot: v9r   r  
Nz4Human report (collect-only) -> logs/human_report.txtzCOLLECT_HUMAN_REPORT_ERR | generated_atgenerated_tsbot_versionv9r  collect_onlymarket_openvm_resources
n_featuresru   bars_session
bars_total	n_symbolsn_tradeabler   rx	  z*Claude handoff -> logs/claude_handoff.jsonzCOLLECT_HANDOFF_ERR | r  u   █u   ░)r   rB   r   rC   _get_vm_resourcesr  r  r  r   r   r.  writer   r   r   rX   r   r   r  rl  r~  r  )dmr	  r	  r	  r	  rG	  resmkt_openmkt_strr  septhinr  linesr   r   handoffs   &&&&&            r   _write_collect_only_reportr	    sR    ||J'001HIG "CH!v):;M;OPT;TUX:YY['\G
A7C7D-
 	
1';
WI

#c)nS)*!C	N4+@ AIs#1S^C$8#j/#9N	P
#c)nS)*!C	N4+@}a
 c.&9!%<B	@
#c*oc*+1S_T,B#~s
#5_)=c(B"	F
c*+,,B3GXCYBZ[
"
'~6
'
4'89
't}5
't}5
'
c!SuATA\A\X\=]6^(^_b'ccfg
?>

y-;E@@)3//1GGDIIe$% 0JK 	7499;4>83+:WZVV	
G ;,c22aIIgq+ 3@A5 0/  @:1#>??@* 32  ;5aS9::;s`   (J <!I?J 2K K K ?J	
J J?J::J?K	K L K>>Lc                $    V ^8  d   QhR\         /# r6   r5  )r;   s   "r   r<   r<   o  s      4 r   c                    / p  \        R4      ;_uu_ 4       pVP                  4       P                  4       pRRR4       \        X^ ,          4      V R&   \        V^,          4      V R&   \        V^,          4      V R&   \	        V R,          \        \        ^4      ,          ^d,          ^4      V R&    \        R4      ;_uu_ 4       p\        R VP                  4       P                  4        4       4      pRRR4       \        XR	,          P                  4       ^ ,          4      R
,          V R&   \        VR,          P                  4       ^ ,          4      R
,          V R&   V R,          V R,          ,
          V R&   \	        V R,          \        V R,          ^4      ,          ^d,          ^4      V R&    ^ RIpVP                  R4      w  rVp\	        VR,          ^4      V R&   \	        VR,          ^4      V R&   \	        We,          ^d,          ^4      V R&   \        P                  ! 4       V R&   \         V R&   V #   + '       g   i     EL; i  \         d    T P                  R^ R^ R^ R^ /4        ELi ; i  + '       g   i     EL; i  \         d    T P                  R^ R^ R^ R^ /4        Li ; i  \         d    T P                  R^ R^ R^ /4        Li ; i)z?Read live VM resource stats from /proc for reports and handoff./proc/loadavgNr	  r	  r	  r	  rf  c              3   V   "   T F  pR V9   g   K  VP                  R 4      x  K!  	  R# 5ir  Nr   r   r  s   & r   r   $_get_vm_resources.<locals>.<genexpr>}  s$     N,AqSAXlaggcll,A   	))MemTotalr   r	  MemAvailableram_avail_mbr	  r	  r  g    eAr	  r	  r	  r	  r	  )r.  ri  r   r  r  r  PHYSICAL_CORESrX   updater6  
splitlinesr   r   
disk_usager  active_countr  )outr   partsmir   r  usedfrees           r   r	  r	  o  s{   
CN/""aFFHNN$E #a/Ia/Ia/JI^Q1G G# MqQI[/""aNAFFH,?,?,ANNB #!"Z."6"6"8";<DHN!"^"4":":"<Q"?@DHN!.1C4GGM#C$6S=PRS9T$TWZ$Z\]^IK"--c2T$US[!4O$TS[!4N$T\C%7;J '335C-CJ7 #""  N

Iq)Q
Ay!LMN #""  [

NA~q-IWXYZ[  K

OQ:qIJKsf   I H/A9I 0J /I.2B9J ,A J, /I 	:	I $I+*I+.I?	9	J $J)(J),"KKc                H    V ^8  d   QhR\         R\        R\        R\         /# )r7   r  r	  r  existing_linesrG   r  r  )r;   s   "r   r<   r<     s5     _A _A _A+ _A[ _A)-_Ar   c                   \         P                  ! \        4      P                  R4      p\	        4       p\        4       pV'       d   RMR\        4       R,          R R2pVP                  p^Hp	RV	,          p
RV	,          pRR	 lp. pVP                  V
4       VP                  R
V 24       VP                  RV 24       VP                  V
4       VP                  R4       VP                  R4       VP                  V4       V! VR,          ^d4      pV! VR,          ^d4      pV! VR,          ^d4      pVP                  RV RVR,          R RVR,          R RVR,          R RVR,          R 2
4       VP                  RV RVR,          R RVR,          R RVR,          R R 2	4       VP                  R!V RVR,          R RVR",          R R#VR$,          R R%2	4       VP                  R&VR',           R(VR),           24       \        R* V  4       4      p\        \        V 4      ,          pVV,           p\        R+ V  4       4      p\        R, V  4       4      pV\        V^4      ,          ^d,          pVP                  R4       VP                  R-4       VP                  V4       VP                  R.VR/ 24       VP                  R0VR/ 24       VP                  R1VR2 R3VV,          ^d,          R4 R524       VP                  R6VR7 R8VR R924       VP                  R:\        R; V  4       4      R7 24       VP                  R4       VP                  R<4       VP                  V4       VP                  R=R>R? RR@RA RRBRC RRDRE RRFRG RRHR7 RRIRA 24       VP                  R4       \        V 4      p\        VRJ RKRL7      pVRM,           EF@  pVP                  \        VP                   ^4      ,          ^d,          p\#        VP$                  RN4      '       d   VP$                  P'                  4       MROpVP(                  '       d   RPMRQpVP*                  ^ 8  d   RRMVP*                  ^ 8  d   RSMRTpTP                  R=VP,                  R? RVRU RV RVVP*                  RW RVRX RYVP                   RG RVRZ R\        VP.                  4      RA 2V\0        ^,          8  d   VP$                  P2                  '       d   R[MR,           4       EKC  	  \        V R\ R]7      R^,          pVP                  R4       VP                  R_4       VP                  V4       V F  p\#        VP$                  RN4      '       d   VP$                  P'                  4       MROpVP                  \        VP                   ^4      ,          ^d,          pVP                  R=VP,                  R? R`VP*                  RW RaVR RbVRc 24       K  	  . pV  F  pVP.                  P5                  4        Fh  w  p p!VP7                  V V!P8                  4      p"V!P;                  V"4      p#VP                  VP,                  V V!P8                  V"V#V!P<                  34       Kj  	  K  	  V'       d   VP                  R4       VP                  Rd\        V4       Re24       VP                  V4       VP                  R=R>R? RRfRg RRhRE RRiRE RRjRE RRkRE 24       VP                  R4       \        VRl RKRL7       F@  w  p$p p%p"p#p&V#^ 8  d   RRMRSp'VP                  R=V$R? RV Rg RmV%Rn RmV"Rn RV' V#Ro RYV&Rp 24       KB  	  \        V  U(U)u. uF  p(V(P>                  RRq  F  p)V)NK  	  K  	  up)p(Rr RKRL7      Rs,          p*V*'       d   VP                  R4       VP                  Rt4       VP                  V4       VP                  R=R>Ru RRfRg RRvRw RRxRG RRyRz 2
4       VP                  R4       V* Fi  p)V)R{,          ^ 8  d   RRMRSp'VP                  R=V)R|,          Ru RV)R},          Rg RV' RVV)R{,          R~ RV)R,          Ro RYV)P7                  RR4      Rz 24       Kk  	  \        V R R]7      p+\#        V+P$                  R4      '       d   V+P$                  P@                  '       d   \        V+P$                  P@                  P5                  4       R R]7      R,          p,VP                  R4       VP                  RV+P,                   R24       VP                  V4       V, F;  w  p-p.V! V.V,^ ,          ^,          ^R7      p/VP                  R=V-Ru RV/ RV.R 24       K=  	  VP                  R4       VP                  R4       VP                  V4       VP                  R=VPC                  4        24       TP                  R\#        VR4      '       d2   VPD                  '       d    \        VPD                  PF                  4      MR 24       VP                  R4       VP                  V
4       VP                  RV R24       VP                  V
4       RPI                  V4      p0Rp1 \K        V1R4      ;_uu_ 4       p2V2PM                  V04       RqRqRq4       \N        PQ                  RV1 24        \Y        WV4       Rq# u up)p(i   + '       g   i     L=; i  \R         d#   p3\T        PW                  RT3 24        Rqp3?3LPRqp3?3ii ; i  \R         d$   p4\T        PW                  RT4 24        Rqp4?4Rq# Rqp4?4ii ; i)z
v9: Write logs/human_report.txt -- clean, phone-readable report.
Covers: market status, VM health, agent rankings, active positions,
recent trades, top signals, feature importance leaders.
r	  r	  r	  rc   r  r	  r	  r	  c           	          \        \        V \        VR 4      ,          V,          4      4      pW5,          WBV,
          ,          ,           # r	  r	  )r  max_valwidthfillr  r	  s   &&&&& r   	bar_chart&_write_human_report.<locals>.bar_chart  s6    U3Wd!33e;<=}u777r   z  TRADING BOT REPORT  |  r	  r,   r	  r	  r	  r	  r	  r  r	  r	  r	  r  r  r	  r	  r	  r	  r	  r  r	  r	  r  r	  r	  r	  r	  r	  r	  r	  r	  r	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r  r   r8  s   & r   r   &_write_human_report.<locals>.<genexpr>  s     3Fq{{F   c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r(  r	  s   & r   r   r	    s     0Axxr	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r  r	  s   & r   r   r	    s     .v!vvvr	  z  PORTFOLIO SUMMARYz  Starting capital : $z>12,.2fz  Current equity   : $z  Net P&L          : $z>+12,.2f  (r=  %)z  Total trades     : >6z  |  Win rate: r  z  Active positions : c              3   L   "   T F  p\        VP                  4      x  K  	  R # 5ir	  r   r  r	  s   & r   r   r	    s     ,Nv!S-=-=v   "$z(  AGENT LEADERBOARD  (sorted by Net P&L)  Agent<22Type>4zNetP&L>10WinRate>8r	  >7ICPosc                     V P                   # r	  r  r  s   &r   ro  %_write_human_report.<locals>.<lambda>  s    q{{r   Tr  :Nr  Nr  r   ClonezBase    ▲   ▼   ─>5r  z>+9,.2fz>7.1fz% z>6.3fu    ⚠️LOW-ICc                 r    \        V P                  R 4      '       d   V P                  P                  4       # R# r  r   r  r  r  r  s   &r   ro  r
    s+    '!''S_B`B`!''*<*<*>*ifi*ir   r  r  z'  UNDERPERFORMERS  (pruning candidates)z  P&L=$z  WR=z%  IC=r>  z  ACTIVE POSITIONS  (z open)Sym<6EntryCurrentzP&L%Sharesc                     V ^,          # )   r   rm  s   &r   ro  r
    s    ]^_`]ar   r  z>7.2f>+6.1fz>8.3fNc                 &    V P                  R ^ 4      # )r   r  rR  s   &r   ro  r
    s    aeeD!nr   N   Nz  RECENT TRADESz<20zP&L>9zAct%Reasonz<15r$  r  r   >+8.2fr%  r(  c                 r    \        V P                  R 4      '       d   V P                  P                  4       # R# r	
  r

  r  s   &r   ro  r
    s+    7177T`CaCa177+=+=+?+jgj+jr   r  c                     V ^,          ) # r  r   rm  s   &r   ro  r
    s
    QqTEr   r  z  TOP FEATURES  (from r  )r	  r:  z  DATA COLLECTIONz  Sentiment symbols tracked: sentiment_enginer	  r	  r	  r	  r   r  zHuman report -> zHUMAN_REPORT_WRITE_ERR | zHTML_DASHBOARD_CALL_ERR | r	  z>  ------------------------------------------------------------zC  -----------------------------------------------------------------rx  )-r   rB   r   rC   r	  r  r  ri  rS   rT  r  r   r  rG   rQ   r  r(  r  r  r  r  r  r  r  rI  r  r   r@  r;  r%  r!  r  r  r  r
  r[  r   r.  r	  r   r   rX   r   r   _write_html_dashboard)5r  r	  r  r	  rG	  r	  r	  r	  ri  r  r	  r	  r	  r	  cpu_barram_bardsk_barr  total_startr:  r@	  rA	  rR  _all_agentsr  r  wrictyp	pnl_arrowr	  all_positionsr  ro  r+  r%  ag_namer;  r!  arrowr8  rR  recent_trades
best_agentfirR  impr  report_textreport_pathr   r   _hes5   &&&&                                                 r   _write_human_reportr1
    s
    ||J'001HIG "CH!v):;M;OPT;TUX:YY['\GyyF
A
'C7D8 E	LL	LL,WI67	LL:gY'(	LL 
LL	LL!"	LLI,GI,GJ-G	LL77)1S^D$9#i.QTAUUVWZ[dWefiVjjklopzl{|  lA  B  C	LL77)1S^D$9S=OPQ<RRWX[\jXklmWnnpqr	LL77)1S_T$:#c.>QRU=VV[\_`o\pqt[uuwxy	LL;s#3455KCPaLbKcde 3F33I#c&k1K*L000L.v..JL! 44s:H	LL	LL&'	LL	LL)+g)>?@	LL),w)?@A	LL))H)=S;AVWZAZ[_@``bcd	LL(b(9RUVWXY	LL(,Nv,N)Nr(RST 
LL	LL;<	LL	LL2gc]!F2;a~QynAhWY]Z[\`ac[ddefklneopq	LL!v,KK%:DIFSkkggBIIq))C/'.rxx'F'Fbhh!!#Cg'\\A-EBLL1<L5RW	Qs2ha	{!BLL3I%j299R."U1S5Fr4JL"$'<q'@"@RXXEUEUEU[]_	
  F ijkmnF	LL	LL:;	LL'.rxx'F'Fbhh!!#CggBIIq))C/r"''#gbll7-C5CPVWYZ]V^_`  M**,HC**S#)),Ckk#&G  "''3		3!TU - 
 R,S-?,@GHTr'#abz72,a	"~QvVXkYZ[cdfZghi_%9?Sako9p5GS%gv$q[EeELL2gc]!C82eE]"SKqQVPWX_`fWggijpqviwxy :q
 4FqAIIcdOqOF4$d 
M R&'Tr'#abz5*AfR[(SVXY_%AuX\EuELLQwZ$Aak"%5QugQqx>OqY<'r!%%*<S)AC  V!jkJz!233
8H8H8X8X8XJ$$44::</RSVWR-joo->a@ATID#CAq4CLL2d3ZqQs3i89 
 
LL	LL$%	LL	LL2bnn&'()	LL0T[\^`rTsTsxz  yL  yL  yLR5H5H5O5O1P  RW  1X  Y  Z	LL	LL	LL=	67	LL))E"K)K>+s##qGGK  $&{m45
Af$/g 	5V $#  >8<==>  A9#?@@AsN   +!k
k4 k!, k4 l$ !k1	,k4 4l!?ll!$m/mmc                @    V ^8  d   QhR\         R\        R\        RR/# )r7   r  r	  r  r8   Nr	  )r;   s   "r   r<   r<   3  s.     S: S:$ S:K S:{ S:t S:r   c           #     %  av ^ RI p^ RIp/ p \        P                  ! \	        R4      4      p. p \	        RRR7      ;_uu_ 4       p\        VP                  V4      4      pRRR4       / p \        P                  ! \	        R4      4      p/ p	 \        P                  ! \	        R4      4      p	\        P                  ! \        4      P                  R4      p
\        4       p\        4       pTR	,          R
 R2pT'       d   RMRT 2pT'       d   RMRpTP                  R/ 4      pTP                  R/ 4      pTP                  R. 4      pTP                  R\        4      pTP                  R\         4      pTP                  RT
4      pTP                  RR4      pT'       d   \#        T4      M\$        p\&        T,          pTT,           pTP                  R^ 4      pTP                  R^ 4      pT\)        T^4      ,          ^d,          pT'       d   TT,          ^d,          M^ pTP                  R^ 4      pT Uu. uF*  pTP                  R4      f   K  TP                  R^ 4      NK,  	  p pT '       d   \+        T 4      \#        T 4      ,          M^ p!T '       d   \)        T 4      M^ p"T '       d   \-        T 4      M^ p#T'       d   \)        TR R7      M/ p$T$P                  R/ 4      p%\+        R T 4       4      p&TP                  R 4      ;'       g    R!p'T''       d   T'MR!p'TP                  R"R#4      p(T	P                  R$R%4      p). p*Rp+T Fy  p, T+\/        T,P                  R&^ 4      4      ,          p+T*P1                  R'T,P                  R(R4      R&\3        T+^4      R)T,P                  R)R4      R*T,P                  R*R4      /4       K{  	  T Uu. uF  pTR+,          NK  	  p-pT Uu. uF  p\3        TP                  R^ 4      ^4      NK!  	  p.p. p/T. FH  p0T0R,8  d   T/P1                  R-4       K  T0R.8  d   T/P1                  R/4       K7  T/P1                  R04       KJ  	  \5        TR1 R2R37      R4,          p1. ER%Op2. p3\7        T14       Fm  w  p4p5T5P                  R5. 4      p6T3P1                  R6T5R+,          R7T6 U7u. uF  p7\3        T7^4      NK  	  up7R8T2T4,          R9T2T4,          R:,           R;R<R=R>R?^/4       Ko  	  \)        R@ T1 4       ^RA7      p8\9        T84       U4u. uF  p4RBT4^,            2NK  	  p9p4\        T%P;                  4       4      RC,          p:\        T%P=                  4       4      RC,           U7u. uF  p7\3        T7^4      NK  	  p;p7TP                  RD^ 4      p<TP                  RE^ 4      p=TP                  RF^ 4      p>TP                  RGRH4      p?TP                  RI^ 4      p@TP                  RJ^ 4      pATP                  RKRL4      pBTP                  RM^ 4      pCTP                  RN^ 4      pDTP                  RO^ 4      pETP                  RP^ 4      pF\        P>                  ! T\@        RA7      pG\        P>                  ! TRQ,          \@        RA7      pH\        P>                  ! T*ER&R \@        RA7      pI\        P>                  ! T3\@        RA7      pJ\        P>                  ! T9\@        RA7      pK\        P>                  ! T-\@        RA7      pL\        P>                  ! T.\@        RA7      pM\        P>                  ! T/\@        RA7      pN\        P>                  ! T:\@        RA7      pO\        P>                  ! T;\@        RA7      pP\        P>                  ! T\@        RA7      pQT^ 8  d   RMRpRT^ 8  d   RRM
T^ 8  d   RSMRTpST'       d   RUMRpTRV ovRpU\5        TRW R2R37       EF#  p5T5P                  R^ 4      p0T5P                  RX^ 4      ^d,          pVT5P                  R^ 4      pWT5P                  RYT5P                  RZ^ 4      4      pXT5P                  RZ^ 4      pYT5P                  R[^ 4      pZT5P                  R\^ 4      p[T5P                  R]4      R^8X  d   R_MR`p\\C        T0\)        T"Ra4      ,          ^P,          4      p]T0R,8  d   RM
T0R.8  d   RbMRp^T0\D        ^,          8  d   RcMRp_XURPG                  . RdNT0 NReNXW NRfNSv! T5R+,          4       NRgNSv! T5R+,          4       NRhNT_ NRiNX\R_8X  d   RjMRk NRlNX\ NRmNX] NRnNX^ NRoNT^ NRlNT0Rp NRqNXY NRrNXZRs NRrNT5P                  Rt^ 4      Rs NRrNX[ NRrNXVR
 NRuNXW^ 8  d   RvM
XW^ 8  d   RwMR NRlNXWRx NRrNT5P                  Ry^ 4       NRzNT5P                  R{^ 4      R| NRzNT5P                  R}^ 4      ^d,          R
 NR~NT5P                  R^ 4      ^d,          R
 NRN4      ,          pUEK&  	  Rp`T'       Ed   \I        TER&R 4       EFn  p,\/        T,P                  R&^ 4      4      paTa^ 8  d   RvM
Xa^ 8  d   RwMRpbX`RSv! T,P                  R(R4      R,          4       RSv! T,P                  R*R4      4       RT,P                  R]R4      R8X  d   RMR RlSv! T,P                  R]R4      4       RSv! T,P                  R)R4      4       RT,P                  RR4       R\/        T,P                  R^ 4      4      R| R\/        T,P                  R^ 4      4      R| RXb RlXaRx RTb Rl\/        T,P                  R^ 4      4      Rx R\/        T,P                  R^ 4      4      Rs RSv! T,P                  RR4      4       R2,          p`EKq  	  MRp`RpcT%'       d   T%'       d   \)        T%P=                  4       4      M^pd\5        T%PK                  4       R R7      R,           F9  w  pepf\C        TfXd,          ^d,          4      pgXcRSv! Te4       RTg RTfRp R2,          pcK;  	  MRpcRph\5        TR R2R37       EF,  piTiP                  R^ 4      pjTjR8  d   RM
XjR8  d   RMRpkXiP                  R]4      R^8X  d   R^MRplTlR^8X  d   RjMRkpmXlR^8X  d   R_MR`pnXiP                  R5. 4      poRPG                  R ToER'R  4       4      pp\#        To4      ^8  d   XoER(,          To^ ,          8  d   RM\#        Xo4      ^8  d   RMRTpqXhRSv! XiR+,          4       RXm RlXn RTiP                  RZ^ 4       RXk RlXjRp RXp RTiP                  R[^ 4      Rp RTiP                  Rt^ 4      Rp RTq R2,          phEK/  	  RPG                  . RNXT NRNTR NRNXR NRlNXS NRN\M        T4      R| NRNT!Rp NRN\#        T4       NRNT NRNT NRNT NRNT NRNTR NRNTR NRNTR NRlNTS NRN\M        T4      R| NRNTRx NRNTR
 NRNT NRNTT,
           NRNT NRNT!Rp NRNT"Rp NRNT#Rp NRNT NRNT& NRNT' NRNT<^U8  d   RM
T<^<8  d   RMR NRlNT<R
 NRNT< NRnNT<^U8  d   RM
T<^<8  d   RMR NRNXDR| NRNXER| NRNXFR| NRNT=^Z8  d   RM
T=^K8  d   RMR NRlNT=R
 NRNT>R NRNT?R NRNT= NRnNT=^Z8  d   RM
T=^K8  d   RMR NRNT?R NRNX@^U8  d   RM
X@^F8  d   RMR NRlNX@R
 NRNXAR
 NRNXBR
 NRNT@ NRnNT@^U8  d   RM
X@^F8  d   RMR NRNXBR
 NRNT NRN\#        T4       NRNXC NRNT' NRNT( NRN\D        Rs NRNXU NRNT( NRN\#        T4       NRNT' NRNT) NRNT	P                  RR%4       NRNT	P                  RR%4       NRN\N         NRN\P         NRN\R         NRN\T         NRN\D        Rs NRN\V        ;'       g    ^ NRNT& NRNSv! T$P                  R+R4      4       NRNT"Rp NRNXc NRNT NRNRPG                  Tv3R lT 4       4       NRN\#        T4       NRNX` NRNT NRNT NRNT'       d   RMR NRN\&        R NRNTR NRN\#        T4       NRN\$         NRNT NRN\X         NRN\Z         NER NT NERNT<^U8  d   RM
T<^<8  d   RMR NRlNT<R
 NERNT>R NRNT?R NERNT=R
 NERNXAR
 NRNXBR
 NERNX@R
 NERNXC NERNXDR| NRNXER| NRNXFR| NERN\N         NER	N\P         NER
N\R         NERN\T         NERN\D         NERN\V        ;'       g    ^ NERNXG NERNXH NERNXI NERNXJ NERNXK NERNXL NERNXM NERNXN NERNXO NERNXP NERN4      prERps \	        TsERERER7      ;_uu_ 4       pTP]                  Tr4       RRR4       \^        P`                  Pc                  Xs4      pt\d        Pg                  ERTs ERTtER,           ER 24       \h        Pg                  ER!TtER,           ER"\#        T4       ER#\#        T4       24       R#   \
         d     ELi ; i  + '       g   i     EL; i  \
         d     ELi ; i  \
         d     ELi ; i  \
         d     ELi ; iu upi   \
         d     EK3  i ; iu upi u upi u up7i u up4i u up7i   + '       g   i     EL!; i  \
         d%   pu\h        Pk                  ER$Tu 24        Rpu?uR# Rpu?uii ; i()  a  
Generate a comprehensive HTML dashboard saved to logs/bot_dashboard.html.
Reads claude_handoff.json, TRADE_LOG.csv, train_done.json for all data.
Pushed to GitHub daily via _do_github_push.

Sections / Tabs:
  Overview   -- market status, capital summary, VM gauges, quick stats
  Agents     -- sortable leaderboard, IC bar chart, IC history line chart
  Training   -- per-agent training details, IC trends, distillation status
  Features   -- feature importance bar chart from highest-IC agent
  Trades     -- trade log table + cumulative P&L chart (when trades exist)
  System     -- VM resources, disk breakdown, data collection status
Nr   rn   r,   r  rp   ro   r	  rc   r  r  r	  u   CLOSED — opens in #3fb950z#f85149	portfolior	  r  feature_colsr	  r	  r  r   r@	  rA	  total_positionsr  c                 &    V P                  R ^ 4      # r  r  r  s   &r   ro  '_write_html_dashboard.<locals>.<lambda>      AEE,,Br   r  top_featuresc              3   D   "   T F  qP                  R ^ 4      x  K  	  R# 5i)r  Nr  r	  s   & r   r   (_write_html_dashboard.<locals>.<genexpr>  s     EWEE-33Ws    eod_datezNot yet recordedweekend_dateNeverr  r	  r$  r   r  r   r  r  g
ףp=
?zrgba(63,185,80,0.85)Q?zrgba(210,153,34,0.85)zrgba(248,81,73,0.85)c                 &    V P                  R ^ 4      # r9
  r  r  s   &r   ro  r:
    s    |Q)?r   Tr  r  r  r  ru   borderColorbackgroundColor33tensionrE  r	  FpointRadiusc              3   X   "   T F   p\        VP                  R . 4      4      x  K"  	  R# 5i)r  N)r   r@  )r   r  s   & r   r   r>
    s#     DtBFF<344tr	  )defaultzTrain r
  r	  r	  r	  r	  i4  r	  r	  r	  g?@r	  r	  r	  r	  r  r
  r
  r
  z)<meta http-equiv="refresh" content="300">c                 x    \        V 4      P                  R R4      P                  RR4      P                  RR4      # )&z&amp;<z&lt;>z&gt;)r:   rR   r  s   &r   esc"_write_html_dashboard.<locals>.esc  s1    1v~~c'*223v>FFs6RRr   c                 &    V P                  R ^ 4      # r9
  r  r  s   &r   ro  r:
    s    AEE,q,Ar   rR  r=  r  r  r(  r  cloner
  Baser  z#d29922u    ⚠️z(
        <tr class="agent-row" data-ic="z" data-pnl="z" data-name="z'">
          <td><span class="ag-name"></span>z'</td>
          <td><span class="badge zbadge-clonez
badge-basez">z</span></td>
          <td>
            <div class="ic-cell">
              <div class="ic-bar-bg"><div class="ic-bar" style="width:z%;background:z0"></div></div>
              <span style="color:r:  zE</span>
            </div>
          </td>
          <td class="num">z </td>
          <td class="num">r>  r  z %</td>
          <td class="num ro  negr=  open_positionsz&</td>
          <td class="num small">r	  r  r  z'%</td>
          <td class="num small">r  z%</td>
        </tr>z2
            <tr>
              <td class="small">:N   Nz</td>
              <td>z+</td>
              <td><span class="badge LONGz	badge-buyzbadge-shortz,</span></td>
              <td class="mono">z$</td>
              <td class="num">r!  z%</td>
              <td class="num">$r"  r#  z#</td>
              <td class="num r%  z+%</td>
              <td class="num small">r+  z&</td>
              <td class="small">r(  z</td>
            </tr>uY   <tr><td colspan="11" class="no-data">No trades yet — bot is in learning phase</td></tr>c                     V ^,          ) # r  r   rm  s   &r   ro  r:
    s
    1r   rI  z1
            <tr>
              <td class="mono">zT</td>
              <td><div class="feat-bar-bg"><div class="feat-bar" style="width:z3%"></div></div></td>
              <td class="num">zc<tr><td colspan="3" class="no-data">Feature importance loads after first training session</td></tr>c                 &    V P                  R ^ 4      # r9
  r  rm  s   &r   ro  r:
  %  r;
  r   r  zvar(--green)g?zvar(--yellow)z
var(--red)r  r  c              3   (   "   T F  qR  x  K
  	  R# 5i)r>  Nr   r  s   & r   r   r>
  ,  s     <A#wZs   u   ↗u   ↘z<tr><td>z</td><td><span class="badge z</span></td><td class="num">z"</td><td class="num" style="color:z</td><td class="mono small">z</td><td class="num">z</td></tr>
z<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
u  
<title>Trading Bot Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
:root {
  --bg:#0d1117;--card:#161b22;--card2:#1c2128;--border:#30363d;
  --green:#3fb950;--yellow:#d29922;--red:#f85149;--blue:#58a6ff;--purple:#a371f7;--orange:#f0883e;
  --text:#e6edf3;--muted:#8b949e;--font:'Segoe UI',system-ui,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--text);font-family:var(--font);font-size:14px;min-height:100vh}
a{color:var(--blue);text-decoration:none}

/* ── HEADER ── */
.hdr{background:var(--card);border-bottom:2px solid var(--border);padding:0 24px;
  display:flex;align-items:center;gap:16px;height:56px;position:sticky;top:0;z-index:100}
.hdr-title{font-size:1.05rem;font-weight:700;color:var(--green);white-space:nowrap}
.hdr-pills{display:flex;gap:10px;flex-wrap:wrap}
.pill{background:var(--card2);border:1px solid var(--border);border-radius:16px;
  padding:3px 10px;font-size:.75rem;color:var(--muted)}
.pill span{color:var(--text);font-weight:600}
.hdr-right{margin-left:auto;font-size:.72rem;color:var(--muted);white-space:nowrap}
.mkt-badge{padding:3px 10px;border-radius:12px;font-size:.75rem;font-weight:700;border:1px solid}

/* ── STAT CARDS ── */
.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:12px;padding:20px 24px 0}
.stat-card{background:var(--card);border:1px solid var(--border);border-radius:10px;
  padding:16px;text-align:center;transition:border-color .2s}
.stat-card:hover{border-color:var(--green)}
.stat-val{font-size:1.6rem;font-weight:700;line-height:1}
.stat-lbl{font-size:.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:.07em;margin-top:5px}
.stat-sub{font-size:.72rem;color:var(--muted);margin-top:3px}

/* ── TABS ── */
.tabs{display:flex;gap:0;padding:20px 24px 0;border-bottom:1px solid var(--border);margin:12px 0 0}
.tab{padding:10px 18px;cursor:pointer;color:var(--muted);font-size:.85rem;font-weight:500;
  border-bottom:2px solid transparent;transition:all .15s;white-space:nowrap}
.tab:hover{color:var(--text)}
.tab.active{color:var(--green);border-bottom-color:var(--green)}
.tab-content{display:none;padding:20px 24px}
.tab-content.active{display:block}

/* ── SECTION CARDS ── */
.section{background:var(--card);border:1px solid var(--border);border-radius:10px;
  padding:18px;margin-bottom:16px}
.section-title{font-size:.85rem;font-weight:600;color:var(--muted);
  text-transform:uppercase;letter-spacing:.08em;margin-bottom:14px}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.three-col{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px}
@media(max-width:700px){.two-col,.three-col{grid-template-columns:1fr}}

/* ── GAUGE ── */
.gauge-wrap{text-align:center}
.gauge-label{font-size:.75rem;color:var(--muted);margin-bottom:6px}
.gauge-bar{height:10px;background:var(--card2);border-radius:5px;overflow:hidden;margin:4px 0}
.gauge-fill{height:100%;border-radius:5px;transition:width .5s}
.gauge-nums{font-size:.75rem;color:var(--muted);display:flex;justify-content:space-between}
.gauge-val{font-size:1.1rem;font-weight:700;margin-bottom:2px}

/* ── TABLES ── */
.tbl-wrap{overflow-x:auto}
table{width:100%;border-collapse:collapse;font-size:.83rem}
th{padding:8px 10px;text-align:left;color:var(--muted);font-size:.72rem;
  text-transform:uppercase;border-bottom:2px solid var(--border);white-space:nowrap;
  cursor:pointer;user-select:none}
th:hover{color:var(--text)}
th.sort-asc::after{content:" ▲"}
th.sort-desc::after{content:" ▼"}
td{padding:8px 10px;border-bottom:1px solid #21262d}
tr:hover td{background:var(--card2)}
.num{text-align:right;font-variant-numeric:tabular-nums}
.mono{font-family:monospace}
.small{font-size:.78rem;color:var(--muted)}
.pos{color:var(--green)}
.neg{color:var(--red)}
.no-data{color:var(--muted);text-align:center;padding:24px;font-style:italic}

/* ── BADGES ── */
.badge{font-size:.65rem;padding:2px 7px;border-radius:10px;font-weight:700;text-transform:uppercase}
.badge-base{background:#0d2a18;color:var(--green)}
.badge-clone{background:#0d2049;color:var(--blue)}
.badge-buy{background:#0d2a18;color:var(--green)}
.badge-short{background:#2a0d0d;color:var(--red)}

/* ── IC BAR ── */
.ic-cell{display:flex;align-items:center;gap:8px;min-width:120px}
.ic-bar-bg{flex:1;height:8px;background:var(--card2);border-radius:4px;overflow:hidden}
.ic-bar{height:100%;border-radius:4px;transition:width .4s}

/* ── FEATURE BAR ── */
.feat-bar-bg{width:160px;height:10px;background:var(--card2);border-radius:5px;overflow:hidden}
.feat-bar{height:100%;border-radius:5px;background:var(--green)}

/* ── SEARCH ── */
.search-row{display:flex;gap:12px;margin-bottom:14px;align-items:center}
.search-box{background:var(--card2);border:1px solid var(--border);border-radius:6px;
  padding:6px 10px;color:var(--text);font-size:.83rem;width:220px;outline:none}
.search-box:focus{border-color:var(--green)}
.filter-btn{background:var(--card2);border:1px solid var(--border);border-radius:6px;
  padding:5px 12px;color:var(--muted);font-size:.78rem;cursor:pointer}
.filter-btn.active{border-color:var(--green);color:var(--green)}
.filter-btn:hover{color:var(--text)}

/* ── CHART CONTAINER ── */
.chart-wrap{position:relative;height:260px}
.chart-wrap-tall{position:relative;height:360px}

/* ── SCROLLBAR ── */
::-webkit-scrollbar{width:5px;height:5px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#30363d;border-radius:3px}

/* ── TRAINING TIMELINE ── */
.train-event{display:flex;align-items:flex-start;gap:12px;padding:10px 0;
  border-bottom:1px solid #21262d}
.train-dot{width:10px;height:10px;border-radius:50%;margin-top:3px;flex-shrink:0}
.train-text{flex:1}
.train-label{font-size:.82rem;font-weight:600}
.train-sub{font-size:.75rem;color:var(--muted)}

/* ── DATA STATUS ── */
.data-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px}
.data-item{background:var(--card2);border-radius:8px;padding:12px}
.data-item-val{font-size:1.15rem;font-weight:700;color:var(--blue)}
.data-item-lbl{font-size:.72rem;color:var(--muted);margin-top:3px}
</style>
</head>
<body>

<!-- ══════════════════════ HEADER ══════════════════════ -->
<header class="hdr">
  <div class="hdr-title">🤖 ML Trading Bot v9</div>
  <div class="hdr-pills">
    <div class="pill">Capital <span>$r  z?</span></div>
    <div class="pill">P&amp;L <span style="color:r  z1</span></div>
    <div class="pill">Avg IC <span>z1</span></div>
    <div class="pill">Agents <span>za</span></div>
  </div>
  <div style="margin-left:12px">
    <span class="mkt-badge" style="color:z;border-color:u   ">
      ● z8
    </span>
  </div>
  <div class="hdr-right">Updated: u  </div>
</header>

<!-- ══════════════════════ STAT CARDS ══════════════════════ -->
<div class="stats-grid">
  <div class="stat-card">
    <div class="stat-val" style="color:var(--blue)">$zW</div>
    <div class="stat-lbl">Total Equity</div>
    <div class="stat-sub">Started $zQ</div>
  </div>
  <div class="stat-card">
    <div class="stat-val" style="color:zM</div>
    <div class="stat-lbl">Net P&amp;L</div>
    <div class="stat-sub">za%</div>
  </div>
  <div class="stat-card">
    <div class="stat-val" style="color:var(--yellow)">zK%</div>
    <div class="stat-lbl">Win Rate</div>
    <div class="stat-sub">zW / zL of z_</div>
  </div>
  <div class="stat-card">
    <div class="stat-val" style="color:var(--green)">zT</div>
    <div class="stat-lbl">Avg IC Score</div>
    <div class="stat-sub">Best: u    · Worst: z`</div>
  </div>
  <div class="stat-card">
    <div class="stat-val" style="color:var(--purple)">z</div>
    <div class="stat-lbl">Open Positions</div>
    <div class="stat-sub">Across all agents</div>
  </div>
  <div class="stat-card">
    <div class="stat-val" style="color:var(--orange)">zX</div>
    <div class="stat-lbl">Total Trains</div>
    <div class="stat-sub">Last EOD: u  </div>
  </div>
</div>

<!-- ══════════════════════ TABS ══════════════════════ -->
<div class="tabs">
  <div class="tab active" onclick="showTab('overview')">📊 Overview</div>
  <div class="tab" onclick="showTab('agents')">🤖 Agents</div>
  <div class="tab" onclick="showTab('training')">🎓 Training</div>
  <div class="tab" onclick="showTab('features')">🔬 Features</div>
  <div class="tab" onclick="showTab('trades')">📈 Trades</div>
  <div class="tab" onclick="showTab('system')">⚙️ System</div>
</div>

<!-- ══════════════════ TAB: OVERVIEW ══════════════════ -->
<div class="tab-content active" id="tab-overview">
  <div class="two-col">
    <div class="section">
      <div class="section-title">Portfolio Equity Curve</div>
      <div class="chart-wrap">
        <canvas id="pnlChart"></canvas>
      </div>
    </div>
    <div class="section">
      <div class="section-title">Agent IC Distribution</div>
      <div class="chart-wrap">
        <canvas id="icDistChart"></canvas>
      </div>
    </div>
  </div>
  <div class="two-col">
    <div class="section">
      <div class="section-title">VM Resources</div>
      <div style="display:flex;flex-direction:column;gap:16px">
        <div class="gauge-wrap">
          <div class="gauge-label">CPU Usage</div>
          <div class="gauge-val" style="color:zN%</div>
          <div class="gauge-bar"><div class="gauge-fill" style="width:zL"></div></div>
          <div class="gauge-nums"><span>0%</span><span>Load: z / z</span><span>100%</span></div>
        </div>
        <div class="gauge-wrap">
          <div class="gauge-label">RAM Usage</div>
          <div class="gauge-val" style="color:zD%  <span style="font-size:.8rem;font-weight:400;color:var(--muted)">r  z MB / zW MB</span></div>
          <div class="gauge-bar"><div class="gauge-fill" style="width:zU"></div></div>
          <div class="gauge-nums"><span>0 MB</span><span></span><span>z MB</span></div>
        </div>
        <div class="gauge-wrap">
          <div class="gauge-label">Disk Usage</div>
          <div class="gauge-val" style="color: GB / zW GB</span></div>
          <div class="gauge-bar"><div class="gauge-fill" style="width:zU"></div></div>
          <div class="gauge-nums"><span>0 GB</span><span></span><span>z GB</span></div>
        </div>
      </div>
    </div>
    <div class="section">
      <div class="section-title">Data &amp; Model Status</div>
      <div class="data-grid">
        <div class="data-item"><div class="data-item-val">zw</div><div class="data-item-lbl">Feature Columns</div></div>
        <div class="data-item"><div class="data-item-val">zu</div><div class="data-item-lbl">Active Agents</div></div>
        <div class="data-item"><div class="data-item-val">zw</div><div class="data-item-lbl">Threads Running</div></div>
        <div class="data-item"><div class="data-item-val">zv</div><div class="data-item-lbl">Last EOD Train</div></div>
        <div class="data-item"><div class="data-item-val">zz</div><div class="data-item-lbl">Last Weekend Train</div></div>
        <div class="data-item"><div class="data-item-val">u  </div><div class="data-item-lbl">IC Vote Threshold</div></div>
      </div>
    </div>
  </div>
</div>

<!-- ══════════════════ TAB: AGENTS ══════════════════ -->
<div class="tab-content" id="tab-agents">
  <div class="section">
    <div class="section-title">IC Score — All Agents (sorted by IC)</div>
    <div class="chart-wrap-tall"><canvas id="icBarChart"></canvas></div>
  </div>
  <div class="section">
    <div class="section-title">Agent Leaderboard</div>
    <div class="search-row">
      <input class="search-box" id="agentSearch" placeholder="🔍 Search agents..." oninput="filterAgents(this.value)">
      <button class="filter-btn active" onclick="sortAgentBy('ic')">Sort IC</button>
      <button class="filter-btn" onclick="sortAgentBy('pnl')">Sort P&amp;L</button>
      <button class="filter-btn" onclick="sortAgentBy('trades')">Sort Trades</button>
      <button class="filter-btn" onclick="filterType('all')">All</button>
      <button class="filter-btn" onclick="filterType('base')">Base Only</button>
      <button class="filter-btn" onclick="filterType('clone')">Clones Only</button>
    </div>
    <div class="tbl-wrap">
      <table id="agentTable">
        <thead>
          <tr>
            <th onclick="sortAgentBy('name')">Name</th>
            <th>Type</th>
            <th onclick="sortAgentBy('ic')">IC Score ▼</th>
            <th onclick="sortAgentBy('tc')">Trains</th>
            <th onclick="sortAgentBy('vacc')">Val Acc</th>
            <th onclick="sortAgentBy('tacc')">Train Acc</th>
            <th onclick="sortAgentBy('trades')">Trades</th>
            <th onclick="sortAgentBy('wr')">Win %</th>
            <th onclick="sortAgentBy('pnl')">P&amp;L ($)</th>
            <th>Pos</th>
            <th>Min Conf</th>
            <th>Stop %</th>
            <th>TP %</th>
          </tr>
        </thead>
        <tbody id="agentTbody">
u  
        </tbody>
      </table>
    </div>
  </div>
</div>

<!-- ══════════════════ TAB: TRAINING ══════════════════ -->
<div class="tab-content" id="tab-training">
  <div class="two-col">
    <div class="section">
      <div class="section-title">IC Score History — Top 5 Agents</div>
      <div class="chart-wrap-tall"><canvas id="icHistChart"></canvas></div>
    </div>
    <div class="section">
      <div class="section-title">Training Timeline</div>
      <div class="train-event">
        <div class="train-dot" style="background:var(--green)"></div>
        <div class="train-text">
          <div class="train-label">Last Weekend Deep Train</div>
          <div class="train-sub">u    · +100 trees per agent · a   agents</div>
        </div>
      </div>
      <div class="train-event">
        <div class="train-dot" style="background:var(--blue)"></div>
        <div class="train-text">
          <div class="train-label">Last EOD Incremental Train</div>
          <div class="train-sub">u!   · +50 trees per agent</div>
        </div>
      </div>
      <div class="train-event">
        <div class="train-dot" style="background:var(--muted)"></div>
        <div class="train-text">
          <div class="train-label">Last Checkpoint</div>
          <div class="train-sub">Date: u    · Agent: last_completedu	    · Idx: next_agent_idxz</div>
        </div>
      </div>
      <br>
      <div class="section-title" style="margin-top:10px">Training Parameters</div>
      <table>
        <tr><td style="color:var(--muted)">Daily trees per agent</td><td class="num">zb</td></tr>
        <tr><td style="color:var(--muted)">Weekend trees per agent</td><td class="num">za</td></tr>
        <tr><td style="color:var(--muted)">Distillation threshold</td><td class="num">zh trees</td></tr>
        <tr><td style="color:var(--muted)">Distillation base trees</td><td class="num">z\</td></tr>
        <tr><td style="color:var(--muted)">IC vote threshold</td><td class="num">z]</td></tr>
        <tr><td style="color:var(--muted)">Workers (training)</td><td class="num">zb</td></tr>
        <tr><td style="color:var(--muted)">Total trains all agents</td><td class="num">u  </td></tr>
      </table>
    </div>
  </div>
  <div class="section">
    <div class="section-title">Per-Agent Training Details</div>
    <div class="tbl-wrap">
      <table>
        <thead>
          <tr><th>Agent</th><th>Type</th><th>Trains</th><th>IC Score</th><th>IC History (last 8)</th><th>Val Acc</th><th>Train Acc</th><th>IC Trend</th></tr>
        </thead>
        <tbody>
          _train_rows_html
        </tbody>
      </table>
    </div>
  </div>
</div>

<!-- ══════════════════ TAB: FEATURES ══════════════════ -->
<div class="tab-content" id="tab-features">
  <div class="two-col">
    <div class="section">
      <div class="section-title">Feature Importance — zHighest IC Agentz (IC=aM  )</div>
      <div class="chart-wrap-tall"><canvas id="featChart"></canvas></div>
    </div>
    <div class="section">
      <div class="section-title">Top Feature Rankings</div>
      <div class="tbl-wrap">
        <table>
          <thead><tr><th>Feature</th><th>Relative Importance</th><th>Gain</th></tr></thead>
          <tbody>zv</tbody>
        </table>
      </div>
    </div>
  </div>
  <div class="section">
    <div class="section-title">All zS Feature Columns</div>
    <div style="display:flex;flex-wrap:wrap;gap:6px">
      c              3   <   <"   T F  pR S! V4       R2x  K  	  R# 5i)z<span style="background:var(--card2);border:1px solid var(--border);border-radius:5px;padding:3px 8px;font-size:.75rem;font-family:monospace">rU
  Nr   )r   r[  rP
  s   & r   r   r>
    sP       G  zF  uv  `  ad  ef  ag  `h  ho  p  zFs   u  
    </div>
  </div>
</div>

<!-- ══════════════════ TAB: TRADES ══════════════════ -->
<div class="tab-content" id="tab-trades">
  <div class="section">
    <div class="section-title">Cumulative P&amp;L Over Time</div>
    <div class="chart-wrap"><canvas id="cumPnlChart"></canvas></div>
  </div>
  <div class="section">
    <div class="section-title">Trade Log (u   total trades)</div>
    <div class="search-row">
      <input class="search-box" id="tradeSearch" placeholder="🔍 Filter by symbol, agent..." oninput="filterTrades(this.value)">
    </div>
    <div class="tbl-wrap">
      <table>
        <thead>
          <tr><th>Timestamp</th><th>Agent</th><th>Type</th><th>Symbol</th><th>Shares</th><th>Entry</th><th>Exit</th><th>P&amp;L ($)</th><th>P&amp;L %</th><th>Meta Conf</th><th>Reason</th></tr>
        </thead>
        <tbody id="tradeTbody">u  </tbody>
      </table>
    </div>
  </div>
</div>

<!-- ══════════════════ TAB: SYSTEM ══════════════════ -->
<div class="tab-content" id="tab-system">
  <div class="three-col">
    <div class="section">
      <div class="section-title">Market</div>
      <table>
        <tr><td style="color:var(--muted)">Status</td><td style="color:z;font-weight:700">zC</td></tr>
        <tr><td style="color:var(--muted)">Mode</td><td>u   OPEN — collecting barsu   CLOSED — sentiment onlyz</td></tr>
        <tr><td style="color:var(--muted)">Trading</td><td>Paper (Alpaca)</td></tr>
        <tr><td style="color:var(--muted)">Starting capital</td><td>$zU / agent</td></tr>
        <tr><td style="color:var(--muted)">Total capital</td><td>$a  </td></tr>
      </table>
    </div>
    <div class="section">
      <div class="section-title">Bot Version</div>
      <table>
        <tr><td style="color:var(--muted)">Version</td><td>v9 (Lifetime Learning)</td></tr>
        <tr><td style="color:var(--muted)">Agents</td><td>r   za base+clone + MetaLearner)</td></tr>
        <tr><td style="color:var(--muted)">Features</td><td>zM</td></tr>
        <tr><td style="color:var(--muted)">Min trade rows</td><td>zM</td></tr>
        <tr><td style="color:var(--muted)">Min train rows</td><td>zV</td></tr>
        <tr><td style="color:var(--muted)">Generated</td><td class="small">z</td></tr>
      </table>
    </div>
    <div class="section">
      <div class="section-title">VM Resources</div>
      <table>
        <tr><td style="color:var(--muted)">CPU</td><td style="color:zH%</td></tr>
        <tr><td style="color:var(--muted)">RAM Used</td><td> MB (zJ%)</td></tr>
        <tr><td style="color:var(--muted)">Disk Used</td><td> GB (zH%)</td></tr>
        <tr><td style="color:var(--muted)">Threads</td><td>zM</td></tr>
        <tr><td style="color:var(--muted)">Load (1/5/15m)</td><td>a  </td></tr>
      </table>
    </div>
  </div>
  <div class="section">
    <div class="section-title">Configuration</div>
    <div class="two-col">
      <table>
        <tr><th colspan="2">Training</th></tr>
        <tr><td style="color:var(--muted)">Daily trees</td><td>zL</td></tr>
        <tr><td style="color:var(--muted)">Weekend trees</td><td>zP</td></tr>
        <tr><td style="color:var(--muted)">Distill threshold</td><td>zK</td></tr>
        <tr><td style="color:var(--muted)">Distill base</td><td>zJ</td></tr>
        <tr><td style="color:var(--muted)">IC vote min</td><td>zJ</td></tr>
        <tr><td style="color:var(--muted)">Max workers</td><td>u  </td></tr>
      </table>
      <table>
        <tr><th colspan="2">Scheduling</th></tr>
        <tr><td style="color:var(--muted)">EOD trigger</td><td>4:15 PM ET post-close</td></tr>
        <tr><td style="color:var(--muted)">Weekend trigger</td><td>Saturday 6AM–10PM ET</td></tr>
        <tr><td style="color:var(--muted)">Backup (market hours)</td><td>Every 30 min</td></tr>
        <tr><td style="color:var(--muted)">Backup (off-hours)</td><td>Every 2 hours</td></tr>
        <tr><td style="color:var(--muted)">Backup (weekend)</td><td>Every 6 hours</td></tr>
        <tr><td style="color:var(--muted)">GitHub push</td><td>Daily</td></tr>
      </table>
    </div>
  </div>
</div>

<!-- ══════════════════ JAVASCRIPT ══════════════════ -->
<script>
// ── Embedded data ────────────────────────────────────────────
const agentData    = z;
const tradeData    = z;
const cumPnlData   = z;
const icHistData   = z;
const icHistLabels = z;
const agNames      = z;
const agIC         = z;
const agColors     = z;
const featLabels   = z;
const featVals     = uO"  ;

// ── Tab system ───────────────────────────────────────────────
function showTab(id) {
  document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
  document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
  document.getElementById('tab-' + id).classList.add('active');
  event.target.classList.add('active');
  // Lazy-render charts when tab becomes visible
  if (id === 'overview')  { renderOverviewCharts(); }
  if (id === 'agents')    { renderAgentChart(); }
  if (id === 'training')  { renderTrainingCharts(); }
  if (id === 'features')  { renderFeatChart(); }
  if (id === 'trades')    { renderTradeChart(); }
}

// ── Chart defaults ───────────────────────────────────────────
Chart.defaults.color = '#8b949e';
Chart.defaults.borderColor = '#30363d';
Chart.defaults.font.family = "'Segoe UI', system-ui, sans-serif";
Chart.defaults.font.size = 11;

let chartsRendered = {};
function renderOnce(id, fn) {
  if (!chartsRendered[id]) { fn(); chartsRendered[id] = true; }
}

// ── P&L Equity Curve ────────────────────────────────────────
function renderOverviewCharts() {
  renderOnce('pnl', () => {
    const ctx = document.getElementById('pnlChart');
    if (!ctx) return;
    const labels = cumPnlData.length ? cumPnlData.map(r => r.ts.slice(5,16)) : ['Start', 'Now'];
    const data   = cumPnlData.length ? cumPnlData.map(r => r.pnl) : [0, 0];
    new Chart(ctx, {
      type: 'line',
      data: {
        labels,
        datasets: [{
          label: 'Cumulative P&L ($)',
          data,
          borderColor: data[data.length-1] >= 0 ? '#3fb950' : '#f85149',
          backgroundColor: data[data.length-1] >= 0 ? 'rgba(63,185,80,0.1)' : 'rgba(248,81,73,0.1)',
          fill: true, tension: 0.3, pointRadius: data.length < 20 ? 4 : 1,
        }]
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        plugins: { legend: { display: false }, tooltip: { mode: 'index' } },
        scales: {
          x: { ticks: { maxTicksLimit: 8 } },
          y: { ticks: { callback: v => '$' + v.toFixed(2) } }
        }
      }
    });
  });
  renderOnce('icDist', () => {
    const ctx = document.getElementById('icDistChart');
    if (!ctx) return;
    new Chart(ctx, {
      type: 'bar',
      data: {
        labels: agNames,
        datasets: [{ label: 'Rolling IC', data: agIC, backgroundColor: agColors, borderRadius: 3 }]
      },
      options: {
        responsive: true, maintainAspectRatio: false, indexAxis: 'y',
        plugins: { legend: { display: false } },
        scales: {
          x: { min: 0, max: Math.max(...agIC) * 1.2, ticks: { callback: v => v.toFixed(3) } },
          y: { ticks: { font: { size: 10 } } }
        }
      }
    });
  });
}

// ── Agent IC Bar Chart ───────────────────────────────────────
function renderAgentChart() {
  renderOnce('icBar', () => {
    const ctx = document.getElementById('icBarChart');
    if (!ctx) return;
    const sorted = [...agNames.map((n,i) => ({n, ic:agIC[i], c:agColors[i]}))]
      .sort((a,b) => b.ic - a.ic);
    new Chart(ctx, {
      type: 'bar',
      data: {
        labels: sorted.map(d => d.n),
        datasets: [{
          label: 'Rolling IC Score',
          data: sorted.map(d => d.ic),
          backgroundColor: sorted.map(d => d.c),
          borderRadius: 4,
        }]
      },
      options: {
        responsive: true, maintainAspectRatio: false, indexAxis: 'y',
        plugins: { legend: { display: false }, tooltip: { callbacks: { label: c => ' IC: ' + c.raw.toFixed(4) } } },
        scales: {
          x: { min: 0, ticks: { callback: v => v.toFixed(3) } },
          y: { ticks: { font: { size: 10 } } }
        }
      }
    });
  });
}

// ── IC History Line Chart ────────────────────────────────────
function renderTrainingCharts() {
  renderOnce('icHist', () => {
    const ctx = document.getElementById('icHistChart');
    if (!ctx) return;
    new Chart(ctx, {
      type: 'line',
      data: { labels: icHistLabels, datasets: icHistData },
      options: {
        responsive: true, maintainAspectRatio: false,
        plugins: { legend: { position: 'top', labels: { boxWidth: 12, font: { size: 11 } } } },
        scales: {
          x: { ticks: { maxTicksLimit: 10 } },
          y: { ticks: { callback: v => v.toFixed(3) }, title: { display: true, text: 'IC Score' } }
        }
      }
    });
  });
}

// ── Feature Importance Chart ─────────────────────────────────
function renderFeatChart() {
  renderOnce('feat', () => {
    const ctx = document.getElementById('featChart');
    if (!ctx || !featLabels.length) return;
    const sorted = featLabels.map((l,i) => ({l, v:featVals[i]})).sort((a,b) => b.v - a.v);
    new Chart(ctx, {
      type: 'bar',
      data: {
        labels: sorted.map(d => d.l),
        datasets: [{
          label: 'Feature Gain Importance',
          data: sorted.map(d => d.v),
          backgroundColor: 'rgba(63,185,80,0.75)',
          borderRadius: 4,
        }]
      },
      options: {
        responsive: true, maintainAspectRatio: false, indexAxis: 'y',
        plugins: { legend: { display: false } },
        scales: {
          x: { ticks: { callback: v => v.toFixed(4) } },
          y: { ticks: { font: { size: 10 } } }
        }
      }
    });
  });
}

// ── Cumulative P&L Chart ─────────────────────────────────────
function renderTradeChart() {
  renderOnce('cumPnl', () => {
    const ctx = document.getElementById('cumPnlChart');
    if (!ctx) return;
    const labels = cumPnlData.map(r => r.ts.slice(5,16));
    const data   = cumPnlData.map(r => r.pnl);
    new Chart(ctx, {
      type: 'line',
      data: {
        labels: labels.length ? labels : ['No trades yet'],
        datasets: [{
          label: 'Cumulative P&L',
          data: data.length ? data : [0],
          borderColor: '#3fb950', backgroundColor: 'rgba(63,185,80,0.1)',
          fill: true, tension: 0.3,
        }]
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        plugins: { legend: { display: false } },
        scales: { y: { ticks: { callback: v => '$' + v.toFixed(2) } } }
      }
    });
  });
}

// ── Table filtering/sorting ───────────────────────────────────
let currentSort = 'ic', currentDir = -1, currentType = 'all';

function sortAgentBy(key) {
  if (currentSort === key) currentDir *= -1;
  else { currentSort = key; currentDir = -1; }
  renderAgentTable();
}

function filterType(type) { currentType = type; renderAgentTable(); }
function filterAgents(q) { renderAgentTable(q.toLowerCase()); }

function renderAgentTable(search='') {
  const tbody = document.getElementById('agentTbody');
  if (!tbody) return;
  let rows = [...tbody.querySelectorAll('.agent-row')];
  rows.forEach(r => {
    const name = r.dataset.name.toLowerCase();
    const typeOk = currentType === 'all' || 
                   (currentType === 'clone' && name.includes('clone')) ||
                   (currentType === 'base'  && !name.includes('clone'));
    const searchOk = !search || name.includes(search);
    r.style.display = typeOk && searchOk ? '' : 'none';
  });
  const visible = rows.filter(r => r.style.display !== 'none');
  const sorted  = visible.sort((a, b) => {
    const vals = {
      ic: [parseFloat(a.dataset.ic), parseFloat(b.dataset.ic)],
      pnl: [parseFloat(a.dataset.pnl), parseFloat(b.dataset.pnl)],
      name: [a.dataset.name, b.dataset.name],
    };
    const [va, vb] = vals[currentSort] || [0, 0];
    return typeof va === 'string' ? va.localeCompare(vb) * currentDir : (va - vb) * currentDir;
  });
  sorted.forEach(r => tbody.appendChild(r));
}

function filterTrades(q) {
  const q2 = q.toLowerCase();
  document.querySelectorAll('#tradeTbody tr').forEach(r => {
    r.style.display = !q2 || r.innerText.toLowerCase().includes(q2) ? '' : 'none';
  });
}

// ── Init ─────────────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
  renderOverviewCharts();
});
</script>
</body>
</html>r   r  zutf-8)encodingzHTML dashboard -> r	  r   zKB)zHTML_DASHBOARD | zKB | agents=z
 | trades=zHTML_DASHBOARD_ERR | )r4
  z#58a6ffz#f0883ez#a371f7z#39d353i8r	  r  )6r/  base64r~  r  r.  rX   rG   
DictReaderr   rB   r   rC   r  r  r@  r  rl  r   
NUM_AGENTSr  r  rT  r  r  rS   r  rQ   r  r  r  r  r  r:   r   rI  r   reversedr   r  DAILY_TRAIN_TREESWEEKLY_TRAIN_TREESrC  DISTILL_BASE_TREESr  r  r  r	  rT   rU   r   r   r   r   r   )wr  r	  r  _csv_b64r	  
trade_rowsr   
train_done
train_ckptr=	  r	  	secs_open
hours_open
mkt_status	mkt_colorr5
  vmag_listr6
  r	  gen_atr  rc	  r!
  rC	  r@	  rA	  rR  r%  	total_posr8  ic_valsavg_icbest_icworst_icbest_agr  total_train_countlast_eod	last_wknd	last_ckptcum_pnl_datarunningr4  ag_namesag_ic	ag_colorsr$
  top5line_colorsic_history_datasetsr  r  rb	  r  max_hist_lenic_history_labelsfeat_labels	feat_valsr	  r	  ram_usedram_totdsk_pctdsk_useddsk_totthreadsload_1load_5load_15_json_agents_json_trades_json_cum_pnl_json_ic_hist_json_ic_labels_json_ag_names_json_ag_ic_json_ag_colors_json_feat_lbl_json_feat_val_json_feature_cols	pnl_colorr&
  refresh_tagagent_rows_htmlr#
  r$  tctrncvacctrdsr%
  ic_bar_wic_colorwarntrade_rows_htmlpnl_vclsfeat_rows_htmlmax_imprR  r-
  bar_w_train_rows_html_a_ic_ic_c_atype_badge_blabel_hist	_hist_str_trendhtmlr	  r   r   rP
  sw   &&&                                                                                                                   @r   r
  r
  3  sX    ' G))D!;<= J&33qdooa01J 4
 JYYt$:;<
 JYYt$@AB

 ,,z*334KLG "H$&It^C(*J$&,@*MJ')YI++k2.I++nb1B++h+G++nl;L++lJ7J++ng6FMM+s3I$+CLH$x/K)+MMM.!4LMM,2J#lA"66<H7BY,s2GMM"3Q7I 3:]'QQUU<=P(!%%a('G]29#g,W-qF!(WaG!(WaH HOW"BCTVG^R0H EWEE..,BB0BH&(,>H..9I../I LG		uSWWUA.//Gcggk2.uWa(#''(B/"-	!   &--W!F))WH-<CDGq%lA.2GEDI;	(()?@5[)**+BC56  '?NrRDEK42vvlB'""RZ$/$QeAaj$/;q>{1~4sE1$
 	 ! DtDaPL16|1DE1DA6!A#1DE x}}',K(,X__->(?(DE(D15A;(DIE vvi#Gvvi#GvvmQ'Hvvnd+Gvvj!$Gvvna(Hvvot,Gvv&*Gvvi#Fvvi#Fvvj!$G jj#6LjjD!13?Ljjde!4cBMjj!4cBMjj!2C@Ojj37Njj4KjjC8Ojjc:NjjC8NL#>(A~)9I$q=%y1}e%IAI=rKS OW"A4PPvvlA&vvj!$s*vvk1%vvlBFF=!$<=vvmQ'vvi#vvh"&&.G3wrC//"45 "e9bEky!6!::y    ( (*t+78;u<IJMbQWj/IZ[%%(F_$55<=AFC" 47<-\!R SU VYTYZG HPj Q^ _g]gh" #+ ,. /1X6  &!  *% 66+a056  &! c(# $'q5%s1ue"E FH ILDzR  66"2156! 7!!" "$
1!5c :#";!#$ "$!:3!>s C%$D!%& "$(9!!<S!@ E'&F' 	 QF OzJtu-.C#''%+,E 19%519%"C $!!$SWW[%<S%A!B C Dswwwr*+, -&58WWVB5G5OkUb%ccefijmjqjqrxy{j|f}e~   #CGGHR$8 9: ;"wwx34 5  %cggmA&> ?D E  %cggl1&= >sC D!U"U4L 1!U"U3779Q+?%@$F G%%*377;q+A%B3$G H!!$SWWXb%9!: ; <  O /$ v N,4#hoo'(! 0oFsKKID#g+,E #  #D	{ +OOTg V"3i (	 N L  W"BDQQa(#&%<u_ZfFF6Ng56"(G"3"g-6b)HH<rs<<	e*/eBi%(.BQTUZQ[_`Q`fkr&z?# $&&,XRy 9!vvmQ78 9,,17"SI >&&/[ 1!vvi3C8 9!vvk15c: ;%h '		
 R.@ @  @
 @
F&@V '4D%9W@V:2W@X 3<Y@X =?Y@X @IkY@X JKY@X LOy>Z]J^Y@X_$Y@Z %+3<[@Z0$[@\ %(L>]@\2*]@b +4c@b 5Cc@b DM+c@bNc@d ,e@d#e@j $*(k@j+6k@v 7DD5Iw@vJ$w@z %0#5{@z6({@@ )2{A@@ 35A@@ 6?KA@@ @AA@@ BEYPS@TA@@UA@D #4.E@D)7E@J 8@nK@JEK@N &,O@N '+O@N ,8*+D*EO@N FKO@N LX.O@NY6O@T 7=S\U@TB!U@X ")Y@X .9Y@X :B#Y@XG7Y@^ 8Ak_@^B7_@h 8I6Ii@hJ%i@l &.Jm@l$//m@t @Grz|bijlbl  sA  /Bu@t BDu@t EL  MP  DQu@tQGu@v HOiw@v P]w@v nuuwmw]i  QX  Y[  Q[  ~M  ao  ]pw@vp>w@x ?ES\y@x JMy@x NTTWLy@x Y\y@x ]ddg[hy@xi/y@@ @Grz|bijlbl  sA  /BA@@ BDA@@ EL  MP  DQA@@ QUA@@ V^  _`  UaA@@ agA@@ ho  pq  grA@@rGA@B HOiC@B P]C@B nuuwmw]i  QX  Y[  Q[  ~M  ao  ]pC@BpGC@D HOqkE@DR/E@L @Grz|bijlbl  sA  /BM@L BDM@L EL  MP  DQM@L QUM@L V^  _b  UcM@L ciM@L jq  ru  ivM@LvGM@N HOiO@N P]O@N nuuwmw]i  QX  Y[  Q[  ~M  ao  ]pO@NpGO@P HOsmQ@PT;Q@^ <F,_@^G;_@` <?w<.a@`I;a@b <C)c@bD;c@d <D*e@dE;e@f <E+g@fF;g@h <QQT:Ui@h+Vi@~  @~"@f	 #,g	@f	 -Ig	@f	 JMWg	@f	W"g	@t	 #+u	@t	,(u	@B
 )2{C
@B
 3>C
@B
 ?InnM]^c>d=eC
@B
 foC
@B
 pzo}o}  O  PU  pV  oWC
@B
WVC
@N
 WhUhO
@N
iXO
@P
 YkWkQ
@P
lWQ
@R
 XiViS
@R
jXS
@T
 YkWkU
@T
lRU
@V
 ShhkQlW
@V
mSW
@X
 TcSgSgfgRhY
@X
iXY
@Z
 YjWj[
@Z
k9[
@H :=W[[Pb=c9d8eI@H fkI@H lssvjwI@HxI@X !!Y@X"$Y@d %/<e@d0e@h 
ww  G  zF  G  G  Hi@hH+i@@ ,/z?*;A@@	< A@R !00S@R1HS@j IR{k@j Sek@j fpdpk@jq9k@l X`9S  fA  9Bm@lBFm@p GWW[E\q@p]Cq@r DOtBTs@rU;s@@ <?w<.A@@ IKA@@ LV,A@@W=A@B >HLC@BICC@D DUBUE@DVCE@F DUBUG@FVLG@H MS8I@HTEI@T V]]_U_\x  AC  yCet  IW  EXU@T XZU@T [b  cf  ZgU@Tg=U@V >FaLW@V IOW@V PWWXkW@V Z_W@V `ggj^kW@Vl>W@X ?Gs^Y@X LRY@X SZZ]Q^Y@X _dY@X ellocpY@Xq<Y@Z =D9[@ZEC[@\ DJ#,]@\ OR]@\ SYY\Q]]@\ ^a]@\ biil`m]@\	n@]@n AR?Ro@nSBo@p CUAUq@pVFq@r GXEXs@rYAs@t BT@Tu@tU@u@v AV?Vw@vW@w@x AP@T@TST?Uy@xVy@\ #^]@\$]@^ #^_@^$_@` $_a@`%a@b $_c@b%c@d &&e@d'e@f %%g@f&g@h "]i@h#i@j &&k@j'k@l %%m@l&m@n %%o@ni&o@DD $C:#sW--GGDM .WW__S!(ST
#>?-b$hZ|CL>Q[\_`j\k[lmn{  
 433     > ^8  		
 .D 0 F FT .--
  :4QC899:s
  AH AH* AHAH* *AH< AI 3AI AI A5AI%AI8%AI=*AJAJ$AJEAJ% E'AJE9B	AJ% HAHHAHHAH'	H!AH* H'AH* H*AH9H8AH9H<AII
AIIAIIAII%AI5I4AI5JAJ"	J	AJ% J%AKJ0AKKAKc                <    V ^8  d   QhR\         R\        R\        /# r7   r  r	  r  r	  )r;   s   "r   r<   r<   
  s+     {@ {@$ {@K {@{ {@r   c           1       a \         P                   ! 4       p\        P                  ! \        4      P	                  R4      pVP
                  o\        4       pR p. pV  EF  p/ p	. p
Rp^ p\        VP                  R4      '       d   VP                  P                  p	\        VP                  R4      '       d   VP                  P                  RXR p
\        VP                  R4      '       d   VP                  P                  4       pMRp\        VP                  R4      '       d   VP                  P                  pVP                  '       d   VP                  RYR M. pTP                  / R	VP                  bR
VP                   '       d   RMRbRV! VP"                  4      bRV! VP$                  4      bRV! VP&                  4      bRV! VP(                  4      bRVP*                  bRVP,                  bRV! VP,                  \/        VP*                  ^4      ,          4      bRV! V4      bRV
 Uu. uF
  q! V4      NK  	  upbRVbRV! V4      bR\        VP                  R4      '       d   VP                  P0                  M^ bRV! VP                  P2                  4      bRV! VP                  P4                  4      bRVP                  P6                  bRV! VP8                  4      RV! VP:                  4      RV! VP<                  4      RV! VP>                  4      RVP@                  RVPB                  R V! VPD                  4      R!V! VPF                  4      R"\I        VPJ                  PM                  4       4      R#\O        VPJ                  4      R$\Q        \S        V	PU                  4       R% R&7      R',          4      R(VRZR  Uu. uF  pR)VPW                  R)4      R*V! VPW                  R*^ 4      4      R+V! VPW                  R+^ 4      4      R,V! VPW                  R-^ 4      4      R.VPW                  R.R/4      R0V! VPW                  R0^ 4      4      R1V! VPW                  R1^ 4      4      /NK  	  up/C4       EK  	  VPY                  R2 R3R47       \S        SPU                  4       R5 R3R47      R6,          pR7TR8TR9R:R;\[        4       R<TR=\\        R>\^        R?\`        R@RA\O        V 4      RV! \c        RB V  4       4      4      RCV! \c        V3RD lV  4       4      4      RE\c        RF V  4       4      RG\c        RH V  4       4      RV! \c        RI V  4       4      \/        \c        RJ V  4       4      ^4      ,          4      RK\c        RL V  4       4      /RMTRNRVP6                  RV! VP2                  4      RV! VP4                  4      RT! \        VR4      '       d   VP                  4       M^ 4      /RORP\O        S4      RQVPe                  4       /RRV UUu/ uF  w  ppVV! V4      bK  	  upp/pRSp \g        VRT4      ;_uu_ 4       p\h        Pj                  ! VV^RU7       RRR4       \l        Po                  RVV 24       R# u upi u upi u uppi   + '       g   i     L:; i  \p         d$   p\r        Pu                  RWT 24        Rp?R# Rp?ii ; i)[z
v9: Write logs/claude_handoff.json -- structured data for Claude analysis.
Jake can paste this file directly to Claude for deep analysis.
Updated every hour alongside the human report.
r	  c                 P    \        \        V 4      ^4      #   \         d     R# i ; i)   N)r  r  rX   rm  s   &r   
safe_float)_write_claude_handoff.<locals>.safe_float  s     %(A&&%%s    %%Nr  r  r  r   r  r  r  rS
  r  r  r  r)  r*  r(  r  rR  r  ic_scorer=  r  r  r  r  r  r	  r  
kelly_winskelly_losseskelly_avg_winkelly_avg_lossr  rW
  r<
  c                     V ^,          ) # r  r   rm  s   &r   ro  '_write_claude_handoff.<locals>.<lambda>J  s
    AaD5r   r  r
  r*
  r   r$  r%  	predictedr&  r(  r,   r*  r+  c                 (    V R ,          ;'       g    ^ # r  r   rm  s   &r   ro  r
  Z  s    !K."5"5A"5r   Tr  c                     V ^,          # r  r   rm  s   &r   ro  r
  ]  s    qtr   rI  r	  r	  r	  r	  r	  r	  r	  r	  r6
  r5
  rc	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r  r	  s   & r   r   (_write_claude_handoff.<locals>.<genexpr>j  s     ,I&Q[[&r	  r:  c              3   D   <"   T F  qP                  S4      x  K  	  R # 5ir	  )r:  )r   r8  ri  s   & r   r   r
  k  s     ,TV^^F-C-CVs    r@	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r	  r	  s   & r   r   r
  l  s     !;Fq((Fr	  rA	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r	  r	  s   & r   r   r
  m  s     !9&Q&&&r	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r	  r	  s   & r   r   r
  n  s     ,DVVVVr	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r	  r	  s   & r   r   r
  n  s     Nhag\]xxagr	  r7
  c              3   L   "   T F  p\        VP                  4      x  K  	  R # 5ir	  r	  r	  s   & r   r   r
  o  s     !CFq#akk"2"2Fr	  r  meta_learnerru   n_pricesr  
top_pricesr   r  rx	  zClaude handoff -> zCLAUDE_HANDOFF_WRITE_ERR | iirx  );r   r   rB   r   rC   ri  r	  r  r  r  r  r  r  r  rS   r  r  r  r  r)  r*  r(  r  r  r=  r  r  r  r  r  r	  r  r  r  r  r   rG   r  r  r   r6  rQ   r   r@  r  r  r  rl  r  rT  r  r.  r~  r  r   r   rX   r   r   )r  r	  r  r^  r=	  r	  r
  ra	  r  r,
  ic_histpsir  r  r*
  rn  rR  top_symbolsr  r[   r	  handoff_pathr   r   ri  s   &&&                     @r   _write_claude_handoffr
  
  s+    yy{F||J'001HIGyyF "C& J288.//))B288\**hh))#$/G288\**,,.JJ288^,,((//K -/JJJ

34(B )
RWW)
W)
 Z

3)
 Z5	)

 Z8)
 Z6)
 RYY)
 RWW)
 Z#bii2C(CD)
 Z
3)
 W=WjmW=)
 [)
 Z
3)
 GBHHl4S4SRXX00YZ)
 Z(8(89)
  Z(:(:;!)
" RXX--#)
$ Z(8(89z"*<*<=Z4Z7R^^R--Z(9(9:Z(:(:;T",,"3"3"56c",,/T&"I#"NO 'st, -A xAEE%O!<AEE)Q,?!@AEE/1,E!Fx!4AEE*a,@!AAEE+q,A!B -;)
 )	) @ OO5tOD ^TJ3OK 	764>+3+:<c&kj,I&,I)IJj,TV,T)TUc!;F!;;c!9&!99j,DV,D)Ds3NhagNhKhjkGl)lmc!CF!CC
 	:$,,*T\\2*T^^4*'$:U:UT__%6[\]	
 	F 0
 	Dfc1sJqM)D;G@ .L@,$$IIgq+ %(78U >$b E
 %$  @:1#>??@sC   0Y2B&Y7:Y<8"Z 6Z Z Z	Z [ Z>>[c                <    V ^8  d   QhR\         R\        R\        /# r
  r	  )r;   s   "r   r<   r<     s&     ^; ^;$ ^;K ^;{ ^;r   c                 N   \        ^
4       \        P                  R4       \        P                  ! \
        4      P                  R4      pRpVP                  4       pTRV R2VP                  4       R\         R\         R\         R\         R	2	R
VP                   RV'       d   VR R2MR R\        VP                  4       2VRR RR RR RR RR RR RR RR RR RR RR R R! R"R! R#R$ R%R! R&R' R(R' 2R.pV  EF!  pVP!                  VP"                  4      pVR),          '       d   R*MR+p	VR,,          e   VR,,          R R2MR.p
VR/,          e   VR/,          R R2MR.pVP%                  VR0,          R V	R R1VR2,          R3 R1VR4,          R3 R1VR5,          R3 R1VR6,          R3 R1VR7,          R3 VR8,          R VR9,          R: V
R VR VR;,          ^d,          R< R=VR>,          ^d,          R< R=VR?,          R$ VR@,          RA VRB,          R' VRC,          R' 24       EK$  	  \'        RD V  4       4      p\'        RE V  4       4      p\'        RF V  4       4      p\'        RG V  4       4      p\'        RH V  4       4      p\'        RI V  4       4      p\'        RJ V  4       4      p\'        RK V  4       4      p\'        RL V  4       4      pW,
          pVV,
          pTRRMVRN ROVR RPVR RQT RRV'       d   VV,          ^d,          M^ RS R=2RTVRN ROVR RPVR RQV RRV\)        V^4      ,          ^d,          RS RUVRN ROVR RPVR RQV RRV\)        V^4      ,          ^d,          RS RV2RW.,          pVP*                  '       dU   VRXRY.,          p\-        VP*                  P/                  4       RZ R[7       F  w  ppVP%                  R\VR] R^VR_ 24       K!  	  \-        V  UUu. uF  qwP0                  RR-  F  pVNK  	  K  	  uppR` RaRb7      Rc,          pV'       Ed3   VRXRd.,          pVP%                  R\RR R^ReRf R^RgR R\RhRi R\RjRi R\RkR! R\RlR! R\RmR! R\RnR! Ro24       VP%                  R4       V F  pVP3                  Rp\5        VRq,          ^d,          VRr,          ^d,          ,
          4      ^d,          4      pVP%                  RsVR0,          Rt RuVRv,          Rf RwVR5,          Rx RyVRq,          Rz R{VRr,          Rz R|VRA R}VP3                  R~^ 4      R R\VP3                  R^ 4      R R\VP3                  R^ 4      R R\VR,           24       K  	  VP%                  VR,           4       \6        P9                  RRP;                  V4      ,           4       \<        P9                  R\>         24        \A        WW&4        \I        WV4       R-# u uppi   \B         d#   p\D        PG                  RT 24        R-p?L=R-p?ii ; i  \B         d$   p\D        PG                  RT 24        R-p?R-# R-p?ii ; i)r   hourly_reportr   zHOURLY REPORT   CSTzCPU cores: z  |  Agents: r   z base + z clones)zMetaLearner: trained=z  discrepancy=r  ppr	  z  profitable_symbols=r	  z<24rh  z>2Equityr	  CashNetPnLGrossWin	GrossLossr	  r	  zWin%AvgDiscr
  RollDisczSL%r	  zTP%MaxPr
  Confr 
  r	  Rstr  rl  Br{  Nz    N/Ar  r  r  r  z>9,.2fr  r$  r)  r*  r(  r'  z>6.1%r  z>5.1fr  r  r  r	  z>5.2fr  r  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r  r	  s   & r   r    hourly_report.<locals>.<genexpr>  s     1&Q[[&r	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  )r)  r	  s   & r   r   r
    s     4V^^Vr	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  )r*  r	  s   & r   r   r
    s     26a\\6r	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r	  r	  s   & r   r   r
    s     .v!XXvr	  c              3   8   "   T F  qP                   x  K  	  R # 5ir	  r	  r	  s   & r   r   r
    s     ,VVVVr	  c              3   <   "   T F  p\        VR R4      x  K  	  R# 5i)r  r   Nr}  r	  s   & r   r   r
    s     I&QWQ3C88&   c              3   <   "   T F  p\        VR R4      x  K  	  R# 5i)r  r   Nr
  r	  s   & r   r   r
    s     G1WQ1#66r
  c              3   <   "   T F  p\        VR ^ 4      x  K  	  R# 5i)r  Nr
  r	  s   & r   r   r
    s     A&QWQ~a00&r
  c              3   <   "   T F  p\        VR ^ 4      x  K  	  R# 5i)r  Nr
  r	  s   & r   r   r
    s     ?1WQ|A..r
  z  TOTALS:  NetPnL=$z>+.2fz  GrossProfit=$z  GrossLoss=$z	  Trades=z
  WinRate=r  z  LONG:   NetPnL=$z%
  SHORT:  NetPnL=$z%
zf  T=type(B=base,C=clone)  AvgDisc=avg pp discrepancy(lower=better)  RollDisc=last-20-trade discrepancyr,   zSector Performance:c                     V ^,          ) # r  r   rm  s   &r   ro  hourly_report.<locals>.<lambda>  s
    qter   r  r	  z<38r  z>+.4fc                 &    \        V R ,          4      # r  )r  r
  s   &r   ro  r
    s    c!E(mr   Tr  rI  z$Top Recent Trades (sorted by |PnL|):r
  r
  PnLzActual%r	  zPred%DiscOwnCfMetaCfEffCfz  Reasonr'  r%  r&  r  r	  r   r   z PnL=r
  z	  actual=r
  z%  pred=r	  zpp  r*  z>5.3fr+  r,  r(  r	  zReport written -> zHUMAN_REPORT_ERR | zCLAUDE_HANDOFF_ERR | z======================================================================================================================================================z------------------------------------------------------------------------------------------------------------------------------------------------------izk  ---------------------------------------------------------------------------------------------------------)%r   r   r	  r   rB   r   rC   r{  r  r	  rf
  BASE_AGENTSCLONE_AGENTSr  r   r  r  ri  rS   rT  r  r  rQ   r   r  r@  r  report_loggerr   r   r   r   r1
  rX   r   r   r
  )r  r	  r  rG	  r	  	meta_discr	  r8  r  tagr  rdr  total_gptotal_gltotal_trd  short_gpshort_glshort_tshort_wlong_net	short_netr  perfrR  
all_tradesr&  r   s   &&&                          r   r
  r
    s   bM_-||J'001DEGC$$&I
'$'

n%]:,bXVbUcckl
~ ./8)C+eD E!$"9"9:;	= 	3-Bx~fS\(3c
;s+HR=R.Bbz%"+fR[r
5*	6 	E ii		"z]]c234E2F2S$%c*"-Yb234F2G2S%&s+2.Ybz#s2ha(F';1Qy\&<Q% !N"3F!;1Q|_V<T{2q/6fRG~c!%(!M*:3*>u)EQ|B*e4Q{^B4G(TVGWY	
  1&11I4V44H2622H.v..G,V,,GI&IIHGGGHA&AAG???G$HH$I	
i.ohs^ Ls^9WI 6*177?3&q=Q	@ Xe,OHS> Js^9WIZGTU@VWZ@Z[^?_ `&u-_XcN Ks^9WIZGTU@VWZ@Z[^?_ `	
	- E 
~~~"+,, 4 4 6OLICLL2c#YaU|45 M4FqIIcdOqOF4#T 
J z"<==r'#abz5*BynB|2fR[72,b"R|8- 	. 	%&A55C)S(81_;Mc;Q(Q$RUX$XYDLLaj%R(B'7 8x'y9f0E F/*62#d5\55A&u-Rk!0DU/K255A&u-R(}	>  
LLttdii../
KK$_$5679F4;f$/9 	52  922$7889  ;4RD9::;s6    W 
%W 2W6 W3W..W36X$XX$c                   0   a  ] tR tRt o RtR tR tRtV tR# )MarketAwareRetrainScheduleri  a  
v9: Simplified scheduler -- intraday retraining removed.
Training fires ONCE per day, 15-30 min after market close.
The _after_hours_train() method handles the full sequential cycle.
The scheduler.tick() is kept for future use but does nothing during hours.
c                .    Wn         RV n        RV n        R# )r  FNr  )callback_last_minute_did_eod)r   r  s   &&r   r  $MarketAwareRetrainScheduler.__init__  s    $!r   c                    R # r	  r   r4  s   &r   tick MarketAwareRetrainScheduler.tick  s     	r   )r  r  r  N)	r   r   r   r   r
  r  r  r   r   r   s   @r   r  r    s     "
 r   r  c                $    V ^8  d   QhR\         /# r6   rO  )r;   s   "r   r<   r<     s       r   c                  >    \        \        P                  ! 4       4      # r	  )r   r   r   r   r   unix_tsr    s    tyy{r   c                0    V ^8  d   QhR\         R\        /# )r7   r   r8   r   r:   )r;   s   "r   r<   r<     s     8 8# 8# 8r   c                ^    V R,
          R,          pVR,          R VR,          ^<,          R R2# )zUnix int -> HHMM CST string (no colon, Python 3.12 safe).
CST = UTC minus 21600 seconds.
Example: unix_ts() -> 1712345678, ts_to_cst(...) -> 1423 CST
`T  re   rc   02dr
  r   )r   r  s   & r   	ts_to_cstr$    s5    
 
euA4i_a$h2-c2$77r   allc                   T   a  ] tR tRt o RtR tV 3R lR ltR tV 3R lR ltR	t	V t
R
# )DataCollectionHealthi  zPer-source diagnostic metrics. Populated by _health.record() calls
throughout the data pipelines. Read by _run_collect_only() health reports.c                   \         P                  ! 4       V n        ^ V n        ^ V n        RV n        RV n        ^ V n        ^ V n        ^ V n	        RV n
        RV n        ^ V n        ^ V n        RV n        RV n        ^ V n        ^ V n        ^ V n        RV n        ^ V n        ^ V n        RV n        RV n        ^ V n        ^ V n        RV n        ^ V n        ^ V n        RV n        ^ V n        R# )r  FNr,   )r  r  r  r  alpaca_errorsalpaca_connectedalpaca_last_baralpaca_consec_failsr  	fh_errorsfh_last_callfh_last_symbolnews_fetchesnews_errorsnews_last_tsnews_last_symbol	sec_scans
sec_errorssec_filings_foundsec_last_ts
st_fetches	st_errors
st_last_tsst_last_symbolreddit_fetchesreddit_errorsreddit_last_tscongress_scanscongress_errorscongress_last_tsdb_bars_writtenr4  s   &r   r  DataCollectionHealth.__init__  s    ^^%
1d0 %dt';#$ A4> $"5!t/ "$"7aDO!"tD$4aT^b 3a!3t9L!5SW4;P r   c                    < V ^8  d   QhRS[ /# )r7   r  r9   )r;   r   s   "r   r<   !DataCollectionHealth.__annotate__2  s     #; #;S #;r   c                8   V P                   ;_uu_ 4        VR 8X  d=   V ;P                  ^,          un        \        P                  ! 4       V n        RV n        EMVR8X  d1   VP                  RR4      V n        VP                  R^ 4      V n        EMnVR8X  dD   V ;P                  ^,          un        VP                  RV P                  ^,           4      V n        EM$VR8X  d}   V ;P                  ^,          un        \        P                  ! 4       V n	        VP                  RR4      V n
        VP                  R	4      '       d   V ;P                  ^,          un        EMVR
8X  d}   V ;P                  ^,          un        \        P                  ! 4       V n        VP                  RR4      V n        VP                  R	4      '       d   V ;P                  ^,          un        EMVR8X  d   V ;P                   ^,          un        \        P                  ! 4       V n        V ;P$                  VP                  R^ 4      ,          un        VP                  R	4      '       d   V ;P&                  ^,          un        EMVR8X  d}   V ;P(                  ^,          un        \        P                  ! 4       V n        VP                  RR4      V n        VP                  R	4      '       d   V ;P.                  ^,          un        EMVR8X  de   V ;P0                  ^,          un        \        P                  ! 4       V n        VP                  R	4      '       d   V ;P4                  ^,          un        MVR8X  de   V ;P6                  ^,          un        \        P                  ! 4       V n        VP                  R	4      '       d   V ;P:                  ^,          un        M0VR8X  d*   V ;P<                  VP                  R^4      ,          un        RRR4       R#   + '       g   i     R# ; i)
alpaca_barTalpaca_connectr  consec_failsalpaca_errorr7  r   r,   r   r  r  filingsr  r  r  db_writer  N)r  r  r   r+  r*  r@  r,  r)  r  r.  r/  r-  r0  r2  r3  r1  r4  r7  r6  r5  r8  r:  r;  r9  r<  r>  r=  r?  rA  r@  rB  )r   r  r  s   &&,r   r  DataCollectionHealth.record2  s   ZZZ<'  A% diikt';(,%+++-66+t+D%+-66.!+D(>)""1,"+-66.373K3Ka3O,Q(9$"		D$5&(ffXr&:#66'??DNNa$7N6!!!Q&!DIIK(9(*x(<%66'??D$4$4$9$45!#		T%5&&"&&A*>>&66'??DOOq$8O<'1$		do&(ffXr&:#66'??DNNa$7N8###q(#		$*=66'??D$6$6!$;$6:%##q(#$))+$*?66'??D$8$8A$=$8:%$$w(::$E ZZZs6   D,PBPBPBPA+P	A*P4A
PP	c                    Vf   R# \         P                   ! 4       V,
          pV^<8  d   VR R2# VR8  d   V^<,          R R2# VR,          R R2# )Nneverr  zs agorc   zm agor  zh ago)r   )r   r   r8  s   && r   r  DataCollectionHealth._ageW  sY    :gIIK"r6qgUO+t8qtCj..D&U##r   c                    < V ^8  d   QhRS[ /# r6   r9   )r;   r   s   "r   r<   rE  ^  s       r   c                z   V P                   ;_uu_ 4        V P                  '       d   R MRV P                   R2pRP                  RR 2RV RV P                  R RV P                  V P                  4       R	V P                   2R
V P                  R RV P                  V P                  4       RV P                   R	V P                   2RV P                  R RV P                  V P                  4       RV P                   R	V P                   2RV P                    RV P"                   RV P                  V P$                  4       R	V P&                   2RV P(                  R RV P                  V P*                  4       RV P,                   R	V P.                   2RV P0                   RV P                  V P2                  4       R	V P4                   2RV P6                   RV P                  V P8                  4       R	V P:                   2RV P<                  R R2RR 2.
4      uuRRR4       #   + '       g   i     R# ; i)	CONNECTEDzDISCONNECTED(fails=r  r	  z[DATA-HEALTH] z[DATA-HEALTH] Alpaca WS  : r  r  z | last_bar=z
 | errors=z![DATA-HEALTH] Finnhub    : calls=z | last=z | sym=z#[DATA-HEALTH] News RSS   : fetches=z![DATA-HEALTH] SEC EDGAR  : scans=z | filings=z#[DATA-HEALTH] StockTwits : fetches=z#[DATA-HEALTH] Reddit     : fetches=z![DATA-HEALTH] Congress   : scans=z[DATA-HEALTH] DB writes  : z barsNz:==========================================================)r  r*  r,  r   r  r  r+  r)  r  r.  r/  r-  r0  r2  r3  r1  r4  r6  r7  r5  r8  r:  r;  r9  r<  r>  r=  r?  rA  r@  rB  )r   r  s   & r   r  DataCollectionHealth.report^  s\   ZZZ!%!6!6!6+,T-E-E,FaH 99 )-bT$:J:J19M N IId&:&:;<JtGYGYFZ\3DMM!3D E		$"3"345WT=P=P<QQ[\`\j\j[km5d6G6G5J K		$"3"345WT=R=R<SS]^b^n^n]oq3DNN3C D112(499TEUEU;V:WWabfbqbqart5dooa5H I		$//2374;N;N:OzZ^ZhZhYik5d6I6I5J K		$"5"567z$BTBTAUW3D4G4G3H I		$"7"789DDXDXCY[-d.B.B1-EUK )#  ZZZs   H	H))H:	)r  r  r*  r,  r)  r+  r@  rA  r?  rB  r  r-  r.  r/  r1  r0  r3  r2  r=  r<  r>  r5  r6  r7  r4  r9  r8  r;  r:  N)r   r   r   r   r
  r  r  r  r  r   r   r   s   @r   r'  r'    s*     R!2#; #;J$ r   r'  c                    ^ RI p   V P                  V P                  4      P                  R,          pV P                  V P                  4      pVP                  pVP
                  p\        P                  ! 4       p \        R4      ;_uu_ 4       p\        R VP                  4       P                  4        4       4      pRRR4       \        XP                  RR4      4      R,          R,          p\        VP                  RR4      4      R,          R,          p	 \        R4      ;_uu_ 4       pVP                  4       P                  4       R	,          p
R
P!                  V
4      pRRR4        ^ RIp\%        TP&                  ! RTP(                  ! 4        R24      4      p\*        P-                  RT RT RX RT RT	 RTR RTR RT 24        \        R4      ;_uu_ 4       p\/        TP                  4       P                  4       ^ ,          4      \0        ,          ^d,          pRRR4       \3        XY4        \        R4      ;_uu_ 4       p\        R TP                  4       P                  4        4       4      p\        TR,          P                  4       ^ ,          4      R,          p\        TR,          P                  4       ^ ,          4      R,          pRT\5        T^4      ,          ,
          pRRR4        \        R4      ;_uu_ 4       pTP7                  4       P                  4       pRRR4       \/        X^,          4      \9        R TR,           4       4      R ,           ,          p \;        X
\<        4      '       d"   \/        T
P                  R
4      ^ ,          4      M\/        T
^ ,          4      p\?        RT\5        \0        ^4      ,          4      p\0        pTR"8  d   \5        ^T^,          4      pMrXR#8  d   ^pMhTR$8  g   TR%8  d   \5        ^T^,          4      pMFTR&8  g   TR'8  d   \5        ^T^,          4      pM$TR8  d   \5        ^T^,          ^,          4      pMTpT\@        8w  d.   \*        P-                  R(\@         R)T R*TR+ R,XR+ R-TR+ 2
4       Ts \D        PF                  ! \H        4       EK    + '       g   i     EL; i  \         d    R/;r ELi ; i  + '       g   i     EL; i  \         d    Rp ELi ; i  \         d    R/p ELi ; i  + '       g   i     EL; i  \         d     ELi ; i  + '       g   i     ELa; i  \         d    Rp ELti ; i  + '       g   i     ELN; i  \         d    R!p EL*i ; i  \         d    R!p ELi ; i  \         d$   p\*        PC                  R.T 24        Rp?EL5Rp?ii ; i)0z
Background thread: logs system resources every 30 seconds.
Writes to debug.log with prefix RESOURCE so you can grep it.
Helps correlate CPU/memory/I/O spikes with Alpaca ping timeouts.
Run: grep RESOURCE ~/trading/debug.log | tail -50
Nr   z/proc/self/ioc              3   V   "   T F  pR V9   g   K  VP                  R 4      x  K!  	  R# 5i)r  Nr	  r	  s   & r   r   )_resource_monitor_loop.<locals>.<genexpr>  s'     #_;QaUY]^U^MAGGDMM;Qr	  rchar0wcharr	  :Nr  Nr  r\  z/proc/z/fdzRESOURCE | rss=zMB | threads=r  z | io_read=zMB | io_write=zMB | cpu_user=r  zs | cpu_sys=zs | fds=rf  c              3   V   "   T F  pR V9   g   K  VP                  R 4      x  K!  	  R# 5ir	  r	  r	  s   & r   r   rW    '     Y5LPSWXPX|qwws||5Lr	  r	  r	  rf   r2   z
/proc/statc              3   8   "   T F  p\        V4      x  K  	  R # 5ir	  r  )r   rn  s   & r   r   rW    s     8Y=aq=r	  :r  NNrP  r   rE  g)\(?g(\?r3   g?g      ?zDYNAMIC_WORKERS | r   | cpu=z.0%z ram=z iowait=zRESOURCE_MONITOR_ERR | r  )%resource	getrusageRUSAGE_SELF	ru_maxrssru_utimeru_stimer  r	  r.  r6  ri  r	  r   r@  rX   r   r   rT   r   r   getpidr   r   r  r	  _record_resource_snapshotr  readlinerT  r  r:   r  r  r   r   rI  _RESOURCE_MONITOR_INTERVAL)_resrss_mbcpuuser_ssys_s	n_threadsr   io_linesread_mbwrite_mbr  r  _osn_fds_lf_cpu_pct_mf_mi
_ram_total
_ram_avail_ram_used_pctr  	_cpu_line_iowait_pct_load1_cpu_pct_now_max_workers_targetr   s                                r   _resource_monitor_loopr    s    
a	>^^D$4$45??4GF ..!1!12CllFllE "..0I(/**b##_2779;O;O;Q#__H +x||Gc:;tCtKx||Gc:;tCtK
/**b779??,R0D"xx~H + CKK&c(BCD !&yk B zWI^H: N"3<|E#;hugO/**c$SXXZ%5%5%7%:;nLsRH +)(FF$/**cYSXXZ5J5J5LYYC!$S_%:%:%<Q%?!@4!GJ!$S%8%>%>%@%C!Dt!KJ$':J8J+J$KM	 +",''3 # 4 4 6I (#IaL1S8Y9UW=8Y5Y\`5`a6@s6K6Ktzz#q12QVW[\]W^Q_  Vc.!.D%DEL*LT!a!23%%)<a!23%)<a!23$a!1Q!67&**!!()9(:$wi H',E-1DH[Y\L]_ $+  	

-.i +**  (%''((
 +**     +**   +**
  $ #$
 (''  "!"  2  	>!8<==	>s  A4V+ <S /R<>AS S9 ,7S%#S9 ,2T /V+ T5 !AT!"T5 7U 
B%U/U 8V U/*?V *A	V 3C,V+ <S		S S"V+ !S""V+ %S6	0S9 4V+ 6S9 9T
V+ 	T

V+ TV+ TV+ !T2	,	T5 5U V+ UV+ U	U V+ U U,(V+ +U,,V+ /V 	:	V VV+ VV+ V($V+ 'V((V+ +W6WWc                     \         P                  ! \        RRR7      p V P                  4        \        P                  R4       R# )z-Start the resource monitor background thread.TResourceMonitorr  z'RESOURCE_MONITOR_STARTED | interval=30sN)r  r  r  r  r   r   r
  s    r   start_resource_monitorr    s2     6t/	1AGGI?@r   gffffff?r  r  c                $    V ^8  d   QhR\         /# )r7   r  rO  )r;   s   "r   r<   r<     s      S r   c                d     \         P                  ! V 4       R#   \        \        3 d     R# i ; i)zSet CPU scheduling priority of the current thread.
Negative = higher priority, positive = lower. Range: -20 to 19.
Silently ignored if process lacks permission to increase priority.N)rr  nicePermissionErrorOSError)r  s   &r   r   r     s)    W% s    //c                $    V ^8  d   QhR\         /# r6   rO  )r;   s   "r   r<   r<   )  s       r   c                      \        R4       FC  p V P                  R4      '       g   K  \        V P                  4       ^,          4      R,          u # 	  ^ #   \         d     ^ # i ; i)z7Current process RSS in MB. Zero-cost diagnostic helper.r]  r^  r   r_  )r`  s    r   _rss_mbr  )  s\    ,-Dx((4::<?+t33 .
   rc  c                $    V ^8  d   QhR\         /# r7   r  r9   )r;   s   "r   r<   r<   3  s     I IC Ir   c           	         \        4       p\        ;'       g    ^ pV'       d   W,          ^d,          R R2MRp\        P                  RV  RVR RV R24       \        P                  R	V  R
V RV R24       R# )zCLog current RSS to both trading.log and debug.log with a clear tag.r  z% of capuncappedz[RAM] r   r  ra
  r  zRAM_TRACE | rg  z	MB | cap=r  N)r  rh  r   r   r   )r  mbcaprc  s   &   r   rl  rl  3  ss    	B
//C),RVCZH
%*C
KK&s2a&cU!45UG72$iuBGHr   c                      a  ] tR tRt o RtV 3R lR ltR tR tRV 3R lR lltRV 3R	 lR
 llt	]
V 3R lR l4       t]
V 3R lR l4       t]
V 3R lR l4       tRtV tR# )ResourceGuardi;  a  
Central resource monitor and throttle controller.
All background threads call yield_p3() or yield_p4() between work units
to cooperatively yield when the system is under load.

Usage in a background thread:
    _resource_guard.yield_p4()   # will sleep if load is high
    do_expensive_backup_work()
    _resource_guard.yield_p4()   # check again after work

Grep debug.log for 'RESOURCE_GUARD' to see throttle events.
Grep debug.log for 'RESOURCE |' to see load history.
c                    < V ^8  d   QhRS[ /# )r7   ncpusrO  )r;   r   s   "r   r<   ResourceGuard.__annotate__J  s     ! !c !r   c                    \        V^4      V n        \        P                  ! 4       V n        RV n        RV n        RV n        RV n        RV n	        RV n
        RV n        ^ V n        RV n        RV n        R# )r  r   F  N)r  r  r  r  r  _load_1m_load_5m	_load_15m_throttle_p3_throttle_p4	_pause_p4rn  r  _ram_total_mb_ram_pct)r   r  s   &&r   r  ResourceGuard.__init__J  sg     ]
&^^-
   """"! r   c           	         RV n         \        P                  ! V P                  RRR7      P	                  4        \
        P                  RV P                   R\        ^d,          R R\        ^d,          R R24       R	# )
z.Start the background resource monitoring loop.Tr  r  zRESOURCE_GUARD_START | ncpus=z | nominal=r  z% | cap=r  N)
rn  r  r  _loopr  r   r   r  LOAD_NOMINALLOAD_CAPr4  s   &r   r  ResourceGuard.startX  si    

4-	//4uw+DJJ< 8#C',HXc\#4FaI	
r   c                N   \        ^ 4       V P                  '       Ed    \        R4      ;_uu_ 4       pVP                  4       P	                  4       pRRR4       \        X^ ,          4      p\        R4      ;_uu_ 4       p\        R VP                  4       P                  4        4       4      pRRR4       \        XP                  RR4      P	                  4       ^ ,          4      R,          p\        VP                  RR	4      P	                  4       ^ ,          4      R,          pWg,
          pV\        V^4      ,          p	\        e4   V\        \        R
,          4      8  p
V\        \        R,          4      8  pM
V	R8  p
V	R8  p\        V^,          4      p\        V^,          4      pW0P                  ,          pV\        8  ;'       g    T
pV\        8  ;'       g    T
pV\        8  ;'       g    TpV P                  ;_uu_ 4        V P                   V P"                  3pW0n        Wn        W`n        Wn        Wn        Wn        Wn        VV n        VV n        RRR4       VV3pVX8w  d^   \2        P5                  RVR RV P                   RV^d,          R RV RV RV	^d,          R RV RV RV^ ,           RV^,           R24       \2        P7                  RVR RVR RVR RV^d,          R RT RT RV	^d,          R RV'       d   R MV'       d   R!MR" 24       \:        P<                  ! \>        4       EK-  R#   + '       g   i     EL; i  + '       g   i     EL; i  + '       g   i     EL; i  \8         d#   p\2        P7                  R#T 24        Rp?LRp?ii ; i)$r  r	  Nrf  c              3   V   "   T F  pR V9   g   K  VP                  R 4      x  K!  	  R# 5ir	  r	  r	  s   & r   r   &ResourceGuard._loop.<locals>.<genexpr>m  r\  r	  r	  z
7400000 kBr   r	  z
4000000 kBr3   
ףp=
?g333333?r  z#RESOURCE_GUARD_STATE_CHANGE | load=r  r  zcpu (r  z	%) | ram=MB/zMB (z%) | throttle_p3=z | pause_p4=z	 | prev=(r  r  zRESOURCE_GUARD | load=r^  z% | ram=zMB(z%) | state=PAUSE_P4THROTTLENOMINALzRESOURCE_GUARD_ERR | ) r   rn  r.  ri  r   r  r6  r	  r   r@  r  rh  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   rX   r   rI  RESOURCE_CHECK_INTERVAL)r   r   r	  r	  rv  rw  	_total_mb	_avail_mb_used_mbr  _ram_throttle
_ram_pauser	  r	  load_pctthrottle_p3throttle_p4pause_p4
prev_state	new_stater   s   &                    r   r  ResourceGuard._loopb  sH   !mmm<@/**bGGIOO-E + q? /**cYSXXZ5J5J5LYYC +
| D J J LQ OPTXX	| D J J LQ OPTXX	%1$s9a'88 )$,s:3D/E$EM$,s:3D/E$EJ$,tOM$,tOJ q? q?"ZZ/',6HH=',6HH='(2EE:ZZZ"&"3"3T^^!DJ(/M(0%(1&(0M(/M(0N(3%(3D%(0DN   )(3	
* %%  '}Adjj\x|C>P Q'jI;d8C<:L M''2m<z J!!+AqAq	B "",WSM73-qRU W#C<, -#*C	{#hsl35G H+3Z{Xabd JJ./  +**
 +**,  ZZ<  @""%:1##>??@sy   M7 L;-M7 ?/M.D.M7 M7 0M7 AM#B/M7 	M7 
M7 ;M		M7 M 		M7 #M4	.	M7 7N$NN$c                    < V ^8  d   QhRS[ /# r  r9   )r;   r   s   "r   r<   r    s     + +c +r   c                   V P                   ;_uu_ 4        V P                  pRRR4       X'       d=   \        P                  RV R\         R24       \
        P                  ! \        4       R# R#   + '       g   i     LV; i)z|Cooperative yield point for P3 (LOW) threads.
Sleeps extra when system load is high. Always returns -- never blocks forever.NzRESOURCE_GUARD_THROTTLE_P3 | 	 | sleep=r  )r  r  r   r   _THROTTLE_DELAY_P3r   rI  )r   r  throttles   && r   r	  ResourceGuard.yield_p3  s[     ZZZ((H !>ugYOaNbbcdeJJ)*  Zs   A00B 	c                    < V ^8  d   QhRS[ /# r  r9   )r;   r   s   "r   r<   r    s     + +c +r   c           	        V P                   ;_uu_ 4        V P                  pV P                  pRRR4       X'       dL   \        P	                  RV R\
        ^d,          R R\         R24       \        P                  ! \        4       R# X'       d=   \        P                  RV R\         R24       \        P                  ! \        4       R# R#   + '       g   i     L; i)	zmCooperative yield point for P4 (BACKGROUND) threads.
Pauses when load is at cap, sleeps extra when throttled.NzRESOURCE_GUARD_PAUSE_P4 | z | load_cap=r  z% exceeded | pausing r  zRESOURCE_GUARD_THROTTLE_P4 | r  )r  r  r  r   r   r  _PAUSE_DELAY_P4r   rI  r   _THROTTLE_DELAY_P4)r   r  pauser  s   &&  r   r   ResourceGuard.yield_p4  s     ZZZnnE((H  ,UG 4$SL--B?BSSTV JJ'!>ugYOaNbbcdeJJ)*  Zs   CC	c                    < V ^8  d   QhRS[ /# r6   r  )r;   r   s   "r   r<   r    s     . .% .r   c                    V P                   ;_uu_ 4        V P                  V P                  ,          uuR R R 4       #   + '       g   i     R # ; ir	  )r  r  r  r4  s   &r   r  ResourceGuard.load_pct  s'    ZZZ==4::- ZZZs	   =A	c                    < V ^8  d   QhRS[ /# r6   r9   )r;   r   s   "r   r<   r    s     	P 	P 	Pr   c           	        V P                   ;_uu_ 4        V P                  V P                  ,          ^d,          pV P                  ^d,          pV P                  pV P
                  '       d   RVR RV RVR R2uuRRR4       # V P                  '       d   RVR RV RVR R2uuRRR4       # R	VR RV RVR R
2uuRRR4       #   + '       g   i     R# ; i)r8  zCRITICAL(cpu=r  z%,ram=r  z%) P4-PAUSEDNz	HIGH(cpu=z%) P3-P4-THROTTLEDzNOMINAL(cpu=r	  )r  r  r  r  r  r  r  )r   r	  r	  ram_mbs   &   r   r  ResourceGuard.status  s    ZZZmmdjj036Gmmc)G''F~~~&wsm6&WSMQ]^ Z """"73-vfXSM_` Z "'#fVHC}BO ZZZs   A#CCC-CC	c                    < V ^8  d   QhRS[ /# r6   r9   )r;   r   s   "r   r<   r    s     S S# Sr   c                    V P                   ;_uu_ 4        V P                  R  RV P                  R  RV P                  R  2uuRRR4       #   + '       g   i     R# ; i)r  r  N)r  r  r  r  r4  s   &r   r  ResourceGuard.load_str  s@    ZZZmmC($--)<AdnnS=QR ZZZs   +AA	)r  r  r  r  r  r  r  r  rn  r  r  r  Nr  )r   r   r   r   r
  r  r  r  r	  r   r  r  r  r  r   r   r   s   @r   r  r  ;  st     ! !
A0F+ ++ +  . . 	P 	P S Sr   r  c                <    V ^8  d   QhR\         R\        R\        /# )r7   r	  r  rn  r  r   )r;   s   "r   r<   r<     s!     * *u *c *c *r   c                    \         ;_uu_ 4        \        P                  \        P                  ! 4       WV34       \	        \        4      R8  d
   \        RR1 RRR4       R#   + '       g   i     R# ; i)zCCalled by resource monitor loop every 30s. Appends to history list.i@  Ni)_resource_history_lock_resource_historyrS   r   r   )r	  r  rn  s   &&&r   rf  rf    sL    		  $))+w	!JK !D(!&5&)	 
 			s   A	A""A3	c            	     
    ^ RI p V P                  ! R4       ^ RIHp ^ RIHp ^ RIHp \        ;_uu_ 4        \        \        4      pRRR4       \        X4      ^8  d   \        P                  R4       R# V UUu. uF  vrVVP                  V4      NK  	  pppV UUu. uF  w  rh qhNK
  	  p	ppV UU
u. uF  w   rjqjNK
  	  ppp
V UUu. uF	  w    rlVNK  	  pppVP                  ! ^^R<RR7      w  pw  pppVP                  RVP!                  4       P#                  R4       2^R	R
7       VP%                  WyRRR7       VP'                  WyRRR7       VP)                  \*        ^d,          RR^R\*        ^d,          R R2R7       VP)                  \,        ^d,          RR^R\,        ^d,          R R2R7       VP/                  R4       VP1                  ^ \3        \3        V	4      R,          ^n4      4       VP5                  ^R7       VP7                  RRR7       VP%                  W{RRR7       VP'                  W{RRR7       \8        e   \8        MRp\8        '       d   \;        VR,          4      M
\;        R=4      p\8        '       d   \;        VR ,          4      M
\;        R>4      pVP)                  VRR^R!V R"2R7       VP)                  VRR^R#V R"2R7       \8        '       d+   VP)                  \8        R$R%R&R'\8        R(,          R) R*2R7       VP/                  R+4       VP1                  ^ VR,,           4       VP5                  ^R7       VP7                  RRR7       VP'                  W}R-^R7       VP%                  W}RR-R7       VP/                  R.4       VP1                  ^ \3        \3        V4      ^,           ^4      4       VP7                  RRR7       VP<                  P?                  VPA                  R/4      4       VP<                  PC                  VPE                  4       4       VPF                  ! ^R07       VPH                  ! 4        VP!                  4       P#                  R14      p\J        PL                  PO                  \P        R2V R324      pVPR                  ! V^dR4R57       VPT                  ! V4       \V        PY                  R6V 24       \        PY                  R7V R8\        V4       24       R#   + '       g   i     EL; iu uppi u uppi u up
pi u uppi   \Z         d    \        P                  R94        R# \\         d&   p\        P_                  R:T 2RR;7        Rp?R# Rp?ii ; i)?z
Generate a resource usage chart (CPU%, RAM MB, thread count) and save to charts/.
Called once after market close alongside the accuracy chart.
Uses only stdlib if matplotlib is unavailable.
Nr   )r   z+RESOURCE_GRAPH | not enough data points yetT)r  sharexzResource Usage -- r  r  )r  r  r4   	steelblue)r  r  r  r	  oranger  z	Nominal (r  r	  )r  r  r  r  redzCap (z
CPU Load %皙?)r  rE  )r  coralr  r3   r  z
Throttle (r  zPause (darkredr	  rh   z
Hard cap (r   r  zGB)zRAM Used (MB)ra   mediumpurplezActive Threadsr	  r	  r  
resources_r  r  )r  r  zResource chart saved -> zRESOURCE_GRAPH_SAVED | z | samples=z;RESOURCE_GRAPH | matplotlib not available -- skipping chartzRESOURCE_GRAPH_ERR | r   )   r   g     @g     @)0r*	  usematplotlib.pyplotpyplotmatplotlib.datesr8	  r   r  rG   r  r   r   r   r  r	  r	  rB   rC   r0	  r/	  r1	  r  r  r3	  r2	  r  r&	  gridrh  r   r6	  r7	  r9	  set_major_locatorHourLocatorxticksr'	  rT   rU   r   r   r(	  r  r   r   ImportErrorrX   r   )r*	  r	  mdatesr  r  rR  r>   
timestampsr[  cpu_pctsr  ram_mbsr  r
  figax1rl	  ax3_cap_mb_thr_mb_pau_mbr   out_pathr   s                           r   generate_resource_graphr    s   HGu')+##,-G $ w<!  !NO7>?weab&&q)w
?*12'JA!Qa'2*12'JAqQa'2*12'JAq!a'2"||Aq(4P_c3)"&&(*;*;J*G)HITVcij 	SL[CHL3&h$RS]fgstwgwx{f||~[  	AHsN%41V[\deh\hil[mmoTpq|$QCMC/56

A
S! 	CwGGsC * 6*D)3#gn%[9I)3#gn%[9IG8tq&wis3 	 	5G5DA#G9C0 	 	2:KK
)sc *:d?3*?sC  E'Q#&

A
S! 	NaHC~N'(QCL1,b12S!		%%f&:&:7&CD		##F$6$6$89

BVVX}-77<<
jD,ABH#7;		#.xj9:3H:[WWXy $## @222h  \Z[ G21#6FFGs   6T$ S8-T$ 7T$ <TT$ T-T$ 5TT$ TFT$ (T$ AT$ $HT$ 8T		!T$ $ U6U6U6U11U6c                   f   a  ] tR tRt o RtRtRtRtR tR t	V 3R lR	 lt
R
 tV 3R lR ltRtV tR# )ProcessAllocatori6  zDynamic process budget based on CPU count and available RAM.
Uses processes (not threads) for CPU-bound work so each worker
gets its own Python interpreter and GIL.
g?rE  rg   c                   ^ RI pVP                  4       ;'       g    ^V n        V P                  4       w  V n        V n        V P                  V P                  RR7      V n        V P                  V P                  RR7      V n
        R# )r  Nrf   )max_cpu_fracr2   )multiprocessing	cpu_countn_cpus	_read_ramram_total_gbram_avail_gb_calcRAM_PER_TRAIN_GBr  RAM_PER_FEATURE_GBfeature_procs)r   _mps   & r   r  ProcessAllocator.__init__?  sg    %mmo**/3~~/?,4,"jj)>)>sjS"jj)@)@sjSr   c                    \        R 4      ;_uu_ 4       p\        R VP                  4       P                  4        4       4      pRRR4       \	        XR,          P                  4       ^ ,          4      R,          R,          p\	        VR,          P                  4       ^ ,          4      R,          R,          pW43#   + '       g   i     L}; i  \         d    Ru # i ; i)rf  c              3   V   "   T F  pR V9   g   K  VP                  R 4      x  K!  	  R# 5ir	  r	  r	  s   & r   r   -ProcessAllocator._read_ram.<locals>.<genexpr>I  s%     S0F1#QR(,!''#,,0Fr	  Nr	  r   r	  )rQ  rg   )r.  r6  ri  r	  r   r   rX   )r   r   r	  r  avails   &    r   r  ProcessAllocator._read_ramF  s    	o&&"S	0D0D0FSS ':,,.q12=DE>*002156=DE<	 '&
  	O	s)   C /B9A4C 9C		C CCc                ,   < V ^8  d   QhRS[ RS[ RS[/# )r7   ram_per_procr  r8   r  )r;   r   s   "r   r<   ProcessAllocator.__annotate__P  s"     	 	% 	u 	 	r   c                *   \        ^\        V P                  ^,
          V,          4      4      p\        ^\        V P                  V P                  ,
          V,          4      4      p\        ^\        W4^4      4      p\        e   \        V\        4      # V# r  )r  r   r  r  RAM_HEADROOM_GBr  r  )r   r  r  
usable_cpu
usable_ramr  s   &&&   r   r  ProcessAllocator._calcP  sy    CqL @AB
C!5!55E
 
 1c*"56&t_--r   c                    V P                  4       w  qn        V P                  V P                  R 4      V n        V P                  V P
                  R4      V n        R# )rf   r2   N)r  r  r  r  r  r  r  )r   r>   s   & r   r  "ProcessAllocator.refresh_avail_ram[  sF    #~~/"jj)>)>#F"jj)@)@#Fr   c                    < V ^8  d   QhRS[ /# r6   r9   )r;   r   s   "r   r<   r  `  s     
 
 
r   c           
         R V P                    RV P                  R RV P                  R RV P                   RV P                   2
# )zProcessAllocator | cpus=r  r  r]
  z GB avail | training_procs=z | feature_procs=)r  r   r  r  r  r4  s   &r   r  ProcessAllocator.status`  sZ    &t{{m 4$$S)0A0A#/F G"1122CDDVDVCWY	
r   )r  r  r  r   r  N)r   r   r   r   r
  r  r  r  r  r  r  r  r  r   r   r   s   @r   r  r  6  sB      OT	 	G

 
r   r  )r  c                      a  ] tR tRt o R!V 3R lR lltV 3R lR ltR tR tR	 tV 3R
 lR lt	V 3R lR lt
R tV 3R lR ltV 3R lR ltR tR tR tR tR tR tR tR tR tR tR tR tR tR tV tR# )"TradingSystemip  Nc                ,   < V ^8  d   QhRS[ RS[RS[/# )r7   r	  active_sourcestrading_mode)r  r  r:   )r;   r   s   "r   r<   TradingSystem.__annotate__q  s#     /( /(T /(3 /(]` /(r   c                   Wn         T;'       g    R 0V n        \        V n        W0n        VR9   V n        VR9   V n        \        4       V n        \        4       V n
        \         Uu/ uF  qDR,          \        VR,          V4      bK  	  upV n        \         Uu. uF1  p\        W@P                  VR,          ,          V P                  4      NK3  	  upV n        RRRRRRRRR	R
RR/p\        WPP                  \!        4       4      V n        RV n        ^ V n        ^2V n        \+        V P,                  4      V n        RV n        RV n        RV n        RV n        R
V n        R
V n        V P=                  4       V n        RV n         RV n!        V PE                  4       p\F        PH                  ! \J        4      PM                  R4      pVPO                  R4      V8H  V n(        VPO                  R4      V8H  V n)        V PP                  '       d   \T        PW                  RV R24       V PR                  '       d   \T        PW                  RV R24       RV n,        RV n-        RV n.        R# u upi u upi )r%  r  r  r  r2   r  r-   r  皙?r  Fr  r  r   r  r?
  r@
  z%[TrainGuard] EOD already done today (z) -- skippingz/[TrainGuard] Weekend train already done today (N)longboth)r|  r#  r  )/r	  r  _healthhealthr  
allow_longrA  r  r	  r  r  AGENT_CONFIGSr  rq   r  r  r  r{	  _last_watcher_checkcyclefeat_rebuild_everyr  _retrain_retrain_scheduler_last_chart_hour_last_av_fetch_last_report_slot_last_state_save_initial_train_done_fetch_thread_running_load_train_checkpoint_train_checkpoint_idx_last_train_check_ts_last_weekend_check_ts_load_train_doner   rB   r  rC   r@  _after_hours_train_done_weekend_train_doner   r   _last_heartbeat_last_github_push_ts_last_github_backup)r   r	  r  r  r[  	_meta_cfg_done_todays   &&&&    r   r  TradingSystem.__init__q  s%   *,77%**.>>*.??!m!m	DQRMqy*QvY"::MR -/ -1 $A{{1V9'=tyyI -/ M#3S%5t13
	
 'y))\^L#& $%
$&$?$N$&$'$&$'$) %*"&*&A&A&C"&)!&)#%%'i(11*=(-		*(=(G$(-		.(AV(K '''KK?x}UV###KKI&Q^_`$'$'!$' I S/s   $#I7I c                &   < V ^8  d   QhRS[ RS[/# )r7   r  r8   rJ  )r;   r   s   "r   r<   r    s     M MS MT Mr   c                t    V P                   '       g   R# RV P                  9   ;'       g    WP                  9   # )zReturn True if the given data source is enabled.
In collect-only mode respects --sources flag.
In full trading mode all sources are always active.
Tr%  )r	  r  )r   r  s   &&r   _source_activeTradingSystem._source_active  s5    
    +++LLv9L9L/LLr   c           	        \         P                  R+4       \         P                  R4       \         P                  R\         24       \         P                  R\         24       \         P                  R\         24       \         P                  R\
         24       \         P                  R4       \         P                  R4       \         P                  R4       \         P                  R	\         R
24       \         P                  R\         24       \        '       d#   \        '       d   \         P                  R4       M*\         P                  R4       \         P                  R4       \         P                  R+4       \        4        \        R4       V P                  P                  4        \        R4       V P                  '       g   \        R4       V P                    F  pVP"                  P%                  4        K  	  V P&                  P%                  4        \        R4       \)        V P                   V P&                  V P*                  4       \        R4       M\         P                  R4       \        R4       V P                  P-                  4       p\        RV R24       \         P                  RV R24       V^ 8  d.   \        R4       V P/                  4        \        R4       RV n        V P                  P3                  4       p\5        VP7                  4       4      p\9        V P                  P:                  4      p\         P                  RVR R\9        V4       R V R!24       V^d8  d   \         P                  R"\<         R#24       \        R$4       V P?                  R%4      '       d&   V P                  P@                  PC                  4        M\         P                  R&4       V P                  PD                  PC                  4        \         P                  R'4       \        R(4       \G        4        \H        PC                  4        \        R)4       \         P                  R*4       R# ),r	  z@ML Trading System v8 - Alpaca + Finnhub + Sentiment IntelligencezCPU cores    : zBase agents  : zClone agents : zTotal agents : z5MetaLearner  : trading as 33rd agent ($1,000 capital)z5Retrain      : every 15 min during market hours + EODzIData sources : Alpaca WS (all IEX bars) + Finnhub (58/min) + AV + PolygonzCharts       : z/  hourly accuracy PNGzTrade CSV    : z8Alpaca       : keys set, WebSocket will connect on startz?Alpaca       : no keys set (ALPACA_API_KEY / ALPACA_SECRET_KEY)zL               Sign up free at alpaca.markets to enable ~8,000 symbol streamzstartup baselinezafter load_sectorszbefore model loadz)after model load (32 PKL files in memory)zafter agent state restorez>[COLLECT-ONLY] Agent/model loading SKIPPED -- trading disabledzbefore rebuild_all_featureszafter rebuild_all_features (r  zFeatures built for z symbols from existing DB datazbefore _retrainzafter _retrainTzDB: r  z quotes across z symbols (+z history DB(s))z>>> First run --- need z quotes/symbol to trade.zbefore Alpaca WS startr  z4[COLLECT-ONLY] Alpaca WS: DISABLED by --sources flagz>Sentiment    : engine started (news + SEC + reddit + congress)zafter sentiment engine startzfully initializedzReady.
z<============================================================)%r   r   r	  r  r  rf
  r   r-  r%   r'   r   r2  rl  r	  r6  r	  r  r  r  r  r	  r{	  ru  r+  r1  r0  rT  r  r   r  r  rC  r  r  r  r  r   )r   r8  r  r.  r  rb	  s   &     r   
initializeTradingSystem.initialize  s   HVWon%567ok]34ol^45oj\23KMKM_aoj\1GHIon%567>//KKRTNN\]NNijH#$%&   ()[[ !IINN@A diiI01KKXY./GG((*/s)<=)!,JKLq5&'MMO%&'+D$002V]]_%TWW))*d5)?3v;-{4&P_`a3;KK12C1DD\]^)*x((GG##%KKNO!TU/0 $%Jr   c                    \        R4       V P                  '       dE   \        4       '       d   V P                  P	                  4        K>  \
        P                  ! ^4       KV  R# )z
Background thread: Finnhub round-robin polling at 58 calls/min.
Supplements Alpaca bars with sub-minute quote confirmation for
the active 300-stock universe.
Nr  )r   r2  r  r	  rD  r   rI  r4  s   &r   _fetch_loopTradingSystem._fetch_loop  s@     	"(((((*

1	 )r   c           	        \        4       '       d   \        P                  R4       R#  ^ RIpVP                  R4       F  pVR,           p\        P
                  P                  V4      '       g   K3  \        P
                  P                  V4      R,          R,          pV^28  g   Ki  \        P                  ! V^R7      ;_uu_ 4       pVP                  R4      P                  4       pRRR4       \        P                  R\        P
                  P                  V4       R	V R
X 24       K  	  V P                  P!                  4        V P                  P#                  4        \%        V P&                  V P(                  V P                  P*                  V P,                  4       \        P                  R4       R#   + '       g   i     L; i  \         d#   p\        P                  RT 24        Rp?LRp?ii ; i)u  
During market hours: skipped entirely.
Training now happens after market close to avoid competing with
Alpaca WebSocket, DB writes, and trading decisions simultaneously.
This was the cause of silent crashes — parallel training 32 models
on five hundred thousand rows while Alpaca was also writing to SQLite caused thread
collisions that killed the process with no Python error logged.
RETRAIN_SKIPPED_MARKET_OPENNzdata/trading_data_????????.dbrM   r   r   r   zWAL_CHECKPOINT | z | was=zMB | result=zWAL_CHECKPOINT_ERR | $RETRAIN_AFTER_HOURS_FEATURES_REBUILT)r  r   r   rO   rT   rU   rV   r   r   r   r   fetchoner   r   rX   r	  ru  r{  r|	  r  r  ri  r{	  )r   _gr   _wal_wal_mb_wcri  _wes   &       r   r+  TradingSystem._retrain  sl    <=	>ww>?V|77>>$'' ggood3t;tCG|$__S!<<#&;;/O#P#Y#Y#[D =$))/0@0@0E/F G##*)<v? @ 	$$&""$T[[$))TWW^^T__U@A =<  	>!6se<==	>s=   AG 11G ' G  F9'AG 9G	G G9G44G9c                    < V ^8  d   QhRS[ /# r6   rO  )r;   r   s   "r   r<   r    s       r   c           	         \         P                  P                  \        4      '       d   \        P
                  ! \        \        4      4      p\        VP                  R^ 4      4      pVP                  RR4      p\        P                  ! \        4      P                  R4      pW48X  d/   \        P                  RV RVP                  RR4       R	24       V# ^ #   \         d$   p\         P#                  R
T 24        Rp?^ # Rp?ii ; i)z?v9: Load the last completed agent index for round-robin resume.r_
  r  r,   r  z0[CHECKPOINT] Resuming training from agent index z (crashed at r^
  r\  r  zCHECKPOINT_LOAD_ERR | N)rT   rU   rV   TRAIN_CHECKPOINT_FILEr~  r  r.  r   r@  r   rB   r  rC   r   r   rX   r   r   )r   r  rC  r  r^   r   s   &     r   r3  $TradingSystem._load_train_checkpoint  s    
	?ww~~344IId#89:!%% 0!45uuVR( Y/88D=KK"RSVRWWdefejejk{|  fA  eB  BC  !D  EJ   	?  #9!!=>>	?s   (C B,C D%DDc                &   < V ^8  d   QhRS[ RS[/# )r7   next_idxr^
  r   )r;   r   s   "r   r<   r  .  s     	? 	?s 	?C 	?r   c                d    \         P                  ! R \        P                  ! \        4      P                  R4      RVRVR\        P                  ! \        4      P                  R4      /\        \        R4      ^R7       R	#   \         d$   p\        P                  RT 24        R	p?R	# R	p?ii ; i)
r  r  r_
  r^
  saved_atr	  r  rx	  zCHECKPOINT_SAVE_ERR | N)r~  r  r   rB   r  rC   r   r.  rW  rX   r   r   )r   rZ  r^
  r   s   &&& r   _save_train_checkpoint$TradingSystem._save_train_checkpoint.  s    	?II(,,y"9"B"B:"N ( .(,,z":"C"CD["\	
 )3/;  	?  #9!!=>>	?s   A=B B/B**B/c                     \         P                  P                  \        4      '       d   \         P                  ! \        4       R # R #   \
         d     R # i ; ir	  )rT   rU   rV   rW  rW   rX   r4  s   &r   _clear_train_checkpoint%TradingSystem._clear_train_checkpoint9  s?    	ww~~344		/0 5 		s   (A	 A	 	AAc                    < V ^8  d   QhRS[ /# r6   r5  )r;   r   s   "r   r<   r  @  s      $ r   c                     \         P                  P                  \        4      '       d$   \        P
                  ! \        \        4      4      #  / #   \         d     / # i ; i)z4Load the persistent one-per-day training guard file.)rT   rU   rV   TRAIN_DONE_FILEr~  r  r.  rX   r4  s   &r   r7  TradingSystem._load_train_done@  sS    	ww~~o..yyo!677 / 	  			s   (A "A A A c                    < V ^8  d   QhRS[ /# )r7   ry  r9   )r;   r   s   "r   r<   r  I  s     ? ?C ?r   c                    \         P                  ! \        4      P                  R4      pV P	                  4       pW#V&   \         P                  ! \
        4      P                  R4      VR&   \        P                  ! V\        \        R4      ^R7       \        P                  RV RV 24       R	#   \         d$   p\        P                  RT 24        R	p?R	# R	p?ii ; i)
z
Write today's date under 'key' (eod_date or weekend_date) to
TRAIN_DONE_FILE so that bot restarts on the same calendar day
will not re-trigger training.
r  r	  r\  r  rx	  z[TrainGuard] u    written → zTRAIN_DONE_SAVE_ERR | N)r   rB   r  rC   r7  r   r~  r  r.  rd  r   r   rX   r   r   )r   ry  r^   ru   r   s   &&   r   _save_train_doneTradingSystem._save_train_doneI  s    	?LL+44Z@E))+DI'||J7@@AXYDIIdD#6qAKK-uM%AB 	?  #9!!=>>	?s   B+B/ /C:CCc                d  a aaaa \         P                   ! 4       p\        P                  ! \        4      P	                  R4      p\
        P                  RV 24       \        P                  R\        S P                  P                  4       R\        S P                  4       RS P                   24       \        R4       \
        P                  R4        \        S P                  S P                   .,           S P                  S P"                  4       \%        S P                  S P                   .,           S P                  S P"                  4       \
        P                  R
4       S P                  P+                  4       p\
        P                  RV R24       S P                  P-                  4        S P                  P                  '       g   \
        P)                  R4       R	# \/        R S P                  P                  P1                  4        4       4      p\        P                  RVR R\        S P                  P                  4       24       \
        P                  R4       S P                  P3                  4       pV'       g   \
        P)                  R4       \        P                  ! \4        4      P	                  R4      pS P                  P7                  V4      oS'       g,   \
        P)                  R4       S P                  P                  o\
        P                  R\/        R SP1                  4        4       4      R R\        S4       R24       \9        S P                  P;                  4       R R7      p\        V4      oS P                  S,          p	^ p
^ p^ p\<        e   \<        M^p\
        P                  RS RV R\>         24       ^ R	I o^ R	I!oVVVV V3R lp\E        S4       Uu. uFK  pW,           S,          WV,           S,          ,          ^ ,          WV,           S,          ,          ^,          3NKM  	  pp\        RV R 24       \G        VR!7      ;_uu_ 4       pV Uu/ uF  pVPI                  VV4      VbK  	  pp\K        V4       EF  pVPM                  4       w  pppppVeT   V^,          p\        PO                  R"V R#V 2R$R%7       \
        PO                  R&V^,            R'S R(V R)VR* R+V 2
4       MV'       d   V
^,          p
VV,          ^,          PQ                  4        \
        P                  R&V^,            R'S R(V R,\>         R-VV,          ^,          PR                  R. R/VV,          ^,          PU                  4       R. R#VR* R024       M3V^,          p\
        P)                  R&V^,            R'S R(V R1VR* R22	4       V^,           S,          pVS n        S PW                  TV'       g   TMR3V 24       \        R4V R5V
 R624       EK  	  R	R	R	4       \        R74        \
        P                  R84       \Y        S P                  S P"                  S P                  P                  4       S P"                  P[                  4        \
        P                  R94       \]        S P                  S P"                  S P                  P^                  S P                   4       \         P                   ! 4       V,
          p\
        P                  R<V
 R=V R>V R?VR* R@2	4       \        P                  RAV
 R'S RBV RCV RDVR* R224       V^ 8X  d&   S Pa                  4        \
        P                  RE4       \
        P                  RF4        \        S P                  S P                   .,           S P                  S P"                  4       \%        S P                  S P                   .,           S P                  S P"                  4       \
        P                  RH4        \c        4        \e        4        S Pg                  RJ4       R	#   \&         d$   p\        P)                  RT 24        R	p?EL*R	p?ii ; iu upi u upi   + '       g   i     ELo; i  \&         d&   p\        PO                  R:T 2R;R%7        R	p?ELR	p?ii ; i  \&         d#   p\        P)                  RGT 24        R	p?LR	p?ii ; i  \&         d#   p\        P)                  RIT 24        R	p?LR	p?ii ; i)Kal  
v9: LIFETIME LEARNING EOD training.

Flow:
  1. Write pre-train report
  2. Rebuild features (incremental, fast)
  3. Save today's feature rows to features/daily/features_YYYYMMDD.pkl.gz
  4. Load today's feature file as training dataset
  5. For each agent sequentially:
       a. Check tree_count -- if > DISTILL_THRESHOLD, distill first
       b. Add DAILY_TRAIN_TREES (50) new trees via init_model
       c. Checkpoint after each agent
  6. Write post-train report

Agents never forget. Each day adds knowledge on top of all previous days.
Monday's trees are still in the model when it runs on Friday of next year.
r	  zEOD training started at zTRAIN_START | symbols=z
 | models=z | checkpoint_idx=zEOD train startzWriting pre-train report...zPRE_TRAIN_REPORT_ERR | NzPre-train report written.z  Features rebuilt: rB  z$  No features -- skipping EOD train.c              3   8   "   T F  p\        V4      x  K  	  R # 5ir	  r   )r   r   s   & r   r   3TradingSystem._after_hours_train.<locals>.<genexpr>  s     C)BAQ)Br	  zTRAIN_DATA_SIZE | total_rows=r  r&  zSaving today's feature file...zC  Daily feature save failed -- using in-memory features as fallbackr?   zA  Could not load daily file -- falling back to in-memory featuresz  Training dataset: c              3   8   "   T F  p\        V4      x  K  	  R # 5ir	  rl  r  s   & r   r   rm    s     &N7M!s1vv7Mr	  z rows across c                     V ^ ,          # r  r   rm  s   &r   ro  2TradingSystem._after_hours_train.<locals>.<lambda>      1Q4r   r  z	Training z
 agents | uJ    workers | each worker: train → save → release → next | DAILY_TREES=c                  < V w  rp\         P                   ! 4       pVP                  \        8  dp   \        P	                  RV^,            RS RV RVP                   R\         R24       SP
                  P                  ^ZR7      pV'       d   VP                  V4       RpR	p \        Vn	        VP                  S4      pRVn	        \         P                   ! 4       V,
          p	V'       d   VP                  4        RVn        RVn        SP                  4         S
P!                  R
4      P#                  ^ 4       WWyV3#   \         d   pRTn	        Tp Rp?LRp?ii ; i  \         d     L3i ; i)u  
Complete lifecycle for one agent in a worker thread:
  1. Train  -- builds booster, adds DAILY_TRAIN_TREES trees
  2. Save   -- writes pkl to disk
  3. Null   -- drops Python reference to booster
  4. Trim   -- malloc_trim(0) tells glibc to return freed pages to OS
  5. Return -- worker is now free for next agent

Peak RAM per worker = ~320MB during step 1.
After step 4 that memory is fully returned to OS.
N concurrent workers = N × 320MB peak, then drops back to base.
r  r  r   z | tree_count=z > z | DISTILLING)r  NFr4  )r   r=  rC  r   r   r	  r  rH  rh
  r  r  rX   r  r  r  rk  r6  r7  )jobrC  r  r  r   distill_dataerrr  r   r   r5  rj  n_modelsr   training_datas   &         r   _train_save_release=TradingSystem._after_hours_train.<locals>._train_save_release  s\     #CuB "33#a%(2dV 4""'"2"2!337H6IX  $ww;;R;HMM,/ CG(9%++m4(,%
 iikB&G 


 !EM EMJJLK(44Q7 w55+  (,%$  s*   %#E   E!  E	EE!E/.E/zbefore worker-pool training (z	 workers)r  zTRAIN_AGENT_ERR | r   Fr   r  r  r   z FAILED r  zs:  | +z trees | val=r>  z | IC=zs | releasedz	 no data r  zFAILED:zafter z released (z done)zworker-pool training completezTraining MetaLearner...zMetaLearner done.zTRAIN_META_ERR | TzEOD training complete: 
 trained, z distilled, 
 failed | s totalzTRAIN_COMPLETE | trained=z | distilled=z
 | failed=z | elapsed=z+Training checkpoint cleared (full success).zWriting post-train report...zPOST_TRAIN_REPORT_ERR | zPost-train report written.zRESOURCE_GRAPH_SKIP | r?
  )4r   r   rB   r   rC   r   r   r   r   r	  r  rq   r4  rl  r1
  r  r{	  r  r
  rX   r   ru  r{  rT  r  r  r  r  rQ   r   r  rh
  rj  r5  r  r   r  r   r  r   r  r  r  r]  r  r  r|	  ri  r`  r  r   rh  ) r   r   r=	  r   r  
total_rowsr  	today_strordered_models	start_idxtrained_countfailed_countdistilled_count	N_WORKERSry  rV	  all_jobsr  rt  r  r  rC  r  r  r   rv  rZ  elapsed_totalr5  rj  rw  rx  s    f                           @@@@r   _after_hours_train TradingSystem._after_hours_trainY  s   $ ))+,,z*334KL.wi89$S)9)9%:$; <$++&''9$:T:T9UW	
 	"#12	@t.? ?$))T!$++0A"A477DIIV 	/0 GG((**1#X67""$wwNNABC)9)9)@)@)BCC
+Jq> :477++,-/	
 	45WW002
NN`a
 LL+44X>	::9ENN^_ GG,,M"3&N}7K7K7M&N#Nq"Q R-()3	
   1 1 3H~&..9	 (7'BO	zI; 7,-/	
 	6	6 6	6z  /	
 *  H,/8;<Q?/8;<Q?A *	 	 
 	09EF  I66$MUVXct{{#6<cAXGV#G,36::<0T7GS? A%L &&,TF#cU;e ' MLLc!eWAhZr$x}CPSuUW!Q&M"3'*//1KKc!eWAhZr$ 8-. /-c215==cB C,S1!4??A#Fc"3-|	5 !A%LNNc!eWAhZr$yQOQ  !Gx/-5*++#dWTF3CE 6${=/HI? - 7F 	01	GKK12DKKDGG4D4DEIINNKK+, 	T[[$))TWW^^T__U		g-%m_J|L>S!*	

 	'az B()L> B$S),	
 1((*KKEF 	23	At.? ?$))T!$++0A"A477DIIV 	01	?#% 	j)g  	@  #:1#!>??	@n
 W 766V  	G!21#6FF	G4  	A  #;A3!?@@	A  	?  #9!!=>>	?s   A:a 3Ab)b.b
BbC2b"b9A9b A:c )
d a>a99a>bb	c*c

cc?c::c?d/d**d/c                   \         P                   ! 4       p\        P                  ! \        4      P	                  R4      p\
        P                  RV 24       V P                  P                  4       pV'       g   \
        P                  R4       R# \        R VP                  4        4       4      p\
        P                  RVR R\        V4       R	\         R
24       \        V P                  P!                  4       R R7      p^ p^ p\#        V^4       F  w  pw  r \        V
n        V
P'                  V4      pRV
n        V'       dd   V
P)                  4        V^,          p\
        P                  RV R\        V4       RV	 R\         RV
P*                   RV
P,                  R 24       MRV
n        V^,          p \         P4                  ! R4       K  	   \7        V P8                  V P:                  V P                  P<                  4       V P:                  P)                  4        \?        V P8                  V P:                  V P                  P@                  V PB                  4       \         P                   ! 4       V,
          p\
        P                  RV RV RVR R24        \E        V P8                  V PB                  .,           V P                  V P:                  4       \G        V P8                  V PB                  .,           V P                  V P:                  4       V PI                  R!4       R#   \.         dc   pRT
n        T^,          p\0        P3                  RT	 RT 2RR7       \
        P3                  RT R\        T4       RT	 RT 24        Rp?ELRp?ii ; i  \.         d&   p\0        P3                  RT 2RR7        Rp?ELRp?ii ; i  \.         d#   p\0        P                  R T 24        Rp?LRp?ii ; i)"aq  
v9: WEEKEND DEEP TRAIN -- Saturday once per week.

Combines Mon-Fri daily feature files into a single weekly dataset.
The full-week context makes rolling features (ret_5, ret_10, slope_20,
weekly momentum, etc.) far more informative than any single day.

Adds WEEKLY_TRAIN_TREES (100) trees per agent -- double a daily update.
Agents that ran EOD training all week will end Saturday with an extra
100 trees trained on the week's complete picture.

Over 52 weekends per year that's 5,200 additional trees of weekly context
on top of the 12,600 from daily updates -- agents develop genuine
week-over-week pattern recognition.
r	  zWeekend deep train started at z3Weekend train: no weekly data available -- skippingNc              3   8   "   T F  p\        V4      x  K  	  R # 5ir	  rl  r  s   & r   r   /TradingSystem._weekend_train.<locals>.<genexpr>h  s     ?*>Q#a&&*>r	  z  Weekly dataset: r  z rows | z symbols | +z trees/agentc                     V ^ ,          # rp  r   rm  s   &r   ro  .TradingSystem._weekend_train.<locals>.<lambda>n  rr  r   r  r  r  r   r{  z trees | total=z | val=r>  zWEEKEND_TRAIN_ERR | r   Tr   z	 FAILED: r2   zWEEKEND_META_ERR | zWeekend deep train complete: r|  r}  r  r~  zWEEKEND_REPORT_ERR | r@
  )%r   r   rB   r   rC   r   r   r	  r  r   rT  r  r   ri
  rQ   rq   r   r  r  r  r  r=  r  rX   r   r   rI  r  r  r  r  r|	  ri  r{	  r1
  r
  rh  )r   r   r=	  weekly_dataweekly_rowsr  r  failedr  r  r  r  r   r   s   &             r   _weekend_trainTradingSystem._weekend_trainN  sU     ))+,,z*334KL4WI>? gg224NNPQ?+*<*<*>?? Qx; -?,@N	

   1 1 3H ).! <A}R(:%++k2(,%JJLqLGKKaS#n"5!6b ?./u?O?O>P Q$}}S13 -1E)aKF JJsO+ !=0	IDKKDGG4D4DEIINN 	T[[$))TWW^^T__U))+'+G9JhjW6	
	>t.? ?$))T!$++0A"A477DIIV 	n-9  R(,%!""%9$s1##FQU"Vs1#Qs>':&;2dV9QCPQQ	R  	I!4QC84HH	I  	>  #8!<==	>sR   BL/*L/AN "A:O /N:ANNO*O

OO?O::O?c                0  a  \         P                   ! 4       pV\        S R^ 4      ,
          R8  d   R# VS n         \        P                  ! V 3R lRRR7      P                  4        R#   \         d$   p\        P                  RT 24        Rp?R# Rp?ii ; i)	z#Generate accuracy chart every hour._last_chart_tsrc   Nc                  X   < \        S P                  S P                  P                  4      # r	  )rs	  r  r	  rh  r4  s   r   ro  ,TradingSystem._maybe_chart.<locals>.<lambda>  s    6t{{DGGJJOr   TChartGenr  zCHART_ERR | )	r   r}  r  r  r  r  rX   r   r   r   rB   r   s   f  r   _maybe_chartTradingSystem._maybe_chart  s|    iik/33d:!	5O* eg 	5  <s!344	5   +A' 'B2BBc                0  a  \         P                   ! 4       pV\        S R^ 4      ,
          R8  d   R# VS n         \        P                  ! V 3R lRRR7      P                  4        R#   \         d$   p\        P                  RT 24        Rp?R# Rp?ii ; i)	z9Write hourly report every 30 minutes during market hours._last_report_tsrb   Nc                  Z   < \        S P                  S P                  S P                  4      # r	  )r
  r  r	  r  r4  s   r   ro  -TradingSystem._maybe_report.<locals>.<lambda>  s    }T[[$''499Mr   THourlyReportr  zREPORT_ERR | )	r   r}  r  r  r  r  rX   r   r   r  s   f  r   _maybe_reportTradingSystem._maybe_report  s|    iik0!44t;"	6M. eg 	6  =!455	6r  c                
   \         P                   ! 4       pV\        V R^ 4      ,
          R8  d   R# Wn         V P                  P	                  4        R#   \
         d$   p\        P                  RT 24        Rp?R# Rp?ii ; i)z/Trigger Alpha Vantage burst fetch periodically._last_av_tsra   NzAV_FETCH_ERR | )r   r}  r  r	  rG  rX   r   r   r  s   &  r   _maybe_av_fetchTradingSystem._maybe_av_fetch  si    iik}a0036	8GG--/ 	8  ?1#!677	8s   A BA==Bc                   a  \         P                   ! 4       pV\        S R^ 4      ,
          R8  d   R# VS n        \        P                  ! V 3R lRRR7      P                  4        R# )z"Save agent state every 15 minutes._last_state_save_tsrd   Nc                     < \        S P                  S P                  S P                  P                  S P
                  4      # r	  )r|	  r  r  r	  ri  r{	  r4  s   r   ro  1TradingSystem._maybe_save_state.<locals>.<lambda>  s(    /TYYX\XgXghr   T	StateSaver  )r   r}  r  r  r  r  rU  s   f r   _maybe_save_stateTradingSystem._maybe_save_state  sO    iik4a883>#& hk	
 %'r   c                     V P                   P                  4        R#   \         d$   p\        P	                  RT 24        Rp?R# Rp?ii ; i)z)Rotate DB if needed -- called each cycle.zWATCHER_CHECK_ERR | N)r	  r  rX   r   r   r  s   & r   _maybe_check_watcher"TradingSystem._maybe_check_watcher  s@    	=GG((* 	=  #7s!;<<	=s    AAAc                f   \         P                   ! 4       p\        P                  ! \        4      pVP	                  4       pV^8  pV'       d   RpM\        4       '       d   RpMRpV\        V R^ 4      ,
          V8  d   R# Wn        \        P                  ! \        RRR7      P                  4        R# )	a]  
Smart local backup with frequency based on market schedule:
  - Weekday market hours : every 30 min  (new data every minute)
  - Weekday off-hours    : every 2 hours (EOD train done, just protecting state)
  - Weekend              : every 6 hours (no new data, just safety net)
Renamed from _maybe_github_backup (misleading -- this is local-only).
r"  rb   i   _last_backup_tsNTLocalBackupr  )r   r   rB   r  r  r  r}  r  r  r  r   r  )r   rB   now_etr  
is_weekendr  s   &     r   _maybe_local_backup!TradingSystem._maybe_local_backup  s     i(!AX
HHH0!44x?"d	

%'r   c                    \         P                   ! 4       pV\        V R^ 4      ,
          R8  d   R# Wn        \        P                  ! V P
                  RRR7      P                  4        R# )a  
Push key report files to GitHub Stock_Bot/backup/ once per day.
This allows remote review of bot state without SSH access.
Files pushed: human_report.txt, claude_handoff.json, TRADE_LOG.csv,
              agent_state.json, train_done.json, last 500 lines of trading.log
r;  re   NT
GithubPushr  )r   r}  r;  r  r  _do_github_pushr  rU  s   & r   _maybe_github_push TradingSystem._maybe_github_push  sQ     iik5q99EA$'!''<	

%'r   c           	       aaaaaa ^ RI o^ RIo^ RIo\        ^4       RoRpRV R2oRRS 2RR	/oR
 VVVVVV3R llp\        P
                  ! \        4      P                  R4      p^ p. R%OpV Fx  w  rg\        P                  P                  V4      '       g   K,   \        VR4      P                  4       p\        V4      R&8  d   KY  V! WxRV 24      p	V	'       d   V^,          pKx  Kz  	  \        P                  P                  R4      '       dg    \        RR4      ;_uu_ 4       pVP#                  4       pRRR4       RP%                  XR'R 4      P'                  4       pV! RVRV 24       V^,          p ^ RIp. p\+        VP)                  \        P                  P%                  \,        R4      4      4       Fh  p\        P.                  ! V4      pVP1                  R\        P                  P3                  V4      RVP4                  R,          RVP6                  /4       Kj  	  SP9                  RVR\        V4      RV/^R7      P'                  4       pV! RVR V 24       V^,          p\:        P=                  R"V R#24       \        P=                  R$V 24       R#   \         d(   p
\        P!                  RT RT
 24        Rp
?
EK\  Rp
?
ii ; i  + '       g   i     EL; i  \         d$   p
\        P!                  RT
 24        Rp
?
ELRp
?
ii ; i  \         d#   p\        P!                  R!T 24        Rp?LRp?ii ; i)(z(Upload key files to GitHub via REST API.N]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zJake-Culberson/Claud-Codezhttps://api.github.com/repos/z	/contentsAuthorizationBearer zContent-Typezapplication/jsonc                <    V ^8  d   QhR\         R\        R\         /# )r7   remote_pathcontent_bytesr  )r:   bytes)r;   s   "r   r<   3TradingSystem._do_github_push.<locals>.__annotate__  s!     	 	s 	5 	s 	r   c                   < S
 R V  2pSP                   P                  VRRS 2/R7      pRp SP                   P                  V4      ;_uu_ 4       pSP                  VP	                  4       4      P                  RR4      pRRR4       RTRSP                  T4      P                  4       /pT'       d   YWR&   SP                   P                  TSP                  T4      P                  4       R	SR
7      p SP                   P                  T4      ;_uu_ 4       pSP                  TP	                  4       4      P                  R/ 4      P                  RR4      R,          uuRRR4       #   + '       g   i     L; i  \         d     ELi ; i  + '       g   i     R# ; i  \         d'   p	\        P                  RT  RT	 24        Rp	?	R# Rp	?	ii ; i)r  r  r  )rq  r,   shaNr  contentPUT)ru   methodrq  r  r  zGITHUB_PUSH_ERR | r   )requestRequesturlopenr  ri  r@  rX   	b64encodedecoder  encoder   r   )r  r  r  r  reqr  r  payloadreq2r   APIPAT_jsonrd
  hdrsurllibs   &&&       r   _push,TradingSystem._do_github_push.<locals>._push  s   E;-(C..(('RUQV6X(YCC^^++C00D++diik266ubAC 1 !#y&2B2B=2Q2X2X2Z[G!$>>))#EKK4H4O4O4Q27 * GD^^++D11T ;;tyy{377"EII%QSTUXY 21 10  211 $$'9+c!%MNsf   #E< 0E)E< 5#F" AF
F" )E9	4E< 9E< <F
FF	F" F" "G-GGr  rbr   zbot: daily push zGITHUB_PUSH_FILE_ERR | r   r   r  r,   z%Stock_Bot/backup/trading_log_tail.txtzGITHUB_PUSH_LOG_ERR | z*.pklr  size_kbmtime	generatedr  rq   rx	  z$Stock_Bot/backup/model_manifest.jsonzbot: model manifest zGITHUB_MANIFEST_ERR | zGitHub daily push complete: u    files → Stock_Bot/backup/zGITHUB_PUSH_COMPLETE | files=)
r   z!Stock_Bot/backup/human_report.txtr   z$Stock_Bot/backup/claude_handoff.jsonrn   zStock_Bot/backup/TRADE_LOG.csv)rr   z!Stock_Bot/backup/agent_state.json)rp   z Stock_Bot/backup/train_done.json)ro   z&Stock_Bot/backup/train_checkpoint.json)r   z#Stock_Bot/backup/bot_dashboard.htmlr  r  r  i  @i)urllib.requestrd
  r~  r   r   rB   r   rC   rT   rU   rV   r.  ri  r   rX   r   r   	readlinesr   r  rO   rQ   r   statrS   r   st_sizest_mtimer  r   r   )r   REPOr  r=	  pushedfiles_to_pushr  remoter  r  r   r   r	  rM  _glmanifest_pkl_stmanifest_bytes_mer  r  r  rd
  r  r  s   &                   @@@@@@r   r  TradingSystem._do_github_push  s    44"n*.tfI>73%.BTU	 	, ,,z*334HI
 +ME77>>%((Nud+002w<"22F/?y-IJaKF  + 77>>-((C---KKME .wwuTU|,335=tGWX_W`Eab!	AHsxx^W(MNOggdmBGG,,T2s{{d2S\\!  P #[[WX(* 	 )   	 
 8.(	24aKF 	26(:VWX9&BCO  N$$'>ugS%LMMN .--
  C$$'=aS%ABBC0  	A  #9#!?@@	Ash   *J	JK( &K7A K( 8C4L K*KKK%		K( (L3LLM$MMc                     \        ^ 4       V P                  P                  4        R#   \         d&   p\        P                  RT 2RR7        Rp?R# Rp?ii ; i)z9Background feature rebuild -- runs in FeatRebuild thread.zFEAT_REBUILD_BG_ERR | Tr   N)r   r	  ru  rX   r   r   r  s   & r   _rebuild_features_background*TradingSystem._rebuild_features_backgroundb  sO    	LaLGG((* 	L!7s;dKK	Ls   %) AAAc                   V P                   P                  p\        V P                   P                  4      pV P                   F%  pVP                  V4       VP                  V4       K'  	  . p. pVP                  4        F  w  rgVe   \        V4      \        8  d   K  VP                  VR4      pV^ 8:  d   K:   V\        ,          P                  R,          P                  \        P                  4      p	\        P                   ! \        P"                  ! V	4      4      '       g   K   TP'                  T4       TP'                  T	4       K  	  V'       g   R# \        P(                  ! V\        P                  R7      p
 V P*                  P-                  V
4      p \        P1                  R4      pV P                   EF  pVP4                  P6                  '       g   K"  \9        VP4                  R4      '       dJ   \        VP4                  P:                  4      ^8  d&   VP4                  P=                  4       \>        8  d   K   VP4                  P-                  V
4      w  r\G        T4       EF  w  ppTP                  TR4      pT^ 8:  d   K"  \I        TT,          4      p\K        TT,          4      p\K        TT,          4      pTR	,          TR
,          ,           pTTPL                  8  d   K  T^ 8  d   \K        TT,          T,          4      MRpT^8X  d   YcPN                  9   d   TPQ                  YhRR7       K  YcPR                  9  d_   T PT                  '       dJ   TP4                  PW                  TT,          4      w  pppTPY                  YhT;'       g    RTTTT4       EK;  EK>  EKA  T^ 8X  g   EKK  YcPR                  9   d   TP[                  YhRR7       EKq  YcPN                  9  g   EK  T P\                  '       g   EK  TP4                  PW                  TT,          4      w  pppTP_                  YhT;'       g    RTTT4       EK  	  EK  	  V P`                  P4                  P6                  '       Ed   V P`                  P                  V4       V P`                  P                  V4        V P`                  P4                  P-                  V
4      w  pp\G        V4       EFO  w  ppVP                  VR4      pV^ 8:  d   K"  \I        VV,          4      p\K        VV,          4      pVR	,          R,           pV^ 8  d   \K        VV,          V,          4      MRpV^8X  d   VV P`                  PL                  8  d   W`P`                  PN                  9   d    V P`                  PQ                  WhRR7       K  W`P`                  PR                  9  ds   V PT                  '       d^   V P`                  P4                  PW                  VV,          4      w  pppV P`                  PY                  YhT;'       g    RVRVV4       EK\  EK_  EKb  V^ 8X  g   EKl  VV P`                  PL                  8  g   EK  W`P`                  PR                  9   d!   V P`                  P[                  WhRR7       EK  W`P`                  PN                  9  g   EK  V P\                  '       g   EK  V P`                  P4                  PW                  VV,          4      w  pppV P`                  P_                  YhT;'       g    RVRV4       EKR  	  \@        Pc                  R\        V4       RV Pd                   24       R#   \$         d     EK  i ; i  \$         d5    \        P.                  ! \        T4      R\        P                  R7      p EL i ; i  \2         d    Rp ELi ; i  \$         d2   p\@        PC                  RTPD                   RT 24        Rp?EKM  Rp?ii ; i  \$         d$   p\@        PC                  RT 24        Rp?ELRp?ii ; i)u  
v9: Core trading loop — runs every ~1 second during market hours.

Flow:
  1. Exit checks on all agents (ATR stop-loss, take-profit, drawdown reset)
  2. Build tradeable symbol list + stacked feature matrix
  3. Per-agent: batch-predict all symbols in one LGB call
  4. Signals passing IC gate + min_conf: execute buy/sell/short/cover

Uses predict_batch() so each agent makes ONE LightGBM call per cycle.
Full predict() only called at actual trade execution to get pred_pct.
Nr   rz  r2   rD  r  zBATCH_PREDICT_ERR | r   rD  rE  r  r  )r(  zMETA_AGENT_TRADE_ERR | zTRADING_PASS | syms=	 | cycle=r  r/   )3r	  ri  r6  r  r  r  r  r   r   r  r@  r  r  r  r  r}  r%  isfiniterX   rS   r  r  rq  r~  ra  r  r  r  r  r  r  rI  r   r   r  r  r   r  r	  r  r  r  r&  r  re  ru  rA  r|  r{	  r   r)  )r   ri  r  r  symsvecsr  r  r  vecrg  
meta_batchatr_idx
directionsconfidences_per  r  rb  rJ  rs  rD  r>   pred_pct	meta_dirsmeta_cfsr  mcfeff_mpes   &                             r   _trading_passTradingSystem._trading_passj  sP    77>> (() ++BNN6"NN6" 
 ~~'GCzSW'88JJsC(Ez&--b188Dvvbkk#.// 0 KKKK ( hht2::6	C00=J
	"((3G
 ++B88### ,//++,1HH''),AA*,((*@*@*M'

 $D/3

3,A:jm,A/
1.s(Ws]2BKK'5<\%Q 01t6000H=LL0T___)+)9)9$q')B8Qs8??sBQXY 6E0 !Vll*8<$6$664;K;K;K)+)9)9$q')B8QX__b'6R7 *# ^ ??  (((OO''/OO''/G&*oo&;&;&I&I+&V#	8'oFAs"JJsC0Ez8il+B,C)i/C9@AeDGG$454GQw3$//*B*B#B//"A"AA OO11#X1N (A(AAdooo-1__-B-B-J-J4PQ7-SNAx OO//HOOSRUWZ\cd GVA qSDOO,D,D%D//";";; OO00H0M (G(GGDL\L\L\-1__-B-B-J-J4PQ7-SNAx OO11#hoo#sTWY\]% ., 	"3t9+ .ZZL"	
C    	CTCrzzBJ	C  	G	"  $$';BGG9Cu%MNt  G$$'>tf%EFFGs   :A+])?]< ^> _2D1` $A` 3` ` /A` ` A` *` )]98]9<;^;:^;>__`%`		``?`::`?c                   V P                  4       '       g   R # V P                  '       d   V P                  4        R # \        P	                  R4       \
        P	                  R4       RpRV n        \        P                  ! V P                  RRR7      pVP                  4        \        P	                  R4       \
        P	                  R4         \        4       p\        P                  ! \        4      p\        P                  ! 4       V P                   ,
          R	8  d   \        P                  ! 4       V n        \        P"                  ! 4        Uu. uF  qUP$                  NK  	  pp\'        V P(                  P*                  P,                  P/                  4       4      p\
        P	                  R
V RV P0                   RV P(                  P2                  P5                  4       R R\'        V P(                  P6                  4       RV RV 24       V'       d   V'       g   \        P	                  R4       \
        P	                  R4       RV n         V P;                  4       pVP=                  RR 4       \>        P@                  ! V\C        \D        R4      ^R7       V P(                  PI                  4        TpV'       Ed6   V ;P0                  ^,          un        V P0                  V PJ                  ,          ^ 8X  dx   \M        R \        P"                  ! 4        4       4      p	V	^ 8X  d3   \        P                  ! V PN                  RRR7      P                  4        M\
        PQ                  RV	 R24       \        P                  ! 4       p
V P(                  P6                  '       d   V PS                  4        V PU                  4        V PW                  4        V PY                  4        V P[                  4        V P]                  4        V P_                  4        V Pa                  4        \        P                  ! 4       V
,
          pVR8  d   \
        Pc                  RVR RV P0                   R\'        V P(                  P6                  4       R\M        R  V Pd                   4       4       R!\f        Ph                   R"\f        Pj                   24       \        Pl                  ! \o        ^ R#V,
          4      4       EK%  \        P                  ! 4       pWPp                  ,
          R	8  pV'       Ed;   V P8                  '       Eg(   VPs                  4       ^8  Ed   Wn8        VPt                  VPv                  rV^8  ;'       g    V^8H  ;'       d    V^8  pV^8  ;'       g    V^8H  ;'       d    V^8*  pT;'       g    TpV'       d   RV n        \        P	                  R$VPy                  R%4       R&V'       d   R'MR( R)24       \
        P	                  R*V'       d   R+MR, R-VPy                  R%4       R.24       \        P                  ! V Pz                  RR/R7      P                  4        VPs                  4       R>9   pT;'       d!    ^VPt                  u;8*  ;'       d    ^8*  Mu p\        P                  ! 4       V P|                  ,
          R	8  pV'       d   V P~                  '       g   V'       d{   \        P                  ! 4       V n>        RV n?        \        P	                  R0VPy                  R14       R.24       \        P                  ! V P                  RR2R7      P                  4        VPs                  4       ^ 8X  dd   V P~                  '       dR   RV n?         V P;                  4       pVP=                  R3R 4       \>        P@                  ! V\C        \D        R4      ^R7       V P_                  4        V Pa                  4        \        4       p\        V4      R4,          ^8  d"   \        P	                  R5VR4,          R R624       \        Pl                  ! ^4       EK  u upi   \F         d     ELi ; i  \F         d     Li ; i  \         Edo    \        P	                  R74       \
        P	                  R84       RT n        T P(                  P2                  P                  4        T P(                  P*                  P                  4        T Pd                   F  pTP                  P                  4        K  	  T P                  P                  4        \        T Pd                  T P                  T P(                  P                  T P                  4       \        T Pd                  T P(                  T P                  4       \        T Pd                  T P(                  P,                  4       \        P	                  R94        R # \F         dm   p\        P                  R:T 2RR;7       \
        P                  R<\        T4      P                   R=T 2RR;7       \        Pl                  ! ^4        R p?E	K  R p?ii ; i)?Nz#Main loop running. Ctrl+C to stop.
MAIN_LOOP_STARTFTFinnhubFetchr  z8Finnhub fetch thread started (58 calls/min round-robin).FINNHUB_THREAD_STARTEDra   zHEARTBEAT | market_open=r  r  r  z | features=z | sentiment_symbols=z | threads=zMarket just opened.MARKET_OPENr?
  r  rx	  c              3   |   "   T F2  pVP                   R 8X  g   K  VP                  4       '       g   K.  ^x  K4  	  R# 5i)FeatRebuildN)r  is_alive)r   rR  s   & r   r   $TradingSystem.run.<locals>.<genexpr>1  s3      /'<! vv6 ;<::< A'<s   <<
<r  zFEAT_REBUILD_SKIP | z already runningrg   zGIL_STALL | main loop took r  z=s (normal <0.2s) -- WebSocket ping thread was starved. cycle=z
 features=z agents_trained=c              3   `   "   T F$  qP                   P                  '       g   K   ^x  K&  	  R# 5ir  )r  r  r	  s   & r   r   r  R  s     "MkWW__11ks   .
.z
 resource=z load=rf   zEOD training trigger: r	  z ET | z
post-closez
pre-marketz windowz#AFTER_HOURS_TRAIN_TRIGGER | window=
post_close
pre_marketz | time=z ETAfterHoursTrainzWeekend deep train trigger: z%A %H:%MWeekendTrainr@
  rc   zMarket closed -- zh until open.z
Shutting down...SHUTDOWN_KEYBOARD_INTERRUPTzAll models saved. Goodbye.zLoop error: r   zMAIN_LOOP_EXCEPTION | r  )r  r
  )PrF  r	  _run_collect_onlyr   r   r   r2  r  r  rI  r  r  r   rB   r  r   r:  r  r  r   r	  r  rh  r  r)  r  r  r  r8  r7  r  r~  r  r.  rd  rX   r:  r*  rT  r  r   r  r  r  r  r  r  r  r  r   r  r   r  r  rI  r  r5  r  r  r  rC   r  r6  r9  r  r  r   KeyboardInterruptr  r  r  r  r|	  ri  r{	  r
  rs	  r   r  r   )r   	_was_openfetch_threadopen_nowr  rR  r	  	sent_syms_d_active_rebuilds_t_loop_start_t_loop_elapsed_now_ts
_check_duer  _m_post_close_pre_market
_in_window_is_weekend_sat_window_wt_check_duesecsr8  r   s   &                        r   runTradingSystem.run  s
     ""$:;+,	 &*" ''t/?/?-;=NO23p)+#<<	2 99;!5!55;+/99;D(6?6I6I6K%L6Kff6KN%L #DGG$5$5$8$8$H$H$J KI %%28* =!!% -''+ww'8'8'F'F'H&K L$$'(8(8$9#: ;--6K 8##1"24 IKK 56 %%m438D0+!224z40		"d?C&@KGG**,$	 8JJ!OJzzD$;$;;q@
 ,/ /'0':':'</ ,( ,q0%,,'+'H'H'+%2 $eg(.."67G6HHX Y %)IIKMww'''**,%%'&&(((***,--/,,.++-&*iikM&AO&,$,,9/#9N O%%)ZZL
3tww?O?O;P:Q R.""Mdkk"MMN O((7(>(>'? @$$3$<$<#=? JJs1cO&;<=  #iikG"),E,E"E#!MJ!z$*F*F*F6>>K[^_K_4;1!'fmmB(*R'K'KR2X5J5J"((*Q'I'IB!G4H4Hb'2'A'Ak
%;?D8"KK"89Q8RRX3><L"QQX!Z )--"EValgsEt u((.(@'A!F &,,'+'>'>',%6 $eg
 &,^^%5%?K$/$J$JA4J4J4JK%)YY[43N3N%NSV$VM"4+C+C+C6:iik3370:%z:;3@ "((#'#6#6#(!/  %'~~'1,1I1I1I380/!%!6!6!8BFF>48 IIb$*DQO ,,.++--/D4y4'",&7T	#m$TUJJrNg &M, %*d*l  ).$. % 01!!"?@-2*!!&&(!!&&(AGGLLN %		 $T[[$))TWW^^T__]dkk477DII>'TWWZZ@89 |A3/$?"",T!W-=-=,>bD! #  

1s   B a< a#B1a< a< 1a< A	a $a< =C"a<  Ea< 2Aa< 8Aa< a< a< #a< 2
a< =0a< ."a< A)a< ;a< 8a< a< a< 'B a< a< A	a+ A8a< a< a($a< 'a((a< +a96a< 8a99a< <E6i+5i+>i+?A i&&i+)"r8  r2  r1  r.  r  r  r-  r  r<  r;  r:  r/  r  r0  r  r5  r(  r6  r,  r4  r9  r  r  r&  rA  r	  r)  r	  r*  r%  r  r{	  rq   r  )FNr"  )r   r   r   r   r  rC  rF  rI  r+  r3  r]  r`  r7  rh  r  r  r  r  r  r  r  r  r  r  r  r  r-  r   r   r   s   @r   r  r  p  s     /( /(bM MBH!BF 	? 	? ? ? s*jP.f56	8	=2^D@LH
TC Cr   r  __main__z[v9] uvloop installedzStockTrading.pyz7ML Stock Trading Bot v8 -- Alpaca + Finnhub + Sentimenta  Examples:
  python3 StockTrading.py                             # full trading mode
  python3 StockTrading.py --collect-only              # all sources, no trading
  python3 StockTrading.py --collect-only --sources alpaca
  python3 StockTrading.py --collect-only --sources alpaca,finnhub
  python3 StockTrading.py --collect-only --sources alpaca,finnhub,news,sec
  python3 StockTrading.py --collect-only --sources all

Valid source names: alpaca  finnhub  news  sec  stocktwits  reddit  congress  all)progdescriptionformatter_classepilogz--collect-only
store_truezoRun data collection pipelines only. No agents loaded, no trading. Use to test/debug data sources independently.)rw  rJ
  helpz	--sourceszSRC[,SRC,...]zComma-separated sources to enable (only relevant with --collect-only). Options: alpaca finnhub news sec stocktwits reddit congress all. Default: all)rJ
  metavarr5  z--moder"  r|  r#  zmTrading direction mode. long=buy/sell only (default), short=short/cover only, both=full bidirectional trading)rJ
  choicesr5  z	--ram-capr	  zHard RAM ceiling in GB. Bot will never allocate beyond this. If not specified, runs uncapped at max efficiency. Example: --ram-cap 6.0 sets a 6 GB ceiling on a 7.3 GB VM.)r  rJ
  r6  r5  z--max-workersNzHard cap on concurrent threads/workers across feature rebuild, training, and all ThreadPoolExecutor usage. If not specified, the bot auto-scales to CPU count (max efficiency). Example: --max-workers 4 limits to 4 concurrent threads on any VM.r  z[ERROR] Unknown sources: z        Valid options  : r   z[RAM CAP] Hard ceiling: r  rb
  z" MB) | ResourceGuard throttle at: z MB | pause at: r  z MBz/[RAM CAP] Uncapped -- running at max efficiencyz[MAX WORKERS] Hard cap: zO concurrent threads | Applies to: feature rebuild, training, ThreadPoolExecutorz2[MAX WORKERS] Uncapped -- auto-scales to CPU countz-
[COLLECT-ONLY] Starting data collection modez[COLLECT-ONLY] Sources  : r  z"[COLLECT-ONLY] Trading  : DISABLEDz&[COLLECT-ONLY] Log file : trading.log
z(
[ERROR] Set your Finnhub API key first!z'  export FINNHUB_API_KEY=your_key_here
z
[MODE] Trading mode: z.[MODE] Short selling ONLY -- no long positionsz0[MODE] Bidirectional -- longs AND shorts enabledz/[MODE] Long only -- standard buy/sell (default))r	  r  r  )r  r-   )rB
  r  )r  r   )r2   r3   )r  r4   )wallstreetbetsstocks	investingStockMarket)restatementresignationterminationrJ
  
bankruptcyfraudinvestigationlawsuit	delistingzgoing concernzmaterial weaknesszcybersecurity incidentzdata breachzregulatory actionzsec investigation)acquisitionmergerzstrategic partnershipznew contractbuybackzdividend increasezguidance raisedzrecord revenuezfda approvalzpatent granted	expansion)r  r
     -   >   rt  r  r  r  r  r  rs  r  ru  rr  r  rq  r  r  r  r}  r  rw  rv  rz  rx  r|  r{  ry  r~  ))UltraConservrB
  Q?rD  rf   )Conservativer0   
ףp=
?gQ?r  )ModerateDefensr.   r  g)\(?r  )ModeraterN  r/   r  r  )MeanReversionrL  )\(?r  r3   )MomentumrR  
ףp=
?g=
ףp=?rh   )ModerateAggrr  r-   gQ?rL  )
AggressiveQ?gq=
ףp?r!  g?)HighConvictionr1   rE  g(\?rg   )
Contrarianr  rW  gzG?r  )
Volatilityp=
ף?g(\?g(\?r  )UltraAggressrT  gQ?g(\?g333333?)SectorRotationrN  r-   Q?r  )LowFreqrL  r1   gq=
ףp?g?)HighFreqr  g)\(?gHzG?rf   )Balancedr  r[  r^  r  )r  )NNr	  >   r%  r  r  r  r  r7  r  r  )r"  r|  r#  ((  r
  rT   r   r   loggingr  r  r	  r~  rN  r/  hashlibxml.etree.ElementTreeetreeElementTreeETr   r   collectionsr   r   r  r  r  pandasr  r7  r  r  r  r*	  r  r  r  r	  matplotlib.gridspecr+	  r  r  r  printvaderSentiment.vaderSentimentr   r'  rT  r.  r  r  lightgbmr  r  uvloop	UVLOOP_OKconcurrent.futuresr   r   sklearn.ensembler   r   sklearn.preprocessingr    sklearn.model_selectionr!   sklearn.metricsr"   r  r	  r  r  r  r  rf
  environr@  r#   r%   r'   r)   r+   r  r  r  r  r  r  r  r{  rb  r  r  r0  r  r  r/  rA   rP   rD   r_   r   r   r   rh
  ri
  rC  rj
  r   r@  rh  r  r  SENTIMENT_LOOKBACK_NEWSr  SENTIMENT_LOOKBACK_SECrX  r  SENTIMENT_WEIGHT_NEWSSENTIMENT_WEIGHT_SECSENTIMENT_WEIGHT_REDDITSENTIMENT_WEIGHT_CONGRESSri   rj   r  rk   r  r  SEC_EDGAR_RSSSEC_EDGAR_SEARCHr  rS  r{  r|  r   r   r-  rW  rd  rh  r  r   r   rz	  r   r  rI  r  r  r  r   RETRAIN_MINUTESrH  r  r  r   r   r   	Formatterr   r  	_main_fmt
_debug_fmtbasicConfigINFO	getLoggerr   r   setLevelFileHandler_fh_mainsetFormatterStreamHandler_sh_main
addHandler	propagater  _rhrR   rB   rC   _debug_session_filer   DEBUGr  r  _dh_dh2r  r?  r2  rB  STOCK_UNIVERSE_PRIMARYrG   r6  fromkeysr  r5  r  r  r  r'  r  r  r  r  r:  rf  r  r  r  r   rl  r  r  r!  r  r  r  r  r  r  r  r  r  r  r  r  rs	  r|	  r	  r	  r	  r1
  r
  r
  r
  r  r  r$  COLLECT_ONLY_REPORT_INTERVALVALID_SOURCESr'  r$  rh  r  r  r  r  r  r  r  r  rr  r   RESOURCE_GUARD_RAM_WARNRESOURCE_GUARD_RAM_BAILr  rl  r  r  r  rf  r  r  r  r  r   r  installargparse_apArgumentParserRawDescriptionHelpFormatterr   add_argumentr  r   
parse_args_argssourcesr   r  rb  r  _badrQ   r<  sys_sysmodules	_this_modram_capr  r	  r   r  re  r-  rO
  s   0r   <module>r     s  EN L K K K K + + ( *         
u   &PM
HHM
E
IFI @ R 0 4 * !**,QNB/0|+
 JJNN#46`aJJNN#38TUJJNN#68fg JJNN#68JK JJNN=;          ""   ""   )F, 
 ' '     /  " !   "  # ! #     !        zz~~&8bA zz~~&<bA ,  !#

/A2 F  #  P  F{  d  c  
 ,,(4 . 
*+ 
   MM"45	MM"34
 $   > :z66<QVXjl  ABKKT" A J$ ' I$ ' F$ ' J & 

  ' - 

  ,c 2 

  ' -QA~;G%% ;1m 1 -7JL	>!

   ',, 4			8	$  }-   i    "   i     (    (   !!(+   w|| $/*          %,,
a''89>@   )   gmm $      .s3         .S9   *      .."
O>1	1
111$1%+1,112617=1>D1 1 1 1  1 !&1 ',1 -21 391 :?1 @F1 	1 	1 	1 	1 %	1 &,	1 -3	1 49	1 :@	1 AG	1
 1
 1
 1
 !1
 "(1
 )/1 
1 1 1 1  1 !$1 %(1 )-1 .31 491 :?1 @D1 
1 1 1 1 #1 $)1 */1 061 7<1 =A1 BH1 
1 1 1 1 $1 %*1 +11 281 9>1 ?D1 1 1 1 
1 1 1 1 #1 $)1 */1 051 6;1 <A1 BH1 
1 1 1 1 !1 "'1 (.1 /51 6<1 =B1 CG1 
1 1 1 1 "1 #'1 (-1 .31 491 :?1 @E1  
!1  !1  !1  !1  "!1  #(!1  ).!1  /4!1  5:!1  ;@!1  AF!1" 
#1" #1" #1" #1" ##1" $)#1" */#1" 06#1" 7;#1" <A#1$ 
%1$ %1$ %1$ %1( )1( )1( )1( )1( #)1( $*)1( +0)1( 16)1( 7=)1( >C)1* 
+1* +1* +1* +1*  +1* !&+1* ',+1* -3+1* 49+1* :?+1* @E+1, -1, -1, -1, -1, $-1, %*-1, +0-1, 16-1, 7=-1, >C-10 
110 110 110 110 !110 "(110 ).110 /2110 38110 9>110 ?D112 
312 312 312 312 !312 "'312 (.312 /5312 6;312 <B314 
514 518 
918 918 918 918  918 !&918 ',918 -2918 38918 9>918 ?C91: 
;1: ;1: ;1: ;1: !;1: "';1: (-;1: .4;1: 5;;1: <B;1: CG;1< 
=1< =1< =1< =1< #=1< $*=1< +0=1< 17=1< 8>=1< ?D=1> ?1> ?1> ?1> ?1B 
C1B C1B C1B C1B "C1B #(C1B ).C1B /3C1B 49C1B :@C1B AEC1D 
E1D E1D E1D E1D !E1D "'E1D (-E1D .3E1D 49E1D :>E1D ?DE1F 
G1F G1F G1J 
K1J K1J K1J K1J #K1J $)K1J */K1J 05K1J 6;K1J <AK1J BGK1L 
M1L M1L M1L M1L  M1L !&M1L ',M1L -2M1L 38M1L 9?M1L @FM1P 
Q1P Q1P Q1P Q1P Q1P  %Q1P &+Q1P ,1Q1P 26Q1P 7;Q1P <AQ1P BGQ1R 
S1R S1R S1R S1R !S1R "'S1R (,S1R -2S1R 38S1R 9>S1R ?ES1V W1V W1V W1V W1V "W1V #)W1V *0W1V 17W1V 8>W1V ?DW1X Y1X Y1\ 
]1\ ]1\ ]1\ ]1\ "]1^ 
_1^ _1^ _1^ _1^ "_1^ #(_1^ )._1^ /4_1^ 5;_1^ <A_1` 
a1` a1` a1` a1` "a1` #(a1` ).a1` /4a1` 5:a1` ;@a1 f dmm$:;<TB&V"H '{LA#':e eV' 'lw# w#z3 3lA AN2222'2)12 
	2 	2 2 2 $2 &22 2 2 2 2 )2 +62 2 2 2 2  !2  !2$ %2( )2( )2( *)2( ,9)2, -20 
122 324 526 728 92: ;2< =2> 
?2B C2D E2F G2H I2J K2L M2N O2P Q2R S2R S2T U2T $U2V W2V "W2Z [2\ ]2^ _2` a2b c2f 
K' K'N	p pf~# ~#R
k	
 k	
bW Wt9-* 9-~-/ -/f
1 
1= =(B B&L
 L
d&bXl3h< <; ;4P;fD_A _ADS:n{@|^;H .8  " X_ _B 
    k/ZAJ         IWS WS~  ") * *NGb/
 /
b   q#na01 n5G GV" z%&			M77b
B OO$\5=  > OOK]  ^ OOHf)/  0 OOKeT4J  K OOO#tSR  S
 MMOE',}}':':3'?@'?!GGIOO'?@D-Dt)$01)&*?)@ABQ   4<<
+CDI}} "5==4#78	&u}}S&9y?S?STU>V W**-i.B.B4.G*H)K LY11$67:#?	
  $	?@$$'5+<+<$=	!&y'@'@&A BH I	

 %)	!BC>@*499VD\+B*CDE24799:89Q'

(8(8(:';<=:: BCZZ6!DECDu11$$zz++.35A uj  PM	
WX	
NOP  % % H	  JM  E  I
CF	
GHI  FI~j As   AA AA1 AB AB %AB- ,AC ,(ACAAA.A-AA.A1ABBABBABBABB	AB*B)AB*B-ACCACCACCAC