
    mujB@              
       B   S r SSKrSSKrSSKrSSKrSSKJrJrJr  SSK	r
SSKr\R                  R                  S\R                  R                  \R                  R                  \R                  R!                  \5      5      5      5        SSKJr   SSKJr  S\S\4S jr\R                  R7                  \R                  R                  \R                  R                  \R                  R!                  \5      5      5      S	5      r\R                  R7                  \S
5      r/ SQr\4S\S\\   4S jjrSS\\   S\S\ 4S jjr!Sr"\"4S\ S\ 4S jjr#S\\   SS4S jr$S\SS4S jr%/ SQr&SS\\\      S\ 4S jjr'S r(\)S:X  a  \(" 5         gg! \ a    Sr GNf = f)u  
sync_signals — синхронизация сигналов MoE v12 из summary_report в MySQL (current_signals).

Вызывается из monitor.py после завершения анализа, либо вручную:
    python -m utils.sync_signals

Записывает для каждого тикера: signal_type, confidence, p_long, p_short,
tp_price, sl_price, close_price, updated_at.
    N)ListDictOptional)get_connection)is_moex_only_longtickerreturnc                 J    [         c  g [        U 5      $ ! [         a     gf = f)uY   True если тикер относится к MOEX в режиме only-LONG (no short).F)_is_moex_only_long	Exception)r   s    3/home/ai/projects/AI_Strategy/utils/sync_signals.pysignal_is_moex_long_onlyr      s-    !!&)) s   
 
