B
     9-e                 @   sP  d Z ddlZddlZddlmZ ddlmZ ddlZ	ddl
mZmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ ddlmZmZmZm Z  ddl!m"Z"m#Z#m$Z$ ddl%m&Z& ddl'm(Z(m)Z) ddddddddddddddZ*dd  Z+d!d" Z,d#d$ Z-d%d& Z.d'd( Z/d)d* Z0d+d, Z1G d-d. d.eZ2dS )/a)  
There is a risk of loss when trading stocks, futures, forex, options and other
financial instruments. Please trade with capital you can afford to
lose. Past performance is not necessarily indicative of future results.
Nothing in this computer program/code is intended to be a recommendation, explicitly or implicitly, and/or
solicitation to buy or sell any stocks or futures or options or any securities/financial instruments.
All information and computer programs provided here is for education and
entertainment purpose only; accuracy and thoroughness cannot be guaranteed.
Readers/users are solely responsible for how to use these information and
are solely responsible any consequences of using these information.

If you have any questions, please send email to IBridgePy@gmail.com
All rights reserved.
    N)Decimal)exit)epoch_to_dtdt_to_epoch)IBCpp)-stripe_exchange_primaryExchange_from_contract)from_contract_to_security)BrokerClientBase)ReqAttr)CustomError)UpdateAccountValueRecordAccountSummaryRecord)TickPriceRecordTickSizeRecordTickStringRecordTickOptionComputationRecord)OrderStatusRecordOpenOrderRecordExecDetailsRecord)PositionRecord)print_IBCpp_contractprint_IBCpp_executionzbid sizez	bid pricez	ask pricezask sizez
last pricez	last sizez
daily highz	daily lowzdaily volumecloseopenzoption call open interestzoption put open interest)r                           	            c             C   s   t | tst| S | S )N)
isinstancedictvars)obj r*   G:\My Drive\STUDY\EPAT\09 TBP - Trading & Back-testing Platforms\TBP04 - Backtesting & Live Trading\IB IBridgePy API\02 Python 3.7 IBridgePy_Win_Anaconda37_64\broker_client_factory\CallBacks.pyfrom_object_to_dict*   s    
r,   c             C   sP   t | tr2| si S t| } t | tr:t| } nt| } t | tsLt| } | S )N)r&   strjsonloadsr,   r'   r(   )barr*   r*   r+   from_bar_to_dict0   s    



r1   c             C   sP   t | tr2| si S t| } t | tr:t| } nt| } t | tsLt| } | S )N)r&   r-   r.   r/   r,   r'   r(   )contractr*   r*   r+   from_contract_to_dict?   s    



r3   c             C   sP   t | tr2| si S t| } t | tr:t| } nt| } t | tsLt| } | S )N)r&   r-   r.   r/   r,   r'   r(   )
orderStater*   r*   r+   from_orderState_to_dictN   s    



r5   c             C   s   t | tr2| si S t| } t | tr:t| } nt| } t | tsLt| } d| krdt| d | d< x$dD ]}|| krjt| | | |< qjW | S )NZsoftDollarTier)ZfilledQuantitytotalQuantity)r&   r-   r.   r/   r,   r'   r(   )orderkeyr*   r*   r+   from_order_to_dict\   s    




r9   c             C   sZ   t | trt| } nt| } t | ts0t| } x$dD ]}|| kr6t| | | |< q6W | S )N)sharesZcumQty)r&   r-   r.   r/   r,   r'   r(   )	executionr8   r*   r*   r+   from_execution_to_dicto   s    


r<   c             C   s@   t | tr| S t | tr t| S tt dt|  d|   d S )Nz)::convert_decimal: Cannot handle type(x)=z x=)r&   r   r-   r   __name__type)xr*   r*   r+   convert_decimal|   s
    

