Browse Source

add classes to handle execDetails

laxaurus 7 years ago
parent
commit
b9213aa381

+ 5 - 4
src/comms/ibc/base_client_messaging.py

@@ -170,13 +170,14 @@ class AbstractGatewayListener(BaseMessageListener):
         """ generated source for method contractDetailsEnd """
         """ generated source for method contractDetailsEnd """
         raise NotImplementedException
         raise NotImplementedException
    
    
-    def execDetails(self, event, req_id, contract_key, execution, end_batch): 
+    def execDetails(self, event, req_id, contract_key, order_id, side, price, avg_price, cum_qty, exec_id, account, exchange, order_ref, exec_time, end_batch): 
         """ generated source for method execDetails """
         """ generated source for method execDetails """
         raise NotImplementedException
         raise NotImplementedException
+    
    
    
-    def execDetailsEnd(self, event, req_id, end_batch):  # reqId):
-        """ generated source for method execDetailsEnd """
-        raise NotImplementedException
+#     def execDetailsEnd(self, event, req_id, end_batch):  # reqId):
+#         """ generated source for method execDetailsEnd """
+#         raise NotImplementedException
    
    
     def updateMktDepth(self, event, message_value):  # tickerId, position, operation, side, price, size):
     def updateMktDepth(self, event, message_value):  # tickerId, position, operation, side, price, size):
         """ generated source for method updateMktDepth """
         """ generated source for method updateMktDepth """

+ 33 - 4
src/comms/ibgw/tws_event_handler.py

@@ -162,12 +162,41 @@ class TWS_event_handler(EWrapper):
 
 
     def execDetails(self, reqId, contract, execution):
     def execDetails(self, reqId, contract, execution):
         contract_key= ContractHelper.makeRedisKeyEx(contract)
         contract_key= ContractHelper.makeRedisKeyEx(contract)
-        self.broadcast_event('execDetails', {'req_id': reqId, 'contract_key': contract_key, 
-                                             'execution': json.dumps(execution), 'end_batch': False})
-        logging.info('TWS_event_handler:execDetails. [%s] execution id [%d]:= exec px %f' % (execution.account, execution.ExecId , execution.Price))
+        self.broadcast_event('execDetails', {'req_id': reqId,
+                                             'contract_key': contract_key, 
+                                             'order_id': execution.m_orderId,
+                                             'side': execution.m_side,
+                                             'price': execution.m_price,
+                                             'avg_price': execution.m_avgPrice,
+                                             'cum_qty': execution.m_cumQty,
+                                             'exec_id': execution.m_execId,
+                                             'account': execution.m_acctNumber,
+                                             'exchange': execution.m_exchange,
+                                             'order_ref':execution.m_orderRef,
+                                             'exec_time': execution.m_time,
+                                             'end_batch': False})
+        
+        logging.info('TWS_event_handler:execDetails. [%s] execution id [%s]:= exec px %f' % (execution.m_acctNumber, execution.m_execId , execution.m_price))
+
                                      
                                      
     def execDetailsEnd(self, reqId):
     def execDetailsEnd(self, reqId):
-        self.broadcast_event('execDetailsEnd', {'req_id': reqId, 'end_batch': True})
+        
+        self.broadcast_event('execDetails', {'req_id': None, 
+                                             'contract_key': None, 
+                                             'order_id': None,
+                                             'side': None,
+                                             'price': None,
+                                             'avg_price': None,
+                                             'cum_qty': None,
+                                             'exec_id': None,
+                                             'account': None,
+                                             'exchange': None,
+                                             'order_ref':None,
+                                             'exec_time': None, 
+                                             'end_batch': True})
+        
+                  
+
 
 
     def connectionClosed(self):
     def connectionClosed(self):
         logging.warn('TWS_event_handler: connectionClosed ******')
         logging.warn('TWS_event_handler: connectionClosed ******')

+ 48 - 0
src/finopt/instrument.py

@@ -204,4 +204,52 @@ class Option(Symbol):
             logging.error( 'Exception Option.object2kv')
             logging.error( 'Exception Option.object2kv')
                
                
         return None
         return None
