Ë
    BG±jm5  ã                   óª   — d Z ddlZddlZddlZddlZddlmZ dZdZdZdZ	dZ
d	Zd
Zd
Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zdefd„Zd„ Zedk(  r e«        yy)u�  
check_pine.py â€” Static analysis of strategy_activation_scores.pine before optimization runs.

What this tool CAN check statically:
  1. request.security() direct calls â€” budget is 40 total (libraries add to this count
     invisibly; the library contribution is an estimate, not exact).
  2. plotchar() + plot() calls â€” hard limit is 64 per script.
  3. plotchar export titles â€” lists all exported column names.

What this tool CANNOT check statically:
  - Undeclared identifier errors: Pine variable scoping is too dynamic to detect reliably
    without a real compiler. The only way to catch these is to paste into TradingView.
  - Library-internal request.security() counts: the +23 library estimate may drift if
    library versions change. Treat the total as approximate.
  - Compile errors from syntax mistakes, type mismatches, etc.

These limitations are why the TV-validation sentinel exists: the tool prompts you to
paste into TradingView and confirm it compiles, then records that confirmation.

Also manages the TV-validation sentinel file (.pine_tv_validated) used by
auto_optimize_loop.py to warn about unvalidated Pine edits before a run starts.

Usage:
    python3 tools/check_pine.py                # run checks, print report
    python3 tools/check_pine.py --mark-valid   # record that Pine was confirmed OK in TV
    python3 tools/check_pine.py --status       # show whether sentinel is current
é    N)Údatetimez*strategies/strategy_activation_scores.pinez.pine_tv_validatedé   é(   é   é@   gÍÌÌÌÌÌì?c                  óê   — t         j                  j                  t        «      st	        j
                  dt        › �«       t        t        «      5 } | j                  «       cd d d «       S # 1 sw Y   y xY w)NzPine file not found: )ÚosÚpathÚexistsÚ	PINE_FILEÚsysÚexitÚopenÚ	readlines©Úfs    ú;/Users/jameslopez/projects/TradingBot25/tools/check_pine.pyÚ	read_piner   <   sB   € Ü�7‰7�>‰>œ)Ô$Ü�‰Ð(¬¨Ð4Ô5Ü	ŒiŒ˜AØ�{‰{‹}÷ 