r@   c               @   s  e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Z d=d> Z!d?d@ Z"dAdB Z#dCdD Z$dES )F	CallBacksc             C   s,   | j td|f   | jdtjj dS )z0
        Responses of reqAccountUpdates
        z$::accountDownloadEnd: accountCode=%sreqAccountUpdatesN)_logdebugr=   _activeRequests)set_all_requests_of_a_reqType_to_a_statusr
   Status	COMPLETED)selfaccountCoder*   r*   r+   accountDownloadEnd   s    zCallBacks.accountDownloadEndc          
   C   sZ   | j tdt|||t||f   t|ts8t|}| j| j|t	||||| dS )zU
        !!!!!!!! type(value) is STRING !!!!!!!!
        # Multiple accounts
        zE::accountSummary: reqId=%s accountCode=%s tag=%s value=%s currency=%sN)
rC   notsetr=   r-   r&   float_singleTraderset_accountSummary
brokerNamer   )rI   reqIdrJ   tagvaluecurrencyr*   r*   r+   accountSummary   s    

zCallBacks.accountSummaryc             C   s.   | j td t|  | j|tjj d S )Nz::accountSummaryEnd: )	rC   rD   r=   r-   rE   $set_a_request_of_a_reqId_to_a_statusr
   rG   rH   )rI   rQ   r*   r*   r+   accountSummaryEnd   s    zCallBacks.accountSummaryEndc          	   C   sx   | j td t|  | j|}tj|jj	t
|jj|jjt|j|j|jj|dt|jgd}|j||_dS )zC
        IB callback function to receive str_security info
        z::bondContractDetails:)rightstrikeexpirycontractNamestr_security
multipliercontractDetails)indexN)rC   infor=   r-   rE   get_by_reqId_otherwise_exitpd	DataFramer2   rX   rM   rY   rZ   r   r]   lenreturnedResultappend)rI   rQ   r^   aRequestnewRowr*   r*   r+   bondContractDetails   s    

zCallBacks.bondContractDetailsc             C   s   | j td t|  d S )Nz::commissionReport: DO NOTHING)rC   rL   r=   r-   )rI   commissionReportr*   r*   r+   rj      s    zCallBacks.commissionReportc          
   C   s   | j td||f   | j|}tj|jjt	|jj
|jj|jt|j|j|jj|dt|jgd}t|j|g|_dS )zC
        IB callback function to receive str_security info
        z.::contractDetails: reqId=%s contractDetails=%s)rX   rY   rZ   r[   securityr2   r]   r^   )r_   N)rC   rL   r=   rE   ra   rb   rc   r2   rX   rM   rY   lastTradeDateOrContractMonthr   r]   rd   re   concat)rI   rQ   r^   rg   rh   r*   r*   r+   r^      s    

zCallBacks.contractDetailsc             C   s.   | j td t|  | j|tjj dS )zV
        IB callback function to receive the ending flag of str_security info
        z::contractDetailsEnd:N)	rC   rD   r=   r-   rE   rV   r
   rG   rH   )rI   rQ   r*   r*   r+   contractDetailsEnd   s    zCallBacks.contractDetailsEndc             C   sJ   t t|}| jtd|t| f   | j| | j	dt
jj dS )z
        IB C++ API call back function. Return system time in datetime instance
        constructed from Unix timestamp using the showTimeZone from MarketManager
        z&::currentTime: tm=%s brokerClientId=%sreqCurrentTimeN)r   rM   rC   rD   r=   id_timeGeneratorset_diffBetweenLocalAndServerrE   rF   r
   rG   rH   )rI   tmZ