+      
+      
+class ExecFill:
+    
+    SIDE_B = 'BOT'
+    SIDE_S = 'SLD'
+    
+    UNDLY_PX = 3001
+    EXEC_IV = 3002
+    
+    def __init__(self):
+        self.extra = {}
+
+              
+    def setValues(self, req_id, contract_key, order_id, side, price, avg_price, cum_qty, exec_id, account, exchange, exec_time, order_ref):
+        self.req_id = req_id
+        self.contract_key = contract_key
+        self.order_id = order_id
+        self.side = side
+        self.price = price
+        self.avg_price = avg_price
+        self.cum_qty = cum_qty
+        self.exec_id = exec_id
+        self.account = account
+        self.exchange = exchange
+        self.exec_time = exec_time
+        self.order_ref = order_ref
+
+    def set_extra_attributes(self, id, val):
+        self.extra[id] = val
+            
+    def get_extra_attributes(self):
+        return self.extra    
+    
+    def set_impl_vol(self, iv):
+        self.set_extra_attributes(ExecFill.EXEC_IV, iv)
+    
+    def set_undly_spot(self, px):
+        self.set_extra_attributes(ExecFill.UNDLY_PX, px)
         
         
+    def get_kv(self):
+        return self.__dict__
+    
+    def __str__(self):
+        return str(self.__dict__)
+
+    def __eq__(self, other): 
+        return self.__dict__ == other.__dict__
+    

+ 8 - 2
src/html/client_g.html

@@ -412,11 +412,17 @@ table.minimalistBlack tfoot td {
     	
     	
     	for(var port_id in val2cellDict) {
     	for(var port_id in val2cellDict) {
 		 	//console.log('in setPortSummaryTableVal ' + String(port_id) + ", ");
 		 	//console.log('in setPortSummaryTableVal ' + String(port_id) + ", ");
-    		setCellValue('port_sum', val2cellDict[port_id][0], val2cellDict[port_id][1], port_values[port_id]);
+			var num = Number(port_values[port_id]);	
+			num = (isFloat(num)) ? num.toFixed(2) : num;
+    		setCellValue('port_sum', val2cellDict[port_id][0], val2cellDict[port_id][1], num);
     	}
     	}
     }
     }
     
     
