
    ˈiI                        d Z ddlmZmZ ddlmZmZ ddlmZ ddlm	Z	m
Z
mZ ddlmZ ddlmZmZ  G d d	e      Z G d
 de      Z G d de      Ze G d d             Ze G d d             Z G d de      Z G d de      Zy)z
Order placement and execution engine.

Provides abstract interface for order execution that can be implemented
for backtesting (simulated) or live trading (exchange API).
    )ABCabstractmethod)	dataclassfield)datetime)ListOptionalDict)Enum)normalize_pricenormalize_lot_sizec                       e Zd ZdZdZdZdZy)	OrderTypezOrder type enumeration.marketlimitstopN)__name__
__module____qualname____doc__MARKETLIMITSTOP     ./var/www/html/crpytotradingbot/order_engine.pyr   r      s    !FEDr   r   c                       e Zd ZdZdZdZy)	OrderSidezOrder side enumeration.buysellN)r   r   r   r   BUYSELLr   r   r   r   r      s    !
CDr   r   c                        e Zd ZdZdZdZdZdZy)OrderStatuszOrder status enumeration.pendingopenclosed	cancelledN)r   r   r   r   PENDINGOPENCLOSED	CANCELLEDr   r   r   r$   r$      s    #GDFIr   r$   c                      e Zd ZU dZeed<   eed<   eed<   eed<   e	ed<   e	ed<   dZ
ee	   ed	<   dZee	   ed
<   ej                  Zeed<   dZee   ed<   dZee   ed<   dZee	   ed<   dZe	ed<   dZeed<   dZeed<   defdZdefdZy)OrderzOrder data structure.order_idsymbolside
order_typelotspriceNtp_pricesl_pricestatus	open_time
close_timeclose_price        profitr   magic commentreturnc                 <    | j                   t        j                  k(  S )z!Check if order is currently open.)r7   r$   r*   selfs    r   is_openzOrder.is_open9   s    {{k....r   c                 <    | j                   t        j                  k(  S )zCheck if order is closed.)r7   r$   r+   rB   s    r   	is_closedzOrder.is_closed=   s    {{k0000r   )r   r   r   r   int__annotations__strr   r   floatr5   r	   r6   r$   r)   r7   r8   r   r9   r:   r<   r=   r?   boolrD   rF   r   r   r   r.   r.   &   s    MK
O
KL $Hhuo$ $Hhuo$%--FK-$(Ix!(%)J")#'K%'FEE3NGS/ /14 1r   r.   c                       e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   dZ	e
e   ed	<   dZe
e   ed
<   dZe
e   ed<   dZeed<   dZeed<   dedefdZy)PositionzActive position data structure.position_idr0   r1   r3   entry_pricecurrent_priceNr5   r6   r8   r   r=   r;   unrealized_pnlr@   c                     || _         | j                  t        j                  k(  r-| j                  || j
                  z
  z  | _        | j                  S | j                  | j
                  |z
  z  | _        | j                  S )z!Update and return unrealized P&L.)rP   r1   r   r!   r3   rO   rQ   )rC   rP   s     r   