serverTimer*   r*   r+   currentTime   s    zCallBacks.currentTimec             C   sn  | j t d| d| d| d| 	 | jrR|| jkrR| j d|||f  dS |dkr^dS |dkr| j d	 | j d
 t|d||f |dkr| j td|||f   | j d | j d t|d||f n|dkr|dkrd| _n|dkrjd| _n\|dkr|dkr*d| _n|dkr<d| _n|dkrNd| _	n|dkr`d| _	np|dkr~d| _d| _	d| _nR|dkr| j td|||f   | j d n |dkrj| j
dtjj dS n|dkr| j
|tjj nv|d kr*| j td| d| d| d|   n@|d!kr`| j td| d| d| d|   n
|d"krd#|kr| j
|tjj dS | j
|r| j td| d| d| d|   |   t|d||f ndS nd$|  krd%krRn nP|d&krdS | j td'|||f   |d(kr4| jdksL| j	dkr`| j td)  dS || j kr|}d*| j| jkr| j t| j| jd*  n| j t| j| jd+  nL| j
t|}|r| j t| j| jd*  n| j td,  |   | j
|r0t|d||f ndS |   t|d||f nd-|  krjd.ksn d/|  krd0krn nF| j td| d| d| d|   | j d |   |   nd1|  krd2kr(n n>| j td| d| d| d|   | j d3 |   nB| j td| d| d| d|   |   t|d||f dS )4z
        errorId can be either reqId or orderId or -1
        only print real error messages, which is errorId < 2000 in IB's error
        message system, or program is in debug mode
        z::error: errorId=z errorCode=z errorMessage=z advancedOrderRejectJson=zzThe error is ignored by the user. settings.py --> PROJECT --> errorsIgnoredByUser. errorId=%s errorCode=%s errorMessage=%sN)i  iF  )i  z!Hint 1 for error=502: Enable API.z;Hint 2 for error=502: Maybe the port number does not match.zerrorId:%s errorMessage=%s)i  i'  z0::error: errorId=%s errorCode=%s errorMessage=%szEHint: Restart Trader Workstation(TWS) or IB Gateway and try it again.zCHint: Please refer to YouTube tutorial https://youtu.be/pson8T5ZaRw)iL  iM  iN  iL  F)iM  iN  T)i4  i7  i8  i9  i:  i;  i<  i>  iG  iY  im  in  )i7  im  )i8  i<  in  i9  )i:  i;  i>  iY  zerrorCode=2137 is not a critical error in IBridgePy anymore. To hide this error, TWS -> Global Configuration -> Messages -> Cross side warning (untick & save) -> Uncheck it.i4  rB   )   i'  i'  )   i  iA  id  i=  )i     z"API scanner subscription cancelledn   i     z/::error:errorId=%s errorCode=%s errorMessage=%s   z::error: <No security definition has been found for the request> might be a false statement because connectivity to IB server is lost.r2   rk   zW::error: please report this error to IBridgePy@gmail.com for further assistance. Thanksi  i  i  i  i  i  zIBridgePy community version supports backtest on US equities only. Please visit https://ibridgepy.com/features-of-ibridgepy/ and consider IBridgePy Backtester version.)rC   rD   r=   _errorsIgnoredByUserr`   errorr   Z_connectionGatewayToServerZ_connectionMarketDataFarmZ_connectionHistDataFarmrE   rF   r
   rG   rH   'set_a_request_of_an_orderId_to_a_statusrV   	has_reqId_print_version_allRequestskeysparamr   r-   find_reqId_by_int_orderIdint_print_version_and_exite_disconnect)rI   ZerrorId	errorCodeZerrorMessageZadvancedOrderRejectJsonrQ   r*   r*   r+   r|      s    "













&
&

"



6"
"
"zCallBacks.errorc             C   s    | j tdt| jf   d S )Nz&::_print_version:IBridgePy version= %s)rC   r|   r=   r-   versionNumber)rI   r*   r*   r+   r     s    zCallBacks._print_versionc             C   s&   | j tdt| jf   t  d S )Nz4::_print_version_and_exit:EXIT IBridgePy version= %s)rC   r|   r=   r-   r   r   )rI   r*   r*   r+   r     s    z!CallBacks._print_version_and_exitc       	      C   s   t |}t|}| jtd|t|t|f   |d }| j|}|d }| j	
| j|t||| | j	| j|d}t|d t|d  }|d dkr||8 }n|d d	kr||7 }| d|d
| dS )z
        !!!!!! reqId is always -1 based on experiences
        :param reqId:
        :param contract:
        :param execution:
        :return:
        z0::execDetails: reqId=%s contract=%s execution=%sorderId