�Šús   ÁA)Á)A2c                 ó  — t        | «      D ��cg c]=  \  }}d|v r4|j                  «       j                  d«      s|dz   |j                  «       f‘Œ? }}}t	        |«      }|t
        z   }|t        kD  }|t        t        z  k\  }|||||fS c c}}w )zBCount direct request.security() calls and estimate total vs limit.zrequest.security(ú//é   )Ú	enumerateÚlstripÚ
startswithÚrstripÚlenÚLIBRARY_SECURITY_CALLSÚSECURITY_HARD_LIMITÚSECURITY_WARN_PCT)ÚlinesÚiÚlineÚhitsÚdirectÚestimated_totalÚat_limitÚ
near_limits           r   Úcheck_security_callsr(   C   s›   € ä2;¸EÔ2Bô SÑ2B¡w q¨$Ø" dÑ*°4·;±;³=×3KÑ3KÈDÔ3Qð �‰U�D—K‘K“MÒ"Ð2B€Dñ Sä�‹Y€FØÔ5Ñ5€OØÔ!4Ñ4€HØ Ô$7Ô:KÑ$KÑK€JØ�˜¨*°hÐ>Ð>ùóSs   �ABc                 óz  — g }t        | «      D ]x  \  }}|j                  «       }|j                  d«      rŒ(t        j                  d|«      st        j                  d|«      sŒU|j                  |dz   |j                  «       f«       Œz t        |«      }|t        z   }|t        t        z  k\  }|t        kD  }|||||fS )zMCount plotchar() and plot() calls (not commented out), plus library estimate.r   z\s*plotchar\s*\(z\s*plot\s*\(r   )r   r   r   ÚreÚmatchÚappendr   r   ÚLIBRARY_PLOT_CALLSÚPLOT_HARD_LIMITÚPLOT_WARN_PCT)	r    Ú	plot_hitsr!   r"   Ústrippedr$   r%   r'   r&   s	            r   Úcheck_plot_callsr2   N   s¯   € à€IÜ˜UÖ#‰ˆˆ4Ø—;‘;“=ˆØ×Ñ˜tÔ$Øä�8‰8Ð'¨Ô.´"·(±(¸?ÈDÕ2QØ×Ñ˜a !™e T§[¡[£]Ð3Õ4ð $ô �‹^€FØÔ1Ñ1€OØ ¤O´mÑ$CÑC€JØ¤Ñ0€HØ�f˜o¨z¸8ÐCÐCó    c                 óÊ   — g }| D ][  }|j                  «       j                  d«      rŒ#t        j                  d|«      }|sŒ<|j	                  |j                  d«      «       Œ] |S )uN   Extract title= strings from plotchar calls â€” these are the exported columns.r   z%plotchar\s*\(.*?title\s*=\s*"([^"]+)"r   )r   r   r*   Úsearchr,   Úgroup)r    Útitlesr"   Úms       r   Úget_plotchar_titlesr9   _   sW   € à€FÛˆØ�;‰;‹=×#Ñ# DÔ)ØÜ�I‰IÐ>ÀÓEˆÚØ�M‰M˜!Ÿ'™' !›*Õ%ð ð €Mr3   c           
      ó  — t         j                  j                  dt        j                  j	                  t        j                  j	                  t        j                  j                  t        «      «      «      «       	 ddlm} dj                  | «      }g }g }|D ]R  }t        j                  dt        j                  |«      › d�|«      r|j                  |«       ŒB|j                  |«       ŒT ||fS # t        $ r g g fcY S w xY w)aÃ  
    Check that every i_w_* param in config.WEIGHT_COLS is declared in the Pine file.

    A param is 'declared' if the file contains an assignment like:
        float i_w_foo = ...   or   i_w_foo = ...
    (not just used in an expression).

    This catches the common mistake of adding a new signal to the score formula and
    params JSON but forgetting to re-run generate_pine_presets.py to add its
    'float i_w_foo = switch _preset' block.
    r   )ÚWEIGHT_COLSÚ z(?:^|\n)\s*(?:float\s+)?z\s*=\s*)r   r
   Úinsertr	   ÚdirnameÚabspathÚ__file__Úconfigr;   ÚImportErrorÚjoinr*   r5   Úescaper,   )r    r;   ÚcontentÚdeclaredÚ
undeclaredÚws         r   Úcheck_weight_declarationsrI   k   sË   € ô ‡H�H‡O�O�A”r—w‘w—‘¤r§w¡w§¡´r·w±w·±ÄxÓ7PÓ'QÓRÔSðÝ&ð �g‰g�e‹n€Gà€HØ€JÛˆô �9‰9Ð0´·±¸1³°¸gÐFÈÔPØ�O‰O˜AÕà×Ñ˜aÕ ð ð �ZÐÐøô ò Ø�2ˆvŠðús   Á=C3 Ã3DÄDc                  ó>  — t         j                  j                  t        «      syt         j                  j	                  t        «      } t         j                  j                  t
        «      sd| ddfS t         j                  j	                  t
        «      }| |kD  }d| ||fS )z6Return (exists, pine_mtime, sentinel_mtime, is_stale).)FNNTFNT)r	   r
   r   r   ÚgetmtimeÚSENTINEL_FILE)Ú