-    
+
+    function isFloat(n){
+       return Number(n) === n && n % 1 !== 0;
+    } 
+
     function onSubmit() {
     function onSubmit() {
       var input = document.getElementById("input");
       var input = document.getElementById("input");
       // You can send message to the Web Socket using ws.send.
       // You can send message to the Web Socket using ws.send.

+ 48 - 0
src/rethink/portfolio_item.py

@@ -191,6 +191,7 @@ class PortfolioItem():
                                 
                                 
                 pos_theta = 0
                 pos_theta = 0
                 gamma_percent = 0
                 gamma_percent = 0
+		potential_gain = 0
 
 
                 # (S - X) * pos * multiplier
                 # (S - X) * pos * multiplier
                 unreal_pl = (spot_px * multiplier - self.get_average_cost() ) * qty 
                 unreal_pl = (spot_px * multiplier - self.get_average_cost() ) * qty 
@@ -575,3 +576,50 @@ class Portfolio(AbstractTableModel):
         return '\n'.join('[%d]:%s' % (x[0], x[1]) for x in  self.port['g_table']['row_to_ckey_index'].items())       
         return '\n'.join('[%d]:%s' % (x[0], x[1]) for x in  self.port['g_table']['row_to_ckey_index'].items())       
     
     
     
     
+
+class PortfolioTrades:
+    
+    
+    def __init__(self, account):
+        self.trades = []
+        self.account = account
+        
+    
+    
+    def add_fills(self, trade):
+        if trade not in self.trades:
+            self.trades.append(trade)
+            
+    def get_trades(self):
+        return self.trades
+    
+    
+    def dump_trades(self):
+        
+
+        def format_port_header(x):
+                #imap = InstrumentIdMap()
+                return  map(lambda k:k, x.get_kv().keys())
+                    
+            
+        def format_port_data(x):
+                return map(lambda d:d, x.get_kv().values())
+        
+
+        try:
+
+            data = map(format_port_data, self.trades)
+            columns = format_port_header(self.trades[0])
+            pd.set_option('display.max_columns', 50)
+            df1 = pd.DataFrame(data = data, columns = columns)
+        
+            print '\n\n--------- Portfolio Trades %s --------\n'  % self.account 
+            print df1
+            
+        except:
+            logging.error('Portfolio. Exception while dumping trades...%s' % traceback.format_exc())        
+        
+        
+    
+    def average_exec_vols(self):
+        return 0

+ 27 - 8
src/rethink/portfolio_monitor.py

@@ -11,10 +11,10 @@ from dateutil.relativedelta import relativedelta
 from ib.ext.Execution import Execution
 from ib.ext.Execution import Execution
 from ib.ext.ExecutionFilter import ExecutionFilter
 from ib.ext.ExecutionFilter import ExecutionFilter
 from misc2.helpers import ContractHelper, LoggerNoBaseMessagingFilter, ExecutionFilterHelper
 from misc2.helpers import ContractHelper, LoggerNoBaseMessagingFilter, ExecutionFilterHelper
-from finopt.instrument import Symbol, Option, InstrumentIdMap
+from finopt.instrument import Symbol, Option, InstrumentIdMap, ExecFill
 from rethink.option_chain import OptionsChain
 from rethink.option_chain import OptionsChain
 from rethink.tick_datastore import TickDataStore
 from rethink.tick_datastore import TickDataStore
-from rethink.portfolio_item import PortfolioItem, PortfolioRules, Portfolio
+from rethink.portfolio_item import PortfolioItem, PortfolioRules, Portfolio, PortfolioTrades
 from rethink.portfolio_column_chart import PortfolioColumnChart,PortfolioColumnChartTM
 from rethink.portfolio_column_chart import PortfolioColumnChart,PortfolioColumnChartTM
 from rethink.table_model import AbstractTableModel, AbstractPortfolioTableModelListener
 from rethink.table_model import AbstractTableModel, AbstractPortfolioTableModelListener
 from comms.ibc.tws_client_lib import TWS_client_manager, AbstractGatewayListener
 from comms.ibc.tws_client_lib import TWS_client_manager, AbstractGatewayListener
@@ -53,7 +53,10 @@ class PortfolioMonitor(AbstractGatewayListener, AbstractPortfolioTableModelListe
         self.portfolio_charts = {}
         self.portfolio_charts = {}
     
     
 
 
-            
+        '''
+            store executions: {<account>: <PortfolioTrades>}
+        '''
+        self.trades = {}
         
         
     
     
     def start_engine(self):
     def start_engine(self):
@@ -414,12 +417,28 @@ class PortfolioMonitor(AbstractGatewayListener, AbstractPortfolioTableModelListe
             return
             return
 
 
             
             
-    def execDetails(self, event, req_id, contract_key, execution, end_batch):
-        logging.info("PortfolioMonitor:execDetails: [%s] received %s content:[%s]" % (event, contract_key, execution))
+    def execDetails(self, event, req_id, contract_key, order_id, side, price, avg_price, cum_qty, exec_id, account, exchange, order_ref, exec_time, end_batch):
         
         
-    def execDetailsEnd(self, event, req_id, end_batch):  # reqId):
-        logging.info("PortfolioMonitor:execDetailsEnd: [%s] received %d end:[%d]" % (event, req_id, end_batch))
+        if not end_batch:
+            logging.info("PortfolioMonitor:execDetails: [%s] received %s order_id:[%s] price:[%2f]" % (event, contract_key, order_id, price))
+            e = ExecFill()
+            
+            e.setValues(req_id, contract_key, order_id, side, price, avg_price, cum_qty, exec_id, account, exchange, order_ref, exec_time)
+            if account not in self.trades:
+                self.trades[account]= PortfolioTrades(account)
+            self.trades[account].add_fills(e)
+            
+        else:
+            logging.info("PortfolioMonitor:execDetails: End of execDetails")
+            
+            for acct in self.portfolios:
+                # there may not be any trades returned after midnight
+                if acct in self.trades:
+                    logging.info("\n".join('execDetails: %s' % t for t in self.trades[acct].get_trades()))
+                    self.trades[acct].dump_trades()
+                
         
         
+
  
  
     def position(self, event, account, contract_key, position, average_cost, end_batch):
     def position(self, event, account, contract_key, position, average_cost, end_batch):
 
 
@@ -566,7 +585,7 @@ if __name__ == '__main__':
       'session_timeout_ms': 10000,
       'session_timeout_ms': 10000,
       'clear_offsets':  False,
       'clear_offsets':  False,
       'logconfig': {'level': logging.INFO, 'filemode': 'w', 'filename': '/tmp/pm.log'},
       'logconfig': {'level': logging.INFO, 'filemode': 'w', 'filename': '/tmp/pm.log'},
-      'topics': ['position', 'positionEnd', 'tickPrice', 'execDetails', 'execDetailsEnd', 'update_portfolio_account', 'event_tm_request_table_structure', AbstractTableModel.EVENT_TM_TABLE_STRUCTURE_CHANGED],
+      'topics': ['position', 'positionEnd', 'tickPrice', 'execDetails', 'update_portfolio_account', 'event_tm_request_table_structure', AbstractTableModel.EVENT_TM_TABLE_STRUCTURE_CHANGED],
       'seek_to_end': ['*'],
       'seek_to_end': ['*'],
       
       
       
       

+ 0 - 13
src/ws/ws_webserver.py

@@ -1,21 +1,8 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 import sys, traceback
 import sys, traceback
 import logging
 import logging
-import os
-import ast
-import urllib, urllib2, cookielib
-import datetime, time
-import re
-import json
 import cherrypy
 import cherrypy
-import hashlib
-import uuid
-import json
-
 import ConfigParser
 import ConfigParser
-
-
-from sets import Set
 import thread
 import thread