acctNumberTotalCashValuer:   pricesideZBOTZSLDUSDN)r3   r<   rC   rD   r=   r   r   _idConverterfromIBtoBrokerrN   set_execDetailsrP   r   get_account_inforM   updateAccountValue)	rI   rQ   r2   r;   int_orderIdibpyOrderIdrJ   ZcurrentCashValueZ
cashChanger*   r*   r+   execDetails  s     

zCallBacks.execDetailsc             C   s  t |}| jd| d|  t|tr>|r:t|}ni }|d }|d }|d }|d }|d }|d }| j|r| j	|}	nd	S t
jj|	_ytj|d
}
t|
}W n  tk
r   tt|}Y nX tj|||||d|gd}t|	j|g|	_d	S )zn
        call back function from IB C++ API
        return the historical data for requested security
        z __name__::historicalData: reqId=z bar=dater   highlowr   volumeNz%Y%m%d)r   r   r   r   r   )r_   )r1   rC   rL   r&   r-   r.   r/   rE   is_reqId_within_activeRequestsra   r
   rG   STARTEDstatusdtdatetimestrptimer   
ValueErrorr   rM   rb   rc   rm   re   )rI   rQ   r0   Z
timeString
price_open
price_high	price_lowprice_closer   rg   dateTimeidxrh   r*   r*   r+   historicalData  s2    

zCallBacks.historicalDatac             C   s,   | j |r| j |}nd S tjj|_d S )N)rE   r   ra   r
   rG   rH   r   )rI   rQ   ZstartDateStrZ
endDateStrrg   r*   r*   r+   historicalDataEnd  s    zCallBacks.historicalDataEndc             C   s@   | j td t|  | j| | jr<| jdtj	j
 dS )a;  
        IB API requires an nextId for every order, and this function obtains
        the next valid nextId. This function is called at the initialization
        stage of the program and results are recorded in startingNextValidIdNumber,
        then the nextId is track by the program when placing orders
        z::nextValidId: Id = reqIdsN)rC   rD   r=   r-   Z_nextIdZsetUuidrE   rF   r
   rG   rH   )rI   ZnextIdr*   r*   r+   nextValidId  s    zCallBacks.nextValidIdc             C   s,   | j td  | jr(| jdtjj d S )Nz::heartBeatsEndreqHeartBeats)rC   rL   r=   rE   rF   r
   rG   rH   )rI   r*   r*   r+   heartBeatsEnd  s    zCallBacks.heartBeatsEndc             C   s   t |}t|}t|}| jt d| d| d| d| 	 |dkrXd|d f }n| j|}| j	| j
|d t|||| d	S )
zP
        call back function of IB C++ API which updates the open orders
        z::openOrder: ibOrderId=z
 contract=z order=z orderState=)zpermIDatIB%spermIdaccountN)r3   r9   r5   rC   rD   r=   r   r   rN   set_openOrderrP   r   )rI   Zint_ibOrderIdr2   r7   r4   str_ibpyOrderIdr*   r*   r+   	openOrder  s    "zCallBacks.openOrderc             C   s\   | j td  | jdtjj | jdtjj | jdtjj | jdtjj d S )Nz::openOrderEndreqOneOrderreqAllOpenOrdersZreqOpenOrdersZreqAutoOpenOrders)rC   rD   r=   rE   rF   r
   rG   rH   )rI   r*   r*   r+   openOrderEnd  s
    zCallBacks.openOrderEndc             C   s   t |}t |}| jtd|||||f   | j|}| jrN| j|}nd}|dk	r| j|}|j	dkr||_
tjj|_n | j| j|}| j| j|t|||||||||	|

 dS )z
        call back function of IB C++ API which update status or certain order
        Same order may be called back multiple times with status of 'Filled'
        orderStatus is always called back after openOrder
        zN::orderStatus: int_orderId=%s status=%s filled=%s remaining=%s aveFillPrice=%sN)