pine_mtimeÚsentinel_mtimeÚis_stales      r   Úsentinel_statusrP   Œ   su   € ä�7‰7�>‰>œ)Ô$Ø&Ü—‘×!Ñ!¤)Ó,€JÜ�7‰7�>‰>œ-Ô(Ø�j $¨Ð,Ð,Ü—W‘W×%Ñ%¤mÓ4€NØ˜NÑ*€HØ�˜^¨XÐ5Ð5r3   c                  ó&  — t        t        d«      5 } | j                  dt        j                  «       j                  d«      › d�«       | j                  dt        › d�«       ddd«       t        dt        › �«       t        d«       y# 1 sw Y   Œ'xY w)	z>Touch the sentinel file to record Pine was confirmed OK in TV.rH   zValidated: ú%Y-%m-%d %H:%M:%SÚ
zPine file: Nu   âœ… Sentinel updated: zD   auto_optimize_loop.py will not warn about unvalidated Pine edits.)r   rL   Úwriter   ÚnowÚstrftimer   Úprintr   s    r   Ú
mark_validrX   ˜   st   € ä	Œm˜SÔ	! QØ	�‰�+œhŸl™l›n×5Ñ5Ð6IÓJÐKÈ2ÐNÔOØ	�‰�+œi˜[¨Ð+Ô,÷ 
"ô 
Ð"¤= /Ð
2Ô3Ü	ÐPÕR÷	 
"Ð	!ús   ‘ABÂBÚreturnc            	      ó®  — ddl } ddl}t        j                  j	                  t        j                  j                  t        j                  j                  t        j                  j                  t        «      «      «      dd«      }g d¢}d}i }|D ]é  }t        j                  j	                  |d|› d|› d	�«      }t        j                  j                  |«      sŒJt        | j                  t        |«      «      «      }|sŒp|d   j                  d
d«      j                  «       }	|	rt        j                  j                  |	«      sŒµ	 |j                  t        |	«      «      }
|
j                  dg «      ||› d|› �<   Œë |si S t        |j!                  «       «      }|d   }i }|j#                  «       D ]  \  }}||k7  sŒ||dœ||<   Œ |S # t        $ r Y �ŒDw xY w)zí
    Check that all MLP winner artifacts share the same architecture.
    Returns a dict of {preset_key: {winner: arch, ref: ref_arch}} for any mismatches.
    Mixed archs cause generate_pine_mlp_presets.py to silently skip presets.
    r   NÚresultsÚwinners)Ú4HÚ6HÚ8HÚ12HÚ1DÚCOINBASE_BTCUSDÚ(optimization_winner_strategy_mlp_scores_Ú_z.csvÚmlp_weights_filer<   ÚarchÚ )ÚwinnerÚref)ÚcsvÚjsonr	   r
   rC   r>   r?   r@   r   ÚlistÚ
DictReaderr   ÚgetÚstripÚloadÚ	ExceptionÚvaluesÚitems)Ú_csvÚ_jsonÚWINNER_DIR_PATHÚTFSÚASSETÚarchesÚtfÚpÚrowsÚart_pathÚartÚall_arch_listsÚref_archÚ
mismatchesÚkeyrf   s                   r   Úcheck_mlp_preset_archesrƒ   ¡   s“  € ÷ &Ü—g‘g—l‘l¤2§7¡7§?¡?´2·7±7·?±?Ä2Ç7Á7Ç?Á?ÔS[ÓC\Ó3]Ó#^Ø#,¨ió9€Oâ
)€CØ€Eà €FÛˆÜ�G‰G�L‰L˜Ð,TÐUZÐT[Ð[\Ð]_Ð\`Ð`dÐ*eÓfˆÜ�w‰w�~‰~˜aÔ ØÜ�D—O‘O¤D¨£GÓ,Ó-ˆÙØØ˜‘7—;‘;Ð1°2Ó6×<Ñ<Ó>ˆÙœrŸw™wŸ~™~¨hÔ7Øð	Ø—*‘*œT (›^Ó,ˆCØ&)§g¡g¨f°bÓ&9ˆF�e�W˜A˜b˜T�?Ò#ð ñ  Øˆ	ä˜&Ÿ-™-›/Ó*€NØ˜aÑ €HØ€JØ—\‘\–^‰	ˆˆTØ�8ÓØ)-°hÑ?ˆJ�sŠOð $ð Ðøô ò 	Úð	ús   Å4GÇ	GÇGc            
      óž
  — t        j                  d¬«      } | j                  ddd¬«       | j                  ddd¬«       | j                  «       }|j                  rt	        «        y t        «       \  }}}}|j                  r³|st        d	«       y |rpt        j                  |«      j                  d
