
    `i-&                         d Z ddlZddlZddlZddlZddlmZmZ ddlmZ ddl	m
Z
  ej                  d      Z G d d      Zy)	u  
=============================================================================
execution_logger.py — Module de logging d'exécution détaillé
=============================================================================

POURQUOI CE MODULE
------------------
Le bot actuel ne sait PAS combien il paie réellement en spread/slippage.
Il calcule ses PnL avec les prix "théoriques" (mid market au moment du signal),
alors que les ordres MARKET sur Binance s'exécutent au ASK (achat) ou au BID
(vente). La différence ASK-BID, c'est le spread — invisible dans les logs
actuels, mais bien réel sur le compte.

CE QUE FAIT CE MODULE
---------------------
À chaque ordre passé, il loggue dans un fichier dédié :
  - Prix théorique au moment du signal (ce que le bot voyait)
  - Type d'ordre (MARKET / LIMIT)
  - Prix d'exécution réel (depuis la réponse Binance)
  - Slippage en absolu et en pourcentage
  - Spread bid/ask au moment du fill
  - Volume 24h de la paire (pour corréler liquidité ↔ slippage)
  - Tous les fills individuels (un ordre peut être splitté en plusieurs)

UTILISATION DANS market_spy.py
------------------------------
1. Copier ce fichier dans le dossier du bot
2. En haut de market_spy.py, ajouter :

    from execution_logger import ExecutionLogger
    exec_logger = ExecutionLogger(log_dir="/var/log/market_spy")

3. À chaque ordre BUY, juste après la réponse Binance :

    order = client.create_order(symbol=..., side="BUY", type="MARKET", ...)
    exec_logger.log_buy(
        symbol=symbol,
        order_response=order,
        theoretical_price=price_at_signal,
        signal_pattern=pattern_name,
    )

4. À chaque ordre SELL, juste après la réponse Binance :

    order = client.create_order(symbol=..., side="SELL", type="MARKET", ...)
    exec_logger.log_sell(
        symbol=symbol,
        order_response=order,
        theoretical_price=price_at_exit_signal,
        exit_reason=reason,
        buy_log_id=buy_log_id,
    )

Le module crée un fichier JSONL (une ligne JSON par ordre) facile à analyser
ensuite avec le script `analyze_execution.py`.
=============================================================================
    N)datetimetimezone)Path)Optionalexecution_loggerc                       e Zd ZdZddefdZdedededed	ef
d
Z	 ddedededede	e   d	efdZ
dedededededed	efdZded	efdZded	e	e   fdZded	dfdZy)ExecutionLoggeru1   Logger structuré pour chaque exécution d'ordre.Nlog_dirc                 "   t        |      | _        | j                  j                  dd       | j                  dt        j                         j                  d       dz  | _        || _        t        j                  d| j                          y)u   
        Args:
            log_dir : dossier où écrire les logs JSONL
            binance_client : client Binance pour récupérer le bid/ask
                             (optionnel mais recommandé)
        T)parentsexist_okexecutions_z%Y%mz.jsonlu    ExecutionLogger initialisé → N)
r   r
   mkdirr   nowstrftimelog_pathclientloginfo)selfr
   binance_clients      3/home/ubuntu/crypto_trading_bot/execution_logger.py__init__zExecutionLogger.__init__I   sq     G}4$7X\\^5L5LV5T4UU['\\$3DMM?CD    symbolorder_responsetheoretical_pricesignal_patternreturnc           	          t        t        j                               dd }| j                  |d|||d|i|      }| j	                  |       |S )uB   Loggue un ordre BUY. Retourne un buy_log_id à passer à log_sell.N   BUYr   log_idsider   r   r   extrastruuiduuid4_build_record_write)r   r   r   r   r   r&   r$   records           r   log_buyzExecutionLogger.log_buyZ   s_     TZZ\"2A&##)/#^=u= $ 
 	Fr   exit_reason
buy_log_idc           
          t        t        j                               dd }| j                  |d|||||d|      }| j	                  |       |S )z1Loggue un ordre SELL et lie au BUY correspondant.Nr!   SELL)r/   r0   r#   r'   )	r   r   r   r   r/   r0   r&   r$   r-   s	            r   log_sellzExecutionLogger.log_sellj   s_    
 TZZ\"2A&##)/"-ZQ5Q $ 
 	Fr   r$   r%   r&   c                 F   |j                  d      }|j                  dd      }|j                  dd      }	t        |j                  dd            }
t        |j                  dd            }|
dkD  r||
z  }nd}t        j                  d	| d
|	        |dkD  r|dkD  r||z
  }||z  dz  }|dk(  r| }| }nd}d}g }|j                  dg       D ]s  }|j	                  t        |j                  dd            t        |j                  dd            t        |j                  dd            |j                  dd      d       u t        d |D              }| j                  |      \  }}}| j                  |      }|j                  dt        t        j                         dz              }i d|dt        j                  t        j                        j                         d|d|d|d|d|d|	d|
d|d |d!|d"|d#|d$t        |      d|d%|||||d&|S )'u   
        Extrait toutes les infos utiles de la réponse Binance et calcule
        les métriques de qualité d'exécution.
        orderIdtypeUNKNOWNstatusexecutedQtyr   cummulativeQuoteQtyg        zOrdre u%    sans qty exécutée — voir status=d   r2   fillspriceqty
commissioncommissionAsset )r=   r>   r?   commission_assetc              3   &   K   | ]	  }|d      yw)r?   N ).0fs     r   	<genexpr>z0ExecutionLogger._build_record.<locals>.<genexpr>   s     E1qEs   transactTimei  r$   timestamp_utctransact_time_msr%   r   order_id
order_typeexecuted_qtycumm_quote_qtyavg_fill_pricer   slippage_absslippage_pctn_fillstotal_commission)bidask
spread_pctvolume_24h_usdt)getfloatr   warningappendsum_fetch_bid_ask_fetch_volume_24hinttimer   r   r   utc	isoformatlen)r   r$   r%   r   r   r   r&   rK   rL   r8   rM   rN   rO   rP   rQ   fills_detailfillrS   rT   rU   rV   vol_24htransact_times                          r   r+   zExecutionLogger._build_record   s    "%%i0#''	:
##Hi8^//qAB~112GKL !+l:N NKK&
*OPVxXY q ^a%7),==L(+<<CL v~ ,} ,}LL "&&w3 	Dtxx34TXXeQ/0#DHH\1$=>$(HH->$C	! 	 EEE  $226:S* ((0 '**>3tyy{T?Q;RS
f
X\\(,,7AAC
 
 D	

 f
 
 *
 f
 L
 n
 n
  !2
 L
 L
 s<(
  \!
"  0#
$ $&+
, -
 	
r   c                    | j                   y	 | j                   j                  |      }t        |d         }t        |d         }|dkD  r||z
  |z  dz  nd }|||fS # t        $ r%}t        j                  d| d|        Y d }~yd }~ww xY w)	N)NNNr   bidPriceaskPricer   r;   zBid/ask KO pour : )r   get_orderbook_tickerrY   	Exceptionr   debug)r   r   tickerrT   rU   rV   es          r   r]   zExecutionLogger._fetch_bid_ask   s    ;;%	&[[55V5DFz*+Cz*+C69Ag39+c14Jj)) 	&II(1#67%	&s   AA 	B'BBc                     | j                   y 	 | j                   j                  |      }t        |j                  dd            S # t        $ r%}t
        j                  d| d|        Y d }~y d }~ww xY w)Nri   quoteVolumer   zVolume 24h KO pour rl   )r   
get_tickerrY   rX   rn   r   ro   )r   r   rp   rq   s       r   r^   z!ExecutionLogger._fetch_volume_24h   sn    ;;	[[++6+:FM1566 	II+F82aS9:	s   6A 	A4A//A4r-   c                    	 t        | j                  d      5 }|j                  t        j                  |      dz          ddd       y# 1 sw Y   yxY w# t
        $ r"}t        j                  d|        Y d}~yd}~ww xY w)u/   Écriture en append, une ligne JSON par record.a
Nu$   Échec écriture log d'exécution : )openr   writejsondumpsrn   r   error)r   r-   rF   rq   s       r   r,   zExecutionLogger._write   so    	BdmmS) 3Q

6*T123 3 3 	BII<QC@AA	Bs4   A (A	 A 	AA A 	B A;;B )z./exec_logsN)N)__name__
__module____qualname____doc__r(   r   dictrY   r.   r   r3   r+   tupler]   r^   r,   rD   r   r   r	   r	   F   s    ;E E"c 4 #(:=$ .2s D $)8;%c] !*O
C O
s O
C O
&*O
?DO
!O
&*O
j&S &U &  BT Bd Br   r	   )r   rz   loggingr`   r)   r   r   pathlibr   typingr   	getLoggerr   r	   rD   r   r   <module>r      sC   8t     '  g*+oB oBr   