ソースを参照

loads of changes since a long time ago

larry 10 年 前
コミット
f1e1698b0a

+ 2 - 2
cep/greeks_changes.py

@@ -138,9 +138,9 @@ if __name__ == "__main__":
     lns = kvs.map(lambda x: x[1])
     
 #{"analytics":{"imvol" : 0.210757782404, "vega" : 3321.50906944, "delta" : 0.402751602804, "theta" : -5.58857173887, "npv" : 499.993413708, "gamma" : 0.00021240629952}, "contract":{"m_conId": 0, "m_right": "C", "m_symbol": "HSI", "m_secType": "OPT", "m_includeExpired": false, "m_multiplier": 50, "m_expiry": "20160128", "m_currency": "HKD", "m_exchange": "HKFE", "m_strike": 22600.0}, "tick_values":{"0" : 20, "1" : 500.0, "2" : 510.0, "3" : 25, "4" : 500.0, "5" : 1, "8" : 22, "9" : 628.0}, "extra":{"spot" : 22190.0, "rate" : 0.0012, "last_updated" : "20151204143050", "div" : 0.0328}}    
-
+  #QQQ-DEC11, HSI-DEC30
     mdp = lns.map(lambda x: json.loads(x))\
-            .filter(lambda x: (x['extra']['chain_id'] == 'HSI-DEC30'))\
+            .filter(lambda x: (x['extra']['chain_id'] == 'QQQ-DEC11'))\
             .map(lambda x: (x['contract']['m_strike'], (x['analytics']['imvol'], x['analytics']['theta'])  ))\
             .groupByKeyAndWindow(6, 4, 1)
             #.groupByKeyAndWindow(12, 10, 1)

+ 20 - 6
comms/tws_gateway.py

@@ -94,7 +94,7 @@ class TWS_event_handler(EWrapper):
             # no catch if fails again
             if message == 'gw_subscriptions':   
                 sleep(2)
-                logging.info('TWS_event_handler: Retry once broadcasting gw_subscription ' % (dict['typeName'], dict))
+                logging.info('TWS_event_handler: Retry once broadcasting gw_subscription %s [%s]' % (dict['typeName'], dict))
                 self.producer.send_messages(message, json.dumps(dict))    
             
             
@@ -357,7 +357,21 @@ class TWS_gateway(threading.Thread):
         key = self.config.get("tws_gateway",  "subscription_manager.subscriptions.redis_key").strip('"').strip("'")
         if self.rs.get(key):
             #contracts = map(lambda x: ContractHelper.kvstring2contract(x), json.loads(self.rs.get(key)))
-            contracts = map(lambda x: ContractHelper.kvstring2object(x, Contract), json.loads(self.rs.get(key)))
+            
+            def is_outstanding(c):
+                
+                today = time.strftime('%Y%m%d') 
+                if c.m_expiry < today:
+                    logging.info('initialize_subscription_mgr: ignoring expired contract %s%s%s' % (c.m_expiry, c.m_strike, c.m_right))
+                    return False
+                return True
+            
+            contracts = filter(lambda x: is_outstanding(x), 
+                               map(lambda x: ContractHelper.kvstring2object(x, Contract), json.loads(self.rs.get(key))))
+            
+            
+            
+            
             self.contract_subscription_mgr.load_subscription(contracts)
         
 
@@ -642,9 +656,9 @@ class SubscriptionManager():
             self.parent.connection.reqMktData(id, contract, '', False) 
             
                    
-#             if self.persist_f:
-#                 logging.debug('SubscriptionManager reqMktData: trigger callback')
-#                 self.persist_f(self.handle)
+            if self.persist_f:
+                logging.debug('SubscriptionManager reqMktData: trigger callback')
+                self.persist_f(self.handle)
                 
             logging.info('SubscriptionManager: reqMktData. Requesting market data, id = %d, contract = %s' % (id, ContractHelper.makeRedisKeyEx(contract)))
         
@@ -686,7 +700,7 @@ class SubscriptionManager():
                                      if self.handle[i] <> None else ''          ) for i in range(len(self.handle)))\
                      )
         
-        logging.info( ''.join('%s[%d],\n' % (k, v) for k, v in self.conId.iteritems()))
+        #logging.info( ''.join('%s[%d],\n' % (k, v) for k, v in self.conId.iteritems()))
         logging.info( 'Number of instruments subscribed: %d' % len(self.handle))
         logging.info( '------------------------------------------------')
         