«      }t        j                  |«      j                  d
«      }t        d«       t        d|› �«       t        d|› �«       y t        j                  |«      j                  d
«      }t        d|› �«       y t        «       }t        dd› �«       t        dt        › �«       t        d› d�«       t        |«      \  }	}
}}}|rdn|rdnd}t        |› d�«       t        d|
› �«       t        dt        › d�«       t        d|› dt        › �«       t        |z
  }|dk  rt        d«       n|dk(  rt        d«       nt        d|› �«       t        «        t!        |«      \  }}}}}|rdn|rdnd}t        |› d�«       t        d|› �«       t        dt"        › d�«       t        d|› dt$        › �«       t$        |z
  }|dk  rt        d «       n|dk(  rt        d!«       nt        d|› �«       t        «        t'        |«      }|D �cg c]  }|j)                  d"«      sŒ|‘Œ }}t        d#t+        |«      › d$t+        |«      › d%�«       t        «        t-        |«      \  }}|r9t        d&t+        |«      › d'�«       |D ]  }t        d(|› �«       Œ t        d)«       nt        d*t+        |«      › d+�«       t        «        t/        «       }|r�t        d,t+        |«      › d-�«       |j1                  «       D ]  \  }}t        d(|› d.|d/   › d0|d1   › �«       Œ! t        d2«       t        d3«       t        d4«       t        d5«       t        «        n*dd l} | j3                  d6«      rt        d7«       t        «        t        d8› «       t        d9«       |s"t        d:«       t        d;«       t        d<«       nº|r†t        j                  |«      j                  d