placeOrdermodifyOrder)r@   rC   rD   r=   r   r   rE   r   ra   reqTypere   r
   rG   rH   r   rN   get_accountCode_by_ibpyOrderIdrP   set_orderStatusr   )rI   r   r   filled	remainingavgFillPricer   parentIdlastFillPriceclientIdwhyHeldZmktCapPricer   rQ   rg   rJ   r*   r*   r+   orderStatus  s$    



zCallBacks.orderStatusc          	   C   sX   t |}t|}| jtd||||f   t|}| j| j|t	|
 ||| dS )zp
        call back function of IB C++ API which updates the position of a security
        of a account
        z>::position: accountCode=%s contract=%s amount=%s cost_basis=%sN)r@   r3   rC   rD   r=   r   rN   set_positionrP   r   
full_print)rI   rJ   r2   amount
cost_basisrk   r*   r*   r+   position>  s    
zCallBacks.positionc             C   s&   | j td  | jdtjj d S )Nz%::positionEnd: all positions recordedreqPositions)rC   rD   r=   rE   rF   r
   rG   rH   )rI   r*   r*   r+   positionEndQ  s    zCallBacks.positionEndc
             C   s   t |}t |}| jt d| d| d| d| d| d| d| d| d	|	  | j|r| j|}
|
jtj	j
krtj	j
|
_| j| jd
  }| j }| j|||||||||	|
 dS )zw
        call back function from IB C++ API
        return realTimeBars for requested security every 5 seconds
        z::realtimeBar: reqId=z aTime=z price_open=z price_high=z price_low=z price_close=z volume=z wap=z count=rk   N)r@   rC   rL   r=   rE   r   ra   r   r
   rG   rH   r   r   r   rq   get_current_time_dataFromServerset_5_second_real_time_bar)rI   rQ   aTimer   r   r   r   r   wapcountrg   r\   	timestampr*   r*   r+   realtimeBarU  s    @

zCallBacks.realtimeBarc             C   sl   | j td|||j||||f   | j|}t|j}	tj||	dt	|j
gd}
t|j
|
g|_
d S )Nzj::scannerData: reqId=%s rank=%s contractDetails.contract=%s distance=%s benchmark=%s project=%s legsStr=%s)rankrk   )r_   )rC   rD   r=   r2   rE   ra   r   rb   rc   rd   re   rm   )rI   rQ   r   r^   distance	benchmarkZ
projectionZlegsStrrg   rk   rh   r*   r*   r+   scannerDataj  s    
zCallBacks.scannerDatac             C   s.   | j td t|  | j|tjj d S )Nz::scannerDataEnd:)	rC   rD   r=   r-   rE   rV   r
   rG   rH   )rI   rQ   r*   r*   r+   scannerDataEndz  s    zCallBacks.scannerDataEndc             C   s(   | j td  | jdtjj| d S )Nz::scannerParameters:reqScannerParameters)rC   rD   r=   rE   8set_all_requests_of_a_reqType_to_a_status_and_set_resultr
   rG   rH   )rI   xmlr*   r*   r+   scannerParameters~  s    zCallBacks.scannerParametersc             C   s   | j td|||f   d S )Nz)::tickGeneric: reqId=%i field=%s value=%d)rC   rL   r=   )rI   rQ   fieldrS   r*   r*   r+   tickGeneric  s    zCallBacks.tickGenericc             C   s   | j t d| d| d| d| d| d| d| d| d	|	 d
|
 d|  | j| jd  }| jt|||||||||	|
| d S )Nz::tickOptionComputation: reqId=z
 tickType=z tickAttrib=z impliedVol=z delta=z
 optPrice=z pvDividend=z gamma=z vega=z theta=z
 undPrice=rk   )	rC   rD   r=   r   r   r   r   set_tickInfoRecordr   )rI   rQ   tickType