+ 1 - 1
comms/tws_protocol_helper.py

@@ -21,7 +21,7 @@ class TWS_Protocol:
     gatewayEvents = ('gw_subscriptions',)
     
     oceMethods = ()
-    oceEvents = ('optionAnalytics',)
+    oceEvents = ('optionAnalytics','optionsSnapshot')
     
     
     

BIN
comms/tws_protocol_helper.pyc


+ 5 - 1
finopt/optcal.py

@@ -52,7 +52,11 @@ def cal_option(spot, strike, callput, evaldate, exdate, rate, div, vol):
     
     results['theta'] = option.theta() / 365
     results['vega'] = option.vega() 
+#    results['rho'] = option.rho() 
 
+    results['strikeSensitivity'] = option.strikeSensitivity()
+   # results['thetaPerDay'] = option.thetaPerDay()
+   # results['itmCashProbability'] = option.itmCashProbability()
  
 
     return results
@@ -152,4 +156,4 @@ if __name__ == '__main__':
     print chk.isEndOfMonth(Date(30, October, 2015))
     print chk.advance(Date(17, October, 2015), 1, 0)
     print chk.advance(Date(17, October, 2015), 1, 1)
-    print chk.advance(Date(17, October, 2015), 1, 2)
+    print chk.advance(Date(17, October, 2015), 1, 2)

BIN
finopt/optcal.pyc


+ 6 - 2
finopt/options_analytics.py

@@ -21,6 +21,10 @@ import uuid
 from comms.tws_protocol_helper import TWS_Protocol
 
 class AnalyticsListener(threading.Thread):
+    """ This class is used to receive kafka
+        events broadcasted by OptionCalculationEngine 
+
+    """    
     consumer = None
     command_handler = None
     stop_consumer = False
@@ -83,7 +87,7 @@ class AnalyticsListener(threading.Thread):
                         message = self.consumer.next()
                         
                         