«      }t        j                  |«      j                  d
«      }t        d=«       t        d>|› �«       t        d?|› �«       t        d@«       t        d<«       n2t        j                  |«      j                  d
«      }t        dA|› �«       t        «        |s|s|s|rt5        j6                  dB«       y y c c}w )CNz3Static Pine file analysis + TV validation sentinel.)Údescriptionz--mark-validÚ
store_truez0Record that Pine was confirmed OK in TradingView)ÚactionÚhelpz--statusz)Show sentinel status only, no full reportuP   âš ï¸�  No validation sentinel found â€” Pine has never been confirmed OK in TV.rR   u/   âš ï¸�  Pine modified AFTER last TV validation.z   Pine mtime:     z   Last validated: u'   âœ… Pine is current â€” last validated rS   z<============================================================zPine Static Analysis: u   â�Œu   âš ï¸� u   âœ…z request.security() callsz   Direct in file:    z   Library estimate:  +z (from imported libs)z   Estimated total:   z / r   u5      â�Œ OVER LIMIT â€” reduce request.security() callsu@      âš ï¸�  AT LIMIT â€” cannot add more request.security() callsz   Slots remaining:   z plot() + plotchar() callsu0      â�Œ OVER LIMIT â€” reduce plot/plotchar callsu;      âš ï¸�  AT LIMIT â€” cannot add more plot/plotchar callsÚ_normu   ðŸ“‹ plotchar exports: z total, z ending in _normu$   â�Œ Undeclared i_w_* weight params (u#   ) â€” will cause TV compile errors:z   z6   Fix: re-run  python3 tools/generate_pine_presets.pyu   âœ… All z) i_w_* weight params are declared in Pineu!   â�Œ MLP preset arch mismatch â€” z' preset(s) would be SKIPPED by codegen:z: winner arch rh   u    â‰  ref arch ri   zM   These presets produce ZERO weights in Pine (flat score = 0 for those TFs).z   Fix options:z]     A) Revert winner CSV to a compatible artifact:  git checkout HEAD -- results/winners/...z(     B) Do Phase 2 upgrade:  /mlp-phase2z=results/winners/optimization_winner_strategy_mlp_scores_*.csvu<   âœ… MLP preset architectures consistent (no skipped presets)u´   â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€zTV Validation Sentinelu+     âš ï¸�  Not yet validated in TradingView.u8     â†’ Paste Pine into TV, confirm it compiles, then run:z.      python3 tools/check_pine.py --mark-validu5     âš ï¸�  Pine was modified AFTER last TV validation.z     Pine modified:   z     Last validated:  u@     â†’ Paste updated Pine into TV, confirm it compiles, then run:u     âœ… Validated in TV at r   )ÚargparseÚArgumentParserÚadd_argumentÚ
parse_argsrX   rP   ÚstatusrW   r   ÚfromtimestamprV   r   r   r(   r   r   r2   r-   r.   r9   Úendswithr   rI   rƒ   rs   Úglobr   r   )!ÚparserÚargsÚsentinel_existsrM   rN   rO   Úpine_dtÚsent_dtr    Úsec_hitsr$   r%   Únear_secÚat_secÚsec_iconÚslots_remainingr0   Údirect_plotsÚestimated_plotsÚ	near_plotÚat_plotÚ	plot_iconÚslots_remaining_plotr7   ÚtÚnorm_titlesrF   rG   rH   Úskipped_presetsr‚   Úinfor‘   s!                                    r   Úmainr¦   Ê   s*  € Ü×$Ñ$Ð1fÔg€FØ
×Ñ˜¨|ØOð ô Qà
×Ñ˜
¨<ØHð ô Jà×ÑÓ€Dà‡‚ÜŒØä<KÓ<MÑ9€O�Z °à‡{‚{ÙÜÐdÔeð 	ñ Ü×,Ñ,¨ZÓ8×AÑAÐBUÓVˆGÜ×,Ñ,¨^Ó<×EÑEÐFYÓZˆGÜÐCÔEÜÐ'¨ yÐ1Ô2ÜÐ'¨ yÐ1Ô2ð 	ô ×,Ñ,¨^Ó<×EÑEÐFYÓZˆGÜÐ;¸G¸9ÐEÔFØä‹K€Eä	ˆBˆvˆhˆ-ÔÜ	Ð"¤9 +Ð
.Ô/Ü	ˆVˆH�Bˆ-Ôô ;OÈuÓ:UÑ7€Hˆf�o x°Ù‰u±(¡YÀ€HÜ	ˆXˆJÐ/Ð
0Ô1Ü	Ð" 6 (Ð
+Ô,Ü	Ð#Ô$:Ð#;Ð;PÐ
QÔRÜ	Ð" ?Ð"3°3Ô7JÐ6KÐ
LÔMÜ)¨OÑ;€OØ˜ÒÜÐEÕGØ	˜AÒ	ÜÐPÕRäÐ& Ð&7Ð8Ô9Ü	„Gô DTÐTYÓCZÑ@€Iˆ|˜_¨i¸Ù ‘±I¡yÀ5€IÜ	ˆYˆKÐ1Ð
2Ô3Ü	Ð" < .Ð
1Ô2Ü	Ð#Ô$6Ð#7Ð7LÐ
MÔNÜ	Ð" ?Ð"3°3´Ð6GÐ
HÔIÜ*¨_Ñ<ÐØ˜aÒÜÐ@ÕBØ	 Ò	"ÜÐKÕMäÐ&Ð';Ð&<Ð=Ô>Ü	„Gô ! Ó'€FÙ$Ó<™f˜¨¯
©
°7Õ(;’1˜f€KÐ<Ü	Ð#¤C¨£K =°¼¸[Ó9IÐ8JÐJZÐ
[Ô\Ü	„Gô 5°UÓ;Ñ€HˆjÙÜÐ4´S¸³_Ð4EÐEhÐiÔjÛˆAÜ�C˜�s�)Õð äÐFÕHä�œ˜X›˜Ð'PÐQÔRÜ	„Gô .Ó/€OÙÜÐ1´#°oÓ2FÐ1GÐGnÐoÔpØ(×.Ñ.Ö0‰IˆC�Ü�C˜�u˜N¨4°©>Ð*:¸.ÈÈeÉÈÐVÕWð 1äÐ]Ô_Ü�Ô!ÜÐmÔoÜÐ8Ô:Ü�ó 	Ø�9‰9ÐTÔUÜÐPÔRÜŒGô 
ˆXˆJÔÜ	Ð
"Ô#ÙÜÐ;Ô<ÜÐHÔJÜÐ>Õ@Ù	Ü×(Ñ(¨Ó4×=Ñ=Ð>QÓRˆÜ×(Ñ(¨Ó8×AÑAÐBUÓVˆÜÐEÔGÜÐ& w iÐ0Ô1ÜÐ& w iÐ0Ô1ÜÐPÔRÜÐ>Õ@ä×(Ñ(¨Ó8×AÑAÐBUÓVˆÜÐ)¨'¨Ð3Ô4ä	„Gñ ‘™J©/Ü�‰��ð +:ùòo =s   Ê?U
ËU
Ú__main__)Ú__doc__rŠ   r	   r*   r   r   r   rL   r   r   r-   r.   r   r/   r   r(   r2   r9   rI   rP   rX   Údictrƒ   r¦   Ú__name__© r3   r   Ú<module>r¬      s›   ðñó8 Û 	Û 	Û 
Ý à8€	Ø$€ð Ð ØÐ ð Ð Ø€ð Ð Ø€òò?òDò"	ò òB	6òSð& ó &òR|ð~ ˆzÒÙ…Fð r3   