tickAttrib
impliedVoldeltaoptPrice
pvDividendgammavegathetaundPricer\   r*   r*   r+   tickOptionComputation  s    LzCallBacks.tickOptionComputationc             C   s   | j td|||f   | j|r| j|}|jtjj	kr|dkrd|j
d tjjkrdtjj	|_|dkr|j
d tjjkrtjj	|_|dkr|j
d tjjkrtjj	|_| j| j
d  }| j }| jt||||| dS )zV
        call back function of IB C++ API. This function will get tick prices
        z)::tickPrice:reqId=%s tickType=%s price=%sr   tickTypeClientAskedr   r   rk   N)rC   rL   r=   rE   r   ra   r   r
   rG   rH   r   r   TickTypeBIDASKLASTr   r   rq   r   r   r   r   )rI   rQ   r   r   canAutoExecuterg   r\   r   r*   r*   r+   	tickPrice  s    



zCallBacks.tickPricec             C   sR   t |}| jtd|t| |f   | j| jd  }| j	t
||| dS )zT
        call back function of IB C++ API. This function will get tick size
        z(::tickSize: reqId=%s tickType=%s size=%srk   N)r@   rC   rL   r=   	MSG_TABLEr   r   r   r   r   r   )rI   rQ   r   sizer\   r*   r*   r+   tickSize  s    zCallBacks.tickSizec             C   s   | j td t|  d S )Nz::tickSnapshotEnd: )rC   rL   r=   r-   )rI   rQ   r*   r*   r+   tickSnapshotEnd  s    zCallBacks.tickSnapshotEndc             C   sF   | j td|||f   | j| jd  }| jt||| dS )aC  
        IB C++ API call back function. The value variable contains the last
        trade price and volume information. User show define in this function
        how the last trade price and volume should be saved
        RT_volume: 0 = trade timestamp; 1 = price_last,
        2 = size_last; 3 = record_timestamp
        z(::tickString: reqId=%s field=%s value=%srk   N)	rC   rL   r=   r   r   r   r   r   r   )rI   rQ   r   rS   r\   r*   r*   r+   
tickString  s    zCallBacks.tickStringc             C   s   | j td t|  d S )Nz::updateAccountTime:)rC   rL   r=   r-   )rI   rs   r*   r*   r+   updateAccountTime  s    zCallBacks.updateAccountTimec          
   C   sf   | j td||||t| jf   yt|}W n tk
rD   Y nX | j| j|t	|||| dS )z
        IB callback function
        update account values such as cash, PNL, etc
        !!!!!!!! type(value) is STRING !!!!!!!!
        zQ::updateAccountValue: key=%s value=%s currency=%s accountCode=%s _singleTrader=%sN)
rC   rL   r=   rp   rN   rM   r   set_updateAccountValuerP   r   )rI   r8   rS   rT   rJ   r*   r*   r+   r     s    zCallBacks.updateAccountValuec	       	      C   sX   | j tdt|t|t|t|t|t|t|t|f   | |||| d S )Nz::updatePortfolio: contract=%s amount=%s marketPrice=%s marketValue=%s averageCost=%s unrealizedPNL=%s realizedPNL=%s accountCode=%s)rC   rL   r=   r-   r   )	rI   r2   r   ZmarketPriceZmarketValueZaverageCostZunrealizedPNLZrealizedPNLrJ   r*   r*   r+   updatePortfolio  s
    $zCallBacks.updatePortfolioN)%r=   
__module____qualname__rK   rU   rW   ri   rj   r^   rn   rt   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+   rA      sF   
 2!6	%
rA   )3__doc__r   r   r.   decimalr   sysr   pandasrb   BasicPyLib.BasicToolsr   r   	IBridgePyr   IBridgePy.IbridgepyToolsr   IBridgePy.quantopianr   Z"broker_client_factory.BrokerClientr	   &broker_client_factory.BrokerClientDefsr
   "broker_client_factory.CustomErrorsr   models.AccountInfor   r   models.Datar   r   r   r   models.Orderr   r   r   models.Positionr   models.utilsr   r   r   r,   r1   r3   r5   r9   r<   r@   rA   r*   r*   r*   r+   <module>   s8   