-                        logging.debug("TWS_client_base_app: %s:%d:%d: key=%s value=%s" % (message.topic, message.partition,
+                        logging.debug("AnalyticsListener: %s:%d:%d: key=%s value=%s" % (message.topic, message.partition,
                                                      message.offset, message.key,
                                                      message.value))
                         
@@ -95,7 +99,7 @@ class AnalyticsListener(threading.Thread):
 
                                         
     def stop(self):
-        logging.info('TWS_client_base_app: --------------- stopping consumer')
+        logging.info('AnalyticsListener: --------------- stopping consumer')
         self.stop_consumer = True
         
 

BIN
finopt/options_analytics.pyc


+ 59 - 16
finopt/options_chain.py

@@ -285,11 +285,50 @@ class OptionsChain():
         print footer
         
         
+    def generate_google_datatable_json(self):
+        
+        sorted_opt = sorted(map(lambda i: (self.options[i].get_contract().m_strike, self.options[i]) , range(len(self.options))))
+        
+        sorted_call = filter(lambda x: x[1].get_contract().m_right == 'C', sorted_opt)
+        sorted_put = filter(lambda x: x[1].get_contract().m_right == 'P', sorted_opt)
+        
 
-                
         
+        dtj = {'cols':[], 'rows':[]}
+        header = [('last', 'number'), ('bidq', 'number'), ('bid', 'number'), 
+                  ('ask', 'number'), ('askq', 'number'), ('ivol', 'number'), 
+                  ('delta', 'number'), ('theta', 'number'), ('strike', 'number'), 
+                  ('last', 'number'), ('bidq', 'number'), ('bid', 'number'), 
+                  ('ask', 'number'), ('askq', 'number'), ('ivol', 'number'), 
+                  ('delta', 'number'), ('theta', 'number')
+                  ]  
+        # header fields      
+        map(lambda hf: dtj['cols'].append({'id': hf[0], 'label': hf[0], 'type': hf[1]}), header)
+        
+        
+        # table rows
+        # arrange each row with C on the left, strike in the middle, and P on the right
+        def row_fields(x):
+            
+            rf = [{'v': x[1].get_tick_value(4)}, 
+                 {'v': x[1].get_tick_value(0)},
+                 {'v': x[1].get_tick_value(1)},
+                 {'v': x[1].get_tick_value(2)},
+                 {'v': x[1].get_tick_value(3)},
+                 {'v': x[1].get_analytics()[Option.IMPL_VOL]},
+                 {'v': x[1].get_analytics()[Option.DELTA]},
+                 {'v': x[1].get_analytics()[Option.THETA]}]                 
+                 
+             
+            return rf 
+        
+        map(lambda i: dtj['rows'].append({'c': row_fields(sorted_call[i]) +
+                                                [{'v': sorted_call[i][0]}] + 
+                                                row_fields(sorted_put[i])}), range(len(sorted_call)))
     
-
+        
+        print json.dumps(dtj) #, indent=4)
+        
 class OptionsCalculationEngine(SimpleTWSClient):
     tickerMap = {}
     option_chains = {}    
@@ -402,7 +441,9 @@ class OptionsCalculationEngine(SimpleTWSClient):
         while 1:
             sleep(5)
             for oc in self.option_chains.keys():
-                self.option_chains[oc].pretty_print()
+                #self.option_chains[oc].pretty_print()
+                
+                self.option_chains[oc].generate_google_datatable_json()
             
         self.disconnect()
         
@@ -583,7 +624,8 @@ class OptionsCalculationEngine(SimpleTWSClient):
         
         self.get_producer().send_messages('optionAnalytics', msg_str)
     
-    
+    #def broadcast_chain_snapshots(self):
+        
 
         
     
@@ -607,27 +649,28 @@ if __name__ == '__main__':
     
     contractTuple = ('QQQ', 'STK', 'SMART', 'USD', '', 0, '')
     contract = ContractHelper.makeContract(contractTuple)  
-    oc = OptionsChain('QQQ-DEC11')
-    oc.set_option_structure(contract, 0.5, 100, 0.005, 0.003, '20151211')
-    oc.build_chain(114.79, 0.05, 0.25)
+    oc = OptionsChain('QQQ-MAR24')
+    oc.set_option_structure(contract, 2.5, 100, 0.005, 0.003, '20160324')
+    oc.build_chain(98.0, 0.025, 0.25)
     for c in oc.get_option_chain():
         print '%s' % ContractHelper.makeRedisKeyEx(c.get_contract())
     
 
-    contractTuple = ('HSI', 'FUT', 'HKFE', 'HKD', '20151230', 0, '')
+    near_expiry = '20160226'
+    contractTuple = ('HSI', 'FUT', 'HKFE', 'HKD', near_expiry, 0, '')
     contract = ContractHelper.makeContract(contractTuple)  
-    oc1 = OptionsChain('HSI-DEC30')
-    oc1.set_option_structure(contract, 200, 50, 0.0012, 0.0328, '20151230')
-    oc1.build_chain(22508, 0.08, 0.219)
+    oc1 = OptionsChain('HSI-%s' % near_expiry)
+    oc1.set_option_structure(contract, 200, 50, 0.0012, 0.0328, near_expiry)
+    oc1.build_chain(19200, 0.08, 0.219)
     for c in oc1.get_option_chain():
         print '%s' % ContractHelper.makeRedisKeyEx(c.get_contract())
 
-
-    contractTuple = ('HSI', 'FUT', 'HKFE', 'HKD', '20160128', 0, '')
+    far_expiry = '20160330'
+    contractTuple = ('HSI', 'FUT', 'HKFE', 'HKD', far_expiry, 0, '')
     contract = ContractHelper.makeContract(contractTuple)  
-    oc2 = OptionsChain('HSI-JAN28')
-    oc2.set_option_structure(contract, 200, 50, 0.0012, 0.0328, '20160128')
-    oc2.build_chain(22508, 0.08, 0.22)
+    oc2 = OptionsChain('HSI-%s' % far_expiry)
+    oc2.set_option_structure(contract, 200, 50, 0.0012, 0.0328, far_expiry)
+    oc2.build_chain(19200, 0.08, 0.22)
     for c in oc2.get_option_chain():
         print '%s' % ContractHelper.makeRedisKeyEx(c.get_contract())
 

BIN
finopt/options_chain.pyc


+ 69 - 10
finopt/portfolio.py

@@ -208,6 +208,46 @@ class PortfolioManager():
         # pass the list to sumByKey routine
         self.grouped_options = sumByKey(lambda x:(x[0], 0), n)
         #print len(l), sorted(l)
+
+
+    def group_pos_by_strike_by_month(self):
+
+
+        # split into lines of position       
+        m = map(lambda x: x.split(','), self.port)
+        # transform each line into two elements. first one is a key created 
+        # by combining right and strike, the second is the product of 
+        # position * conversion ratio (HSI=50, MSI=10)
+        
+        mth_set = set(map(lambda x: x[2], m))
+        print max(mth_set)
+        n = map(lambda x: (x[3] + x[4] + x[2], float(x[5]) * float(x[6])/50), m)
+        
+        #p = dict(set(map(lambda x:(x[0], 0), n)))
+        
+        def sumByKey(f, n):
+            # filter the list with only unique keys
+            # transform the list into a dict
+            p = dict(set(map(f, n)))
+            
+            # add the numbers together on key
+            l =[]
+            for x in n:
+                
+                p[x[0]] += x[1]
+                
+            return [(k[1:6], 'NEAR' if k[6:] < max(mth_set) else 'FAR', k[0:1],v) for k,v in p.iteritems()]
+         
+         
+           
+        #print len(n),n
+        # initialize a list of strikes and the position sum to 0
+        # pass the list to sumByKey routine
+        self.grouped_options = sumByKey(lambda x:(x[0],  0), n)
+        #print len(l), sorted(l)
+
+
+
         
     def group_pos_by_right(self):        
     # group by put, call (summing up all contracts by right type,ignoring strikes)
@@ -225,7 +265,18 @@ class PortfolioManager():
         for e in sorted(self.grouped_options):
             s += "[%f,%s,%s]," % (float(e[0])/100.0, e[2] if e[1] == 'P' else 0, e[2] if e[1] == 'C' else 0)
         return s
-    
+ 
+ 
+    def get_grouped_options_str_array_stacked(self):
+        s = ''
+        
+        #[('20800', 'FAR', 'C', -1.0), ('17600', 'NEAR', 'P', -2.0), ('21400', 'NEAR', 'C', -4.0), ('15800', 'NEAR', 'P', -4.0), ('15600', 'FAR', 'P', -3.0), ('14600', 'FAR', 'P', -1.0), ('20400', 'NEAR', 'C', -2.0), ('15600', 'NEAR', 'P', -2.0), ('18200', 'NEAR', 'P', 0.0), ('16000', 'NEAR', 'P', -3.0), ('15000', 'FAR', 'P', -1.0), ('18800', 'FAR', 'P', 3.0), ('21200', 'FAR', 'C', -2.0), ('20800', 'NEAR', 'C', -4.0), ('18200', 'FAR', 'P', 1.0), ('17800', 'NEAR', 'P', -8.0), ('18600', 'NEAR', 'P', -1.0)]
+        for e in sorted(self.grouped_options):
+            s += "[%s,%s,%s,%s,%s]," % (e[0], e[3] if e[1] == 'NEAR' and e[2] =='P' else 0, 
+                                        e[3] if e[1] == 'NEAR' and e[2] =='C' else 0,
+                                        e[3] if e[1] == 'FAR' and e[2] =='P' else 0,
+                                        e[3] if e[1] == 'FAR' and e[2] =='c' else 0)
+        return s   
     
     def get_traded_months(self):
         
@@ -288,13 +339,17 @@ class PortfolioManager():
         s = '["symbol","right","avgcost","spotpx","pos","delta","theta","pos_delta","pos_theta","unreal_pl","last_updated"],'
         
         def split_toks(x):
-            pmap = json.loads(self.r_conn.get(x))
-            #print pmap
-            gmap = json.loads(self.r_conn.get(x[3:]))
-            #print gmap
-            s = '["%s","%s",%f,%f,%f,%f,%f,%f,%f,%f,"%s"],' % (x[3:], x[len(x)-1:], pmap['6001'], gmap['5006'], pmap['6002'],\
-                                                                         gmap['5002'],gmap['5004'],\
-                                                                         pmap['6005'],pmap['6006'],pmap['6008'],pmap['last_updated'])
+            try: # 
+                pmap = json.loads(self.r_conn.get(x))
+                #print pmap
+                gmap = json.loads(self.r_conn.get(x[3:]))
+                #print gmap
+                s = '["%s","%s",%f,%f,%f,%f,%f,%f,%f,%f,"%s"],' % (x[3:], x[len(x)-1:], pmap['6001'], gmap['5006'], pmap['6002'],\
+                                                                             gmap['5002'],gmap['5004'],\
+                                                                             pmap['6005'],pmap['6006'],pmap['6008'],pmap['last_updated'])
+            except:
+                logging.error('entry %s skipped due to an exception. Please validate your position' % x)
+                return ''
             return s                                                          
             
         end_s = s + ''.join (split_toks( x ) for x in pall)
@@ -515,6 +570,7 @@ class PortfolioManager():
         # 6002            pos
     
         
+        # sample pos_msg '[HSI', 'OPT', 'None', 'HKD', '20160330', '18200.0', 'P', '204436784]'
         toks = options_data.ContractHelper.printContract(pos_msg.contract).split('-')
         s = ''
         
@@ -522,7 +578,8 @@ class PortfolioManager():
         s = s + '%s,%s,%s' % (','.join(toks[i] for i in slots), toks[5].replace('.0', ''), '50.0' if toks[0][1:] == 'HSI' else '10.0')
         s = s.replace('[', '') + ",%0.4f,%0.4f" % (pos_msg.pos, pos_msg.avgCost)
         
-        
+#         print toks
+#         print '---> %s' % s
         self.port.append(s)
                 
         ckey = options_data.ContractHelper.makeRedisKey(pos_msg.contract)
@@ -581,7 +638,9 @@ if __name__ == '__main__':
     p.retrieve_position()
     print p.get_portfolio_summary()
     print p.get_tbl_pos_csv()
-
+    p.group_pos_by_strike_by_month()
+    print p.grouped_options
+    print p.get_grouped_options_str_array_stacked()
 
     # sample ouput    
 # ["exch","type","contract_mth","right","strike","con_ration","pos","avgcost"],["HSI","OPT","20150828","C","22600",50.0,0.0000,0.0000,],["HSI","OPT","20150828","C","23000",50.0,-1.0000,1770.0000,],["HSI","OPT","20150828","C","23600",50.0,-2.0000,1470.0000,],["HSI","OPT","20150828","C","23800",50.0,-1.0000,920.0000,],["HSI","OPT","20150828","C","24000",50.0,-2.0000,1820.0000,],["HSI","OPT","20150828","C","24200",50.0,-1.0000,3120.0000,],["HSI","OPT","20150828","C","24800",50.0,-1.0000,220.0000,],["HSI","OPT","20150828","P","18000",50.0,-2.0000,1045.0000,],["HSI","OPT","20150828","P","18600",50.0,-1.0000,1120.0000,],["HSI","OPT","20150828","P","18800",50.0,-1.0000,1570.0000,],["HSI","OPT","20150828","P","19800",50.0,-1.0000,870.0000,],["HSI","OPT","20150828","P","20200",50.0,-1.0000,970.0000,],["HSI","OPT","20150828","P","20800",50.0,-2.0000,970.0000,],["HSI","OPT","20150828","P","21600",50.0,-1.0000,1570.0000,],["HSI","OPT","20150828","P","21800",50.0,-7.0000,1955.7143,],["HSI","OPT","20150828","P","23200",50.0,1.0000,25930.0000,],["HSI","OPT","20150929","C","24400",50.0,1.0000,24880.0000,],["HSI","OPT","20150929","P","21600",50.0,0.0000,0.0000,],["HSI","OPT","20150929","P","21800",50.0,2.0000,52713.3333,],["HSI","OPT","20150929","P","22600",50.0,3.0000,39763.3333,],["MHI","OPT","20150828","C","24400",10.0,-1.0000,2603.0000,],["MHI","OPT","20150828","P","20800",10.0,-1.0000,313.0000,],["MHI","OPT","20150828","P","21000",10.0,-1.0000,363.0000,],["MHI","OPT","20150828","P","23600",10.0,5.0000,4285.0000,],["MHI","OPT","20150929","C","24400",10.0,1.0000,4947.0000,],["MHI","OPT","20150929","P","21600",10.0,1.0000,12657.0000,],["MHI","OPT","20150929","P","22600",10.0,1.0000,9877.0000,],["MHI","OPT","20150929","P","23600",10.0,4.0000,7757.0000,],

BIN
finopt/portfolio.pyc


+ 1 - 1
sh/options_chain.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
 ROOT=$FINOPT_HOME
 export PYTHONPATH=$FINOPT_HOME:$PYTHONPATH
+# real time mode
 python $FINOPT_HOME/finopt/options_chain.py $FINOPT_HOME/config/app.cfg
-

+ 4 - 0
sh/stop_options_chain.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+ps ax | grep -i 'options_chain' | grep python | grep -v grep | awk '{print $1}' | xargs kill -SIGTERM
+
+