update_pnlzPosition.update_pnlQ   sn    *99	%"&))}t?O?O/O"PD """ #'))t/?/?-/O"PD"""r   )r   r   r   r   rG   rH   rI   r   rJ   r5   r	   r6   r8   r   r=   rQ   rS   r   r   r   rM   rM   B   sw    )K
O
K $Hhuo$ $Hhuo$$(Ix!(E3NNE# #% #r   rM   c                      e Zd ZdZdefdZdefdZe	 	 	 	 dde	de
e	   d	e
e	   d
edede
e   fd       Ze	 	 	 	 dde	de
e	   d	e
e	   d
edede
e   fd       Ze	 d dede
e	   de
e	   fd       Ze	 d dede
e	   de
e	   fd       Zedefd       Zede	de	ddfd       Zdee   fdZdee   fdZd
edee   fdZd
edee   fdZdede	defdZdede	defdZy)!OrderEnginez
    Abstract base class for order execution engines.

    Implementations provide either simulated (backtest) or
    real (exchange API) order execution.
    r0   c                 <    || _         d| _        i | _        i | _        y)za
        Initialize order engine.

        Args:
            symbol: Trading pair symbol
        r   N)r0   _order_counterorders	positions)rC   r0   s     r   __init__zOrderEngine.__init__c   s!     (*.0r   r@   c                 D    | xj                   dz  c_         | j                   S )zGenerate next order ID.   )rW   rB   s    r   _next_order_idzOrderEngine._next_order_ido   s    q """r   Nr3   r5   r6   r=   r?   c                      y)a:  
        Place a buy order.

        Args:
            lots: Position size
            tp_price: Take profit price
            sl_price: Stop loss price
            magic: Magic number for tracking
            comment: Order comment

        Returns:
            Order object if successful, None otherwise
        Nr   rC   r3   r5   r6   r=   r?   s         r   place_buy_orderzOrderEngine.place_buy_ordert       , 	r   c                      y)a;  
        Place a sell order.

        Args:
            lots: Position size
            tp_price: Take profit price
            sl_price: Stop loss price
            magic: Magic number for tracking
            comment: Order comment

        Returns:
            Order object if successful, None otherwise
        Nr   r_   s         r   place_sell_orderzOrderEngine.place_sell_order   ra   r   r/   r:   c                      y)z
        Close an open order/position.

        Args:
            order_id: Order ID to close
            close_price: Price to close at (optional, uses current if not specified)

        Returns:
            Profit/loss from the closed position
        Nr   )rC   r/   r:   s      r   close_orderzOrderEngine.close_order         	r   rN   c                      y)z
        Close an open position.

        Args:
            position_id: Position ID to close
            close_price: Price to close at

        Returns:
            Profit/loss from the closed position
        Nr   rC   rN   r:   s      r   close_positionzOrderEngine.close_position   rf   r   c                      y)zf
        Get current bid/ask prices.

        Returns:
            Tuple of (bid, ask) prices
        Nr   rB   s    r   get_current_pricezOrderEngine.get_current_price   s     	r   bidaskc                      y)z
        Update current market prices.

        Args:
            bid: Current bid price
            ask: Current ask price
        Nr   )rC   rl   rm   s      r   update_priceszOrderEngine.update_prices   s     	r   c                 ~    | j                   j                         D cg c]  }|j                         s| c}S c c}w )zX
        Get all open orders.

        Returns:
            List of open orders
        )rX   valuesrD   )rC   os     r   get_open_orderszOrderEngine.get_open_orders   s-      ;;--/?a199;???s   ::c                 H    t        | j                  j                               S )z^
        Get all open positions.

        Returns:
            List of open positions
        )listrY   rq   rB   s    r   get_open_positionszOrderEngine.get_open_positions   s     DNN))+,,r   c                 |    | j                   j                         D cg c]  }|j                  |k(  s| c}S c c}w )z
        Get orders by magic number.

        Args:
            magic: Magic number to filter by

        Returns:
            List of matching orders
        )rX   rq   r=   )rC   r=   rr   s      r   get_orders_by_magiczOrderEngine.get_orders_by_magic   s0      ;;--/Da177e3CDDD   99c                 |    | j                   j                         D cg c]  }|j                  |k(  s| c}S c c}w )z
        Get positions by magic number.

        Args:
            magic: Magic number to filter by

        Returns:
            List of matching positions
        )rY   rq   r=   )rC   r=   ps      r   get_positions_by_magicz"OrderEngine.get_positions_by_magic   s0      >>002Gaagg6FGGGry   positionrP   c                     |j                   y|j                  t        j                  k(  r||j                   k\  S ||j                   k  S )z
        Check if take profit has been hit.

        Args:
            position: Position to check
            current_price: Current market price

        Returns:
            True if TP has been hit
        F)r5   r1   r   r!   rC   r}   rP   s      r   check_tp_hitzOrderEngine.check_tp_hit  E     $==IMM) H$5$555 H$5$555r   c                     |j                   y|j                  t        j                  k(  r||j                   k  S ||j                   k\  S )z
        Check if stop loss has been hit.

        Args:
            position: Position to check
            current_price: Current market price

        Returns:
            True if SL has been hit
        F)r6   r1   r   r!   r   s      r   check_sl_hitzOrderEngine.check_sl_hit  r   r   NNr   r>   N)r   r   r   r   rI   rZ   rG   r]   r   rJ   r	   r.   r`   rc   re   ri   tuplerk   ro   r   rs   rM   rv   rx   r|   rK   r   r   r   r   r   rU   rU   [   s7   
1s 
1# #
  %)$( 5/ 5/	
   
% .  %)$( 5/ 5/	
   
% .  (, e_ 
%	 "  (, e_ 
%	 " 5    U t  @e @-DN -
E 
Ee 
E
HC 
HDN 
H6X 6e 6 6&6X 6e 6 6r   rU   c                   ~    e Zd ZdZ	 	 	 d#dedededef fdZdedd	fd
Zdededd	fdZ	de
fdZdededefdZ	 	 	 	 d$dedee   dee   dededee   fdZ	 	 	 	 d$dedee   dee   dededee   fdZ	 d%dedee   dee   fdZ	 d%dedee   dee   fdZdefdZdefdZded edee
   fd!Zdefd"Z xZS )&BacktestOrderEnginezm
    Order engine for backtesting.

    Simulates order execution with configurable spread and slippage.
    r0   initial_balancecommission_percentslippage_pipsc                     t         |   |       || _        || _        || _        || _        d| _        d| _        d| _        g | _	        d| _
        y)a  
        Initialize backtest order engine.

        Args:
            symbol: Trading pair symbol
            initial_balance: Starting balance
            commission_percent: Commission per trade (percentage)
            slippage_pips: Simulated slippage in pips
        r;   N)superrZ   r   balancer   r   _current_bid_current_ask_current_timetrade_historytotal_commission)rC   r0   r   r   r   	__class__s        r   rZ   zBacktestOrderEngine.__init__5  sY      	 .&"4*15*, #r   timer@   Nc                     || _         y)zSet current simulation time.N)r   )rC   r   s     r   set_timezBacktestOrderEngine.set_timeR  s
    !r   rl   rm   c                     || _         || _        | j                  j                         D ]  }|j	                  |        y)zUpdate current market prices.N)r   r   rY   rq   rS   )rC   rl   rm   r}   s       r   ro   z!BacktestOrderEngine.update_pricesV  s>     --/ 	%H$	%r   c                 2    | j                   | j                  fS )zGet current bid/ask prices.)r   r   rB   s    r   rk   z%BacktestOrderEngine.get_current_price_  s    !!4#4#455r   r3   r4   c                 0    ||z  }|| j                   dz  z  S )z!Calculate commission for a trade.d   )r   )rC   r3   r4   position_values       r   _calculate_commissionz)BacktestOrderEngine._calculate_commissionc  s!    !8!83!>??r   r5   r6   r=   r?   c                    t        || j                        }| j                  }| j                  dkD  r&ddlm} | || j                  | j                        z  }t        || j                        }| j                         }|dk  ry| j                  ||      }	| xj                  |	z  c_	        | xj                  |	z  c_
        | j                         }
t        |
| j                  t        j                  t        j                   |||rt        || j                        nd|rt        || j                        ndt"        j$                  | j&                  ||      }|| j(                  |
<   t+        |
| j                  t        j                  ||| j,                  |j.                  |j0                  | j&                  |
      }|j3                  | j,                         || j4                  |
<   |S )z*Place a buy order (executed at ask price).r   pips_to_priceNr/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r=   r?   
rN   r0   r1   r3   rO   rP   r5   r6   r8   r=   )r   r0   r   r   normalizationr   r   
get_equityr   r   r   r]   r.   r   r!   r   r   r$   r*   r   rX   rM   r   r5   r6   rS   rY   rC   r3   r5   r6   r=   r?   execution_pricer   equity
commissionr/   orderr}   s                r   r`   z#BacktestOrderEngine.place_buy_orderh  s    "$4++ !3}T-?-?MMO)/4;;G "Q; //oF
+
"&&(;; ''!?G_Xt{{;T?G_Xt{{;T##((
 !&H  ;;'++^^^^((
 	D--.#+x r   c                    t        || j                        }| j                  }| j                  dkD  r&ddlm} | || j                  | j                        z  }t        || j                        }| j                         }|dk  ry| j                  ||      }	| xj                  |	z  c_	        | xj                  |	z  c_
        | j                         }
t        |
| j                  t        j                  t        j                   |||rt        || j                        nd|rt        || j                        ndt"        j$                  | j&                  ||      }|| j(                  |
<   t+        |
| j                  t        j                  ||| j,                  |j.                  |j0                  | j&                  |
      }|j3                  | j,                         || j4                  |
<   |S )z+Place a sell order (executed at bid price).r   r   Nr   r   )r   r0   r   r   r   r   r   r   r   r   r   r]   r.   r   r"   r   r   r$   r*   r   rX   rM   r   r5   r6   rS   rY   r   s                r   rc   z$BacktestOrderEngine.place_sell_order  s    "$4++ !3}T-?-?MMO)/4;;G "Q; //oF
+
"&&(;; ''!?G_Xt{{;T?G_Xt{{;T##((
 !&H  ;;'++^^^^((
 	D--.#+x r   r/   r:   c                    || j                   vry| j                   |   }|j                         sy|6|j                  t        j                  k(  r| j
                  }n| j                  }t        || j                        }|j                  t        j                  k(  r|j                  ||j                  z
  z  }n|j                  |j                  |z
  z  }| j                  |j                  |      }| xj                  |z  c_        ||z  }t        j                  |_        | j                   |_        ||_        ||_        | xj(                  |z  c_        || j*                  v r| j*                  |= | j,                  j/                  |       |S )zClose an open order.N)rX   rD   r1   r   r!   r   r   r   r0   r3   r4   r   r   r$   r+   r7   r   r9   r:   r<   r   rY   r   append)rC   r/   r:   r   r<   r   s         r   re   zBacktestOrderEngine.close_order  sO    4;;&H%}} zzY]]*"//"//%k4;;? ::&ZZ;#<=FZZ5;;#<=F //

KH
+* #))--' 	 t~~%x( 	!!%(r   rN   c                 &    | j                  ||      S )zClose an open position.)re   rh   s      r   ri   z"BacktestOrderEngine.close_position  s     [99r   c                 t    t        d | j                  j                         D              }| j                  |z   S )z.Get current equity (balance + unrealized P&L).c              3   4   K   | ]  }|j                     y wr   )rQ   .0r{   s     r   	<genexpr>z1BacktestOrderEngine.get_equity.<locals>.<genexpr>)  s     Ka))K   )sumrY   rq   r   )rC   
unrealizeds     r   r   zBacktestOrderEngine.get_equity'  s.    K4>>3H3H3JKK
||j((r   c                 V    t        d | j                  j                         D              S )z?Get margin used by open positions (simplified: position value).c              3   N   K   | ]  }|j                   |j                  z    y wr   )r3   rP   r   s     r   r   z6BacktestOrderEngine.get_margin_used.<locals>.<genexpr>.  s     M166AOO+Ms   #%)r   rY   rq   rB   s    r   get_margin_usedz#BacktestOrderEngine.get_margin_used,  s     MT^^5J5J5LMMMr   
high_price	low_pricec                    g }t        | j                  j                               D ]V  }| j                  |   }|j                  d}|j                  t
        j                  k(  r||j                  k\  rd}n.|j                  t
        j                  k(  r||j                  k  rd}|r3| j                  ||j                        }||j                  ||df       |j                  d}|j                  t
        j                  k(  r||j                  k  rd}n.|j                  t
        j                  k(  r||j                  k\  rd}|s#| j                  ||j                        }|C|j                  ||df       Y |S )z
        Process TP/SL hits within a price range (candle).

        Args:
            high_price: High price of the period
            low_price: Low price of the period

        Returns:
            List of (order_id, profit, close_type) tuples
        FTTPSL)ru   rY   keysr5   r1   r   r!   r"   ri   r   r6   )	rC   r   r   r'   rN   r}   tp_hitr<   sl_hits	            r   process_tp_slz!BacktestOrderEngine.process_tp_sl0  sZ     3 3 56 	CK~~k2H   ,==IMM1jHDUDU6U!F]]inn4hFWFW9W!F!00h>O>OPF){FD&AB    ,==IMM1i8CTCT6T!F]]inn4xGXGX9X!F!00h>O>OPF){FD&AB9	C< r   c                    | j                   s#ddddd| j                  | j                   dddddS | j                   D cg c]  }|j                  dkD  s| }}| j                   D cg c]  }|j                  dk  s| }}t        d | j                   D              }|rt        d |D              nd}|rt        d |D              nd}t	        | j                         t	        |      t	        |      | j                   r$t	        |      t	        | j                         z  dz  nd|| j                  |t        d |D        d	      t        d
 |D        d	      |r|t	        |      z  nd|r|t	        |      z  dS ddS c c}w c c}w )zGet trading statistics.r   r;   )total_tradeswinning_tradeslosing_tradeswin_ratetotal_profitr   
net_profitlargest_winlargest_lossaverage_winaverage_lossc              3   4   K   | ]  }|j                     y wr   r<   r   ts     r   r   z5BacktestOrderEngine.get_statistics.<locals>.<genexpr>q  s     @188@r   c              3   4   K   | ]  }|j                     y wr   r   r   s     r   r   z5BacktestOrderEngine.get_statistics.<locals>.<genexpr>r  s     3a3r   c              3   4   K   | ]  }|j                     y wr   r   r   s     r   r   z5BacktestOrderEngine.get_statistics.<locals>.<genexpr>s  s     41884r   r   c              3   4   K   | ]  }|j                     y wr   r   r   s     r   r   z5BacktestOrderEngine.get_statistics.<locals>.<genexpr>}  s     :Q:r   )defaultc              3   4   K   | ]  }|j                     y wr   r   r   s     r   r   z5BacktestOrderEngine.get_statistics.<locals>.<genexpr>~  s      :a :r   )r   r   r<   r   lenmaxmin)rC   r   winnerslosersr   
total_winstotal_lossess          r   get_statisticsz"BacktestOrderEngine.get_statistics]  s   !! !"#!" #$($9$9#444" #" #  #00AAHHqL1AA!//@188a<!@@@T-?-?@@7>S3733A
8>s4V44A   2 23!'l [HLHZHZGs4+=+='>>D`a( $ 5 5&:':AF :6 :AF8?:G4Q:@L3v;6
 	
 GH
 	
 B@s   E=E='F<F)g     @g?r;   r   r   )r   r   r   r   rI   rJ   rZ   r   r   ro   r   rk   r   r	   rG   r.   r`   rc   re   ri   r   r   r   r   dictr   __classcell__)r   s   @r   r   r   .  s    ")$'"$$ $ "	$
 $:"X "$ "% %U %t %65 6@% @ @% @ %)$(@@ 5/@ 5/	@
 @ @ 
%@J %)$(@@ 5/@ 5/	@
 @ @ 
%@J (,11 e_1 
%	1l (,:: e_: 
%	:)E )
N N+ +% +DK +Z$
 $
r   r   N)r   abcr   r   dataclassesr   r   r   typingr   r	   r
   enumr   r   r   r   r   r   r$   r.   rM   rU   r   r   r   r   <module>r      s    $ (  ' '  =  $  1 1 16 # # #0P6# P6fS
+ S
r   