Переглянути джерело

add classes to handle execDetails

laxaurus 7 роки тому
батько
коміт
b9213aa381

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

@@ -170,13 +170,14 @@ class AbstractGatewayListener(BaseMessageListener):
         """ generated source for method contractDetailsEnd """
         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 """
         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):
         """ 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):
         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):
-        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):
         logging.warn('TWS_event_handler: connectionClosed ******')

+ 48 - 0
src/finopt/instrument.py

@@ -204,4 +204,52 @@ class Option(Symbol):
             logging.error( 'Exception Option.object2kv')
                
         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) {
 		 	//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() {
       var input = document.getElementById("input");
       // 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
                 gamma_percent = 0
+		potential_gain = 0
 
                 # (S - X) * pos * multiplier
                 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())       
     
     
+
+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.ExecutionFilter import ExecutionFilter
 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.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.table_model import AbstractTableModel, AbstractPortfolioTableModelListener
 from comms.ibc.tws_client_lib import TWS_client_manager, AbstractGatewayListener
@@ -53,7 +53,10 @@ class PortfolioMonitor(AbstractGatewayListener, AbstractPortfolioTableModelListe
         self.portfolio_charts = {}
     
 
-            
+        '''
+            store executions: {<account>: <PortfolioTrades>}
+        '''
+        self.trades = {}
         
     
     def start_engine(self):
@@ -414,12 +417,28 @@ class PortfolioMonitor(AbstractGatewayListener, AbstractPortfolioTableModelListe
             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):
 
@@ -566,7 +585,7 @@ if __name__ == '__main__':
       'session_timeout_ms': 10000,
       'clear_offsets':  False,
       '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': ['*'],
       
       

+ 0 - 13
src/ws/ws_webserver.py

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