""
monitoringzsummary_report.md)ASTRGAZPLKOHMOEXMTSSNSVZNVTKPHORPLZLROSNSBERSNGSPVTBRX5BITCOINBITCOINCZCASHEURUSDfilepathc                    [         R                  R                  U 5      (       d  [        SU  35        / $ [	        U SSS9 nUR                  5       nSSS5        / n[        R                  " S[        R                  5      nUR                  W5       H  nUR                  S5      nUR                  S5      nUR                  S	5      n[        UR                  S
5      5      S-  n	[        UR                  S5      5      S-  n
[        UR                  S5      5      S-  nUS:X  d  M  UR                  UUS;   a  UOSU	U
USSSS.5        M     [        S[        U5       SU  35        U$ ! , (       d  f       GN= f)ui   Парсит summary_report.md и возвращает список сигналов по тикерам.u+   [sync_signals] Файл не найден: rutf-8encodingNzv^\|\s*(\w+)\s*\|\s*(ok|stale|error|no_candle|no_model)\s*\|\s*(\w+)\s*\|\s*([\d.]+)%\s*\|\s*([\d.]+)%\s*\|\s*([\d.]+)%            g      Y@      okBUYSELLNEUTRAL        )r   signal_type
confidencep_longp_shorttp_pricesl_priceclose_priceu$   [sync_signals] Распарсено u    сигналов из )ospathexistsprintopenreadrecompile	MULTILINEfinditergroupfloatappendlen)r"   fcontentsignalstable_patternmatchr   statussignalconfr6   r7   s               r   parse_summary_reportrQ   /   sS   77>>(##;H:FG		hg	.!&&( 
/ GJJ 	B
M
 ''0QQQU[[^$u,u{{1~&.A'%/T>NN )/?)Bv	" ""	 	 1( 
0W>UV^U_
`aN? 
/	.s    E((
E7rK   
model_typec                    U (       d  g[        [        R                  " 5       5      nSn[        5        nUR                  5       nU  Hm  n[	        US   5      (       a  SUS'   UR                  S5      S:X  a  SUS'   UR                  SUS   US   US	   US
   US   US   US   US   X4
5        US-  nMo     SSS5        [        SU S35        U$ ! , (       d  f       N= f)u:   Upsert сигналов в таблицу current_signals.r   r   r3   r7   r4   r1   r2   a   
                INSERT INTO current_signals
                    (ticker, signal_type, confidence, p_long, p_short,
                     tp_price, sl_price, close_price, model_type, updated_at)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                ON DUPLICATE KEY UPDATE
                    signal_type = VALUES(signal_type),
                    confidence = VALUES(confidence),
                    p_long = VALUES(p_long),
                    p_short = VALUES(p_short),
                    tp_price = VALUES(tp_price),
                    sl_price = VALUES(sl_price),
                    close_price = VALUES(close_price),
                    model_type = VALUES(model_type),
                    updated_at = VALUES(updated_at)
            r5   r6   r8   r9   r:   r(   Nu    [sync_signals] Записано u$    сигналов в current_signals)inttimer   cursorr   getexecuter>   )rK   rR   now_tsupdatedconncurss          r   
sync_to_dbr^   W   s    FG		TkkmA ((44")55'61'0Am$KK   (Q}-q(Qy\*q}a.>	* qLG9  
B 
,WI5Y
Z[NE 
	s   BC
Ci`T  threshold_secc                 ,   [        [        R                  " 5       5      nX-
  nSn[        5        nUR                  SS9nUR	                  SU45        UR                  5       nU(       d  UR                  5          SSS5        gU H  nU[        UR                  S5      =(       d    S5      -
  nUS-  n	UR                  SS	5      n
[        S
US    SU
 SU	S S35        Sn SSK	nUR                  S5      R                  SUS    SU
 SU	S S35        M     UR	                  SX45        UR                  nUR                  5         UR                  5         SSS5        US:  a  [        SU 35        U$ ! [         a     M  f = f! , (       d  f       N5= f)uL  Сбрасывает устаревшие сигналы в current_signals в NEUTRAL.

Если updated_at < (now - threshold_sec) для тикера — обнуляет signal_type,
confidence, tp_price, sl_price, выставляет updated_at=now.

Возвращает количество обнулённых строк.
r   T)
dictionaryznSELECT ticker, signal_type, updated_at FROM current_signals WHERE updated_at < %s AND signal_type != 'NEUTRAL'N
updated_ati  r4   ?z[sync_signals] STALE r   : z	 updated z.1fu   h ago → NEUTRALAI_Strategyzcurrent_signals STALE:  z (u   h ago) → NEUTRALzUPDATE current_signals SET signal_type='NEUTRAL', confidence=0, p_long=0, p_short=0,     tp_price=0, sl_price=0, close_price=0, updated_at=%s WHERE updated_at < %s AND signal_type != 'NEUTRAL'uG   [sync_signals] Сброшено устаревших сигналов: )rT   rU   r   rV   rX   fetchallcloserW   r>   logging	getLoggerinfor   rowcountcommit)r_   rY   cutoffresetr[   r\   
stale_rowsrow	stale_secstale_hold_sigloggerri   s                r   cleanup_stale_signalsrv      s    F#FE		TkkTk*AI	

 \\^
IIK 
	 CSWW\%:%?a!@@I$&GggmS1G)#h-7) D$SM):< =F!!-055-c(m_AgY G}$68   	A 	
 		Q 
T qyWX]W^_`L!  9 
	s8   AFAF!2E4AF4
F>FFF
Fc                 P   U  GH^  nUS   n[         R                  R                  [        UR	                  5        S35      n[         R                  R                  U5      (       d  Md   [        USSS9 nUR                  5       nSSS5        WR                  5       R                  S5      nU Vs/ s H3  owR                  S5      (       d  M  UR                  S	5      S
:  d  M1  UPM5     nnU(       ad  US   n	U	R                  S	5       V
s/ s H  oR                  5       PM     nn
[        U5      S:  a"   [        US   R                  SS5      5      US'   [%        U5        GMa     g! , (       d  f       N= fs  snf s  sn
f ! [        [         4 a     N>f = f! ["         a     NNf = f)ub   Дополняет сигналы ценами close, tp, sl из individual monitor-файлов.r   z_monitor.mdr$   r%   r&   N
z| |r,      r)   , r:   )r;   r<   joinMONITOR_DIRlowerr=   r?   r@   stripsplit
startswithcountrH   rF   replace
ValueError
IndexErrorr   _compute_tp_sl)rK   r]   r   monitor_filerI   rJ   linesl
data_lines	last_lineppartss               r   sync_ticker_pricesr      s^   8ww||KFLLN3C;1OPww~~l++	lC':a&&( ; MMO))$/E%*WUll4.@!QWWS\UVEV!UJW&rN	,5OOC,@A,@q,@Au:?+0q1A1A#r1J+K-( 	q9  ;:
 X B
 '
3  		sl   (F3E'+F/E8E8#E8)!F
E=#F5!F'
E5	1FFFFF
F%$F%r]   c                    U R                  SS5      nUS;  a  SU S'   SU S'   g SS	KJn  U" U S
   5      u  p4nSSKJn  SSKJn  U" U S
   SSSS9nUb  [        U5      S:  a  gU" U5      n[        US   R                  S   5      n	[        US   R                  S   5      n
U	S:  a  U
S::  a  gX:  a  gXS-  :  a  gUS:X  a/  [        U
SXI-  -   -  S5      U S'   [        U
SX9-  -
  -  S5      U S'   O.[        U
SXI-  -
  -  S5      U S'   [        U
SX9-  -   -  S5      U S'   [        U
S5      U S'   g! [         a     gf = f)u  Вычисляет TP/SL для сигнала BUY/SELL из последней H1-свечи + ATR.

BUG-FIX (2026-07-31): множители берутся per-market из get_risk_params
(MARKET_TARGET_CONFIGS). Ранее захардкожено 3/6 — это противоречило
тренировочным целям для crypto (4/8) и forex (2/4). Также порог ATR
валидации был global 5%/10%, что некорректно для crypto.

Для NEUTRAL TP/SL = 0.
r4   r2   r/   r3   r8   r9   Nr   )get_risk_paramsr   load_dataframeengineer_featuresH1d   Tlimitclean   atr_pctrz   Closer*   r0   r(      r:   )rW   configr   data.loaderr   features.technicalr   rH   rF   ilocroundr   )r]   sigr   sl_multtp_multmax_atr_ratior   r   dfr   rh   s              r   r   r      sz    %%y
)C
/!**!**9!H+*F'-.8AhKSE:R2r"9**2./bk&&r*+!

 "Q&&%<!%1w/@+@"A1EAjM!%1w/@+@"A1EAjM!%1w/@+@"A1EAjM!%1w/@+@"A1EAjM ?- s+   >D1 $A
D1 /D1 5D1 >A2D1 1
D>=D>)
rsi_signal	bb_signalmacd_signaltrend_signalmomentum_signalvolume_signaldirectional_biassignal_strengthtickersc                    U c  [         n SSKJn  SSKJn  SSKJn  [        [        R                  " 5       5      nSnU  GHY  n U" USSSS	9nUb  [        U5      S
:  a  M"  U" U5      nU" U5      nUR                  S   n0 n	[         Hd  n
[        UR                  U
S5      5      n[        R                  " U5      (       d  [         R"                  " U5      (       a  Sn[%        US5      X'   Mf     [        UR                  SS5      5      n[        UR                  SS5      5      n['        5        nUR)                  5       nUR+                  SUU	S   U	S   U	S   U	S   U	S   U	S   U	S   U	S   [%        US5      [%        US5      U45        US-  nSSS5        GM\     [/        SU 35        U$ ! , (       d  f       GM~  = f! [,         a  n[/        SU SU 35         SnAGM  SnAff = f)u0  Вычисляет directional сигналы для всех тикеров и сохраняет в regression_signal_data.

Args:
    tickers: список тикеров. Если None — использует FALLBACK_TICKERS.

Returns:
    количество записанных тикеров.
Nr   r   r   )add_directional_signalsr      Tr   2   rz   r3   r-   r   r   a[  
                    INSERT INTO regression_signal_data
                        (ticker, rsi_signal, bb_signal, macd_signal,
                         trend_signal, momentum_signal, volume_signal,
                         directional_bias, signal_strength,
                         atr_pct, close_price, updated_at)
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                    ON DUPLICATE KEY UPDATE
                        rsi_signal = VALUES(rsi_signal),
                        bb_signal = VALUES(bb_signal),
                        macd_signal = VALUES(macd_signal),
                        trend_signal = VALUES(trend_signal),
                        momentum_signal = VALUES(momentum_signal),
                        volume_signal = VALUES(volume_signal),
                        directional_bias = VALUES(directional_bias),
                        signal_strength = VALUES(signal_strength),
                        atr_pct = VALUES(atr_pct),
                        close_price = VALUES(close_price),
                        updated_at = VALUES(updated_at)
                r   r   r   r   r   r   r   r   r   r(   u   [sync_signals]  ✗ rd   uM   [sync_signals] Записано регрессионных сигналов: )FALLBACK_TICKERSr   r   r   r   features.directionalr   rT   rU   rH   r   DIRECTIONAL_SIGNAL_COLSrF   rW   pdisnanpisnanr   r   rV   rX   r   r>   )r   r   r   r   rY   rZ   r   r   lastsignals_datacolvalr   rh   r[   r\   es                    r   sync_regression_signalsr   &  s    "*4<FG=	CtDBzSWr\ #2&B(,B772;D L.DHHS#./773<<288C==C$)#qM!	 / DHHY45G$((7C01E!Tkkm (  . - / 0 !23 1 !34 !23'1%%O' B 1G "!/ @ 
YZaYb
cdNU "!J  	(1#67	s>   F? CF?/A F,F?,
F<	6F?<F??
G&	G!!G&c            
         SSK n U R                  SS9nUR                  SSSS9  UR                  S	SS
S9  UR                  5       nUR                  (       a  [        5         gUR                  (       a
  [        5         [        5       nU(       d  [        S5        g[        U5        [        U5        [        S U 5       5      n[        S U 5       5      n[        SU SU S[        U5      U-
  U-
   S35        g)u   Основной Entry Point.r   Nu4   Синхронизация сигналов в MySQL)descriptionz--regression
store_trueue   Синхронизировать только регрессионные (directional) сигналы)actionhelpz--allub   Синхронизировать и основные, и регрессионные сигналыuI   [sync_signals] Нет сигналов для синхронизации.c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)r4   r0   r(   N .0r]   s     r   	<genexpr>main.<locals>.<genexpr>  s     ?'Q}%5%>qq'   	c              3   :   #    U  H  oS    S:X  d  M  Sv   M     g7f)r4   r1   r(   Nr   r   s     r   r   r     s     A7a&6&&@7r   u    [sync_signals] Итого: 🟢 u    BUY | 🔴 u    SELL | ⚪ z NEUTRAL)argparseArgumentParseradd_argument
parse_args
regressionr   allrQ   r>   r   r^   sumrH   )r   parserargsrK   buyssellss         r   mainr   }  s    $$1g$hF
| E  F
 B  CD!xx!"$GYZww ?'??DA7AAE	,TF,ug\RUV]R^aeRehmRmQnnv
wx    __main__)moe_v12)N)*__doc__sysr;   rA   rU   typingr   r   r   numpyr   pandasr   r<   insertdirnameabspath__file__db.connectionr   r   r   r   ImportErrorstrboolr   r~   r   SUMMARY_FILEr   rQ   rT   r^   STALE_SIGNAL_THRESHOLD_SECrv   r   r   r   r   r   __name__r   r   r   <module>r      s     ' '   277??277??277??83L#MN O (>
S T  ggll277??277??277??8;T+UVXdeww||K)<=> 
 *6 %3 %$t* %P*T
 * *C *` &  0J 8 8c 8vT
 t B1d 1t 1r TXd3i%8 TC Tny> zF I  s   F FF