Procházet zdrojové kódy

night commits - continue work on option greeks calculations 90% done

esurfer před 9 roky
rodič
revize
07eaa16de3

+ 10 - 8
src/finopt/instrument.py

@@ -57,13 +57,15 @@ class Option(Symbol):
     VEGA     = 5005
     VEGA     = 5005
     PREMIUM  = 5006
     PREMIUM  = 5006
     
     
-    
+
     #[0,1,2,3,4,5,6,7,8,9,14,5001,5002,5003,5004,5005,5006]
     #[0,1,2,3,4,5,6,7,8,9,14,5001,5002,5003,5004,5005,5006]
-        
+         
+
     def __init__(self, contract):
     def __init__(self, contract):
         Symbol.__init__(self, contract)
         Symbol.__init__(self, contract)
         
         
-        self.set_analytics(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0)
+        #self.set_analytics(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0)
+        self.set_analytics(float('nan'),float('nan'),float('nan'),float('nan'),float('nan'))
 
 
         
         
     def set_analytics(self, imvol=None, delta=None, gamma=None, theta=None, vega=None, npv=None):
     def set_analytics(self, imvol=None, delta=None, gamma=None, theta=None, vega=None, npv=None):
@@ -78,11 +80,11 @@ class Option(Symbol):
 #         self.analytics[Option.VEGA] = vega
 #         self.analytics[Option.VEGA] = vega
 #         self.analytics[Option.PREMIUM] = npv
 #         self.analytics[Option.PREMIUM] = npv
         self.set_tick_value(Option.IMPL_VOL, imvol)
         self.set_tick_value(Option.IMPL_VOL, imvol)
-        self.set_tick_value[Option.DELTA] = delta 
-        self.set_tick_value[Option.GAMMA] = gamma
-        self.set_tick_value[Option.THETA] = theta
-        self.set_tick_value[Option.VEGA] = vega
-        self.set_tick_value[Option.PREMIUM] = npv        
+        self.set_tick_value(Option.DELTA, delta) 
+        self.set_tick_value(Option.GAMMA, gamma)
+        self.set_tick_value(Option.THETA, theta)
+        self.set_tick_value(Option.VEGA, vega)
+        self.set_tick_value(Option.PREMIUM, npv)        
         
         
         
         
         
         

+ 9 - 8
src/finopt/optcal.py

@@ -1,11 +1,12 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-
 from QuantLib import *
 from QuantLib import *
 from bs4 import BeautifulSoup
 from bs4 import BeautifulSoup
 from urllib2 import urlopen, Request
 from urllib2 import urlopen, Request
 from time import strftime
 from time import strftime
 import time
 import time
 import traceback
 import traceback
+import instrument
+
 
 
 
 
 def cal_implvol(spot, strike, callput, evaldate, exdate, rate, div, vol, premium):
 def cal_implvol(spot, strike, callput, evaldate, exdate, rate, div, vol, premium):
@@ -24,9 +25,9 @@ def cal_implvol(spot, strike, callput, evaldate, exdate, rate, div, vol, premium
     process = BlackScholesMertonProcess(S,q,r,sigma)
     process = BlackScholesMertonProcess(S,q,r,sigma)
     im = option.impliedVolatility(premium, process)
     im = option.impliedVolatility(premium, process)
     results = {}
     results = {}
-    results['imvol'] = im
+    results[instrument.Option.IMPL_VOL] = im
  
  
-
+    
     return results
     return results
 
 
 
 
@@ -49,13 +50,13 @@ def cal_option(spot, strike, callput, evaldate, exdate, rate, div, vol):
     option.setPricingEngine(engine)
     option.setPricingEngine(engine)
             
             
     results = {}
     results = {}
-    results['npv'] = option.NPV()
+    results[instrument.Option.PREMIUM] = option.NPV()
 
 
-    results['delta'] = option.delta()
-    results['gamma'] = option.gamma()
+    results[instrument.Option.DELTA] = option.delta()
+    results[instrument.Option.GAMMA] = option.gamma()
     
     
-    results['theta'] = option.theta() / 365
-    results['vega'] = option.vega() 
+    results[instrument.Option.THETA] = option.theta() / 365
+    results[instrument.Option.VEGA] = option.vega() 
 #    results['rho'] = option.rho() 
 #    results['rho'] = option.rho() 
 
 
     results['strikeSensitivity'] = option.strikeSensitivity()
     results['strikeSensitivity'] = option.strikeSensitivity()

+ 43 - 26
src/rethink/analytics_engine.py

@@ -17,11 +17,7 @@ from comms.ibc.tws_client_lib import TWS_client_manager, AbstractGatewayListener
 
 
 class AnalyticsEngine(AbstractGatewayListener):
 class AnalyticsEngine(AbstractGatewayListener):
 
 
-    AE_OPTIONS_CONFIG = {
-        'underlying_substitution': {'IND': 'FUT'},
-        'underlying_sub_list': ['HSI', 'MHI']
-    }
-    
+  
     
     
     
     
     def __init__(self, kwargs):
     def __init__(self, kwargs):
@@ -63,13 +59,23 @@ class AnalyticsEngine(AbstractGatewayListener):
         
         
     
     
     def test_oc3(self, oc3):
     def test_oc3(self, oc3):
-        expiry = '20170330'
-        contractTuple = ('HHI.HK', 'FUT', 'HKFE', 'HKD', expiry, 0, '')
+#         expiry = '20170330'
+#         contractTuple = ('HHI.HK', 'FUT', 'HKFE', 'HKD', expiry, 0, '')
+#         contract = ContractHelper.makeContract(contractTuple)  
+#         
+#         oc3.set_option_structure(contract, 200, 50, 0.0012, 0.0328, expiry)        
+#         
+#         oc3.build_chain(10445, 0.03, 0.22)
+
+        expiry = '20170331'
+        contractTuple = ('QQQ', 'STK', 'SMART', 'USD', '', 0, '')
+
+
         contract = ContractHelper.makeContract(contractTuple)  
         contract = ContractHelper.makeContract(contractTuple)  
         
         
-        oc3.set_option_structure(contract, 200, 50, 0.0012, 0.0328, expiry)        
+        oc3.set_option_structure(contract, 0.5, 100, 0.0012, 0.0328, expiry)        
         
         
-        oc3.build_chain(10445, 0.03, 0.22)
+        oc3.build_chain(130, 0.03, 0.22)
         
         
 #         expiry='20170324'
 #         expiry='20170324'
 #         contractTuple = ('QQQ', 'STK', 'SMART', 'USD', '', 0, '')
 #         contractTuple = ('QQQ', 'STK', 'SMART', 'USD', '', 0, '')
@@ -146,24 +152,35 @@ class AnalyticsEngine(AbstractGatewayListener):
     def tds_event_tick_updated(self, event, contract_key, field, price, syms):
     def tds_event_tick_updated(self, event, contract_key, field, price, syms):
         results = {}
         results = {}
         for s in syms:
         for s in syms:
-            chain_id = s.get_extra_attributes(OptionsChain.CHAIN_IDENTIFIER) 
-            if chain_id  in self.option_chains.keys():
-                if 'FUT' in contract_key:
-                    results = self.option_chains[chain_id].cal_greeks_in_chain(self.kwargs['evaluation_date'])
-                else:
-                    results[ContractHelper.makeRedisKeyEx(s.get_contract())] = self.option_chains[chain_id].cal_option_greeks(s, self.kwargs['evaluation_date'])
-        
-            
-        # set_analytics(self, imvol=None, delta=None, gamma=None, theta=None, vega=None, npv=None):
-        # 
-        def update_tds_analytics(key_greeks):
-            self.tds.set_symbol_analytics(key_greeks[0], Option.IMPL_VOL, key_greeks[1][Option.IMPL_VOL])
-            self.tds.set_symbol_analytics(key_greeks[0], Option.DELTA, key_greeks[1][Option.DELTA])
-            self.tds.set_symbol_analytics(key_greeks[0], Option.GAMMA, key_greeks[1][Option.GAMMA])
-            self.tds.set_symbol_analytics(key_greeks[0], Option.THETA, key_greeks[1][Option.THETA])
-            self.tds.set_symbol_analytics(key_greeks[0], Option.VEGA, key_greeks[1][Option.VEGA])
             
             
-        map(update_tds_analytics, list(results.iteritems()))
+            if OptionsChain.CHAIN_IDENTIFIER in s.get_extra_attributes():
+                
+                chain_id = s.get_extra_attributes()[OptionsChain.CHAIN_IDENTIFIER]
+                logging.info('AnalyticsEngine:tds_event_tick_updated chain_id %s' % chain_id)
+                if chain_id  in self.option_chains.keys():
+                    if 'FUT' in contract_key or 'STK' in contract_key:
+                        results = self.option_chains[chain_id].cal_greeks_in_chain(self.kwargs['evaluation_date'])
+                    else:
+                        results[ContractHelper.makeRedisKeyEx(s.get_contract())] = self.option_chains[chain_id].cal_option_greeks(s, self.kwargs['evaluation_date'])
+                logging.info('AnalysticsEngine:tds_event_tick_updated. compute greek results %s' % results)    
+                # set_analytics(self, imvol=None, delta=None, gamma=None, theta=None, vega=None, npv=None):
+                # 
+                def update_tds_analytics(key_greeks):
+                    
+                    self.tds.set_symbol_analytics(key_greeks[0], Option.IMPL_VOL, key_greeks[1][Option.IMPL_VOL])
+                    self.tds.set_symbol_analytics(key_greeks[0], Option.DELTA, key_greeks[1][Option.DELTA])
+                    self.tds.set_symbol_analytics(key_greeks[0], Option.GAMMA, key_greeks[1][Option.GAMMA])
+                    self.tds.set_symbol_analytics(key_greeks[0], Option.THETA, key_greeks[1][Option.THETA])
+                    self.tds.set_symbol_analytics(key_greeks[0], Option.VEGA, key_greeks[1][Option.VEGA])
+                    
+                map(update_tds_analytics, list(results.iteritems()))                
+
+            else:
+                
+                continue
+             
+        
+
 
 
     def tds_event_symbol_deleted(self, event, update_mode, name, instrument):
     def tds_event_symbol_deleted(self, event, update_mode, name, instrument):
         pass
         pass

+ 43 - 14
src/rethink/option_chain.py

@@ -11,7 +11,7 @@ from misc2.observer import NotImplementedException
 
 
 
 
 from time import sleep
 from time import sleep
-from finopt.optcal import cal_implvol
+from finopt.optcal import cal_implvol, cal_option
 
 
 
 
 class OptionsChain(Publisher):
 class OptionsChain(Publisher):
@@ -49,7 +49,12 @@ class OptionsChain(Publisher):
     '''
     '''
     EVENT_OPTION_UPDATED = 'oc_option_updated'
     EVENT_OPTION_UPDATED = 'oc_option_updated'
     EVENT_UNDERLYING_ADDED = 'oc_underlying_added'
     EVENT_UNDERLYING_ADDED = 'oc_underlying_added'
-    OC_EVENTS = [EVENT_OPTION_UPDATED, EVENT_UNDERLYING_ADDED]     
+    OC_EVENTS = [EVENT_OPTION_UPDATED, EVENT_UNDERLYING_ADDED]    
+    EMPTY_GREEKS =   {Option.DELTA: float('nan'), Option.GAMMA: float('nan'), 
+                      Option.THETA: float('nan'), Option.VEGA: float('nan'),
+                      Option.IMPL_VOL: float('nan'), Option.PREMIUM: float('nan')}   
+
+     
     
     
     def __init__(self, name):
     def __init__(self, name):
         self.name = name
         self.name = name
@@ -203,17 +208,41 @@ class OptionsChain(Publisher):
             key = ContractHelper.makeRedisKeyEx(o.get_contract())
             key = ContractHelper.makeRedisKeyEx(o.get_contract())
             greeks = self.cal_option_greeks(o, valuation_date)
             greeks = self.cal_option_greeks(o, valuation_date)
             all_results[key] = greeks
             all_results[key] = greeks
-    
+
         return all_results
         return all_results
     
     
-    def cal_option_greeks(self, o, valuation_date):
+    def cal_option_greeks(self, option, valuation_date):
+        
+        uspot_last = self.get_underlying().get_tick_value(4)
+        if uspot_last is None:
+            return OptionsChain.EMPTY_GREEKS
+        o = option.get_contract()
+        logging.info('OptionChain:cal_option_greeks. %8.4f' % uspot_last)
+
+            
+            
         try:
         try:
-            uspot_last = self.get_underlying().get_tick_value(4)
-            greeks = cal_implvol(uspot_last, o.m_strike, o.m_right, valuation_date, 
-                                  o.m_expiry, self.rate, self.div, self.trade_vol, o.get_tick_value(4))
+            iv = cal_implvol(uspot_last, o.m_strike, o.m_right, valuation_date, 
+                                  o.m_expiry, self.rate, self.div, self.trade_vol, option.get_tick_value(4))
+        except RuntimeError:
+            logging.warn('OptionChain:cal_option_greeks. Quantlib threw an error while calculating implied vol: use intrinsic: last->%8.2f strike->%8.2f right->%s sym->%s' % 
+                         (uspot_last, o.m_strike, o.m_right, o.m_symbol))
+            iv = cal_implvol(uspot_last, o.m_strike, o.m_right, valuation_date, 
+                                  o.m_expiry, self.rate, self.div, self.trade_vol, abs(uspot_last - o.m_strike))
+
+        try:                
+            greeks = cal_option(uspot_last, o.m_strike, o.m_right, valuation_date, 
+                                  o.m_expiry, self.rate, self.div, iv[Option.IMPL_VOL])
+            greeks.update(iv)
+            logging.info('OptionChain:cal_option_greeks. %s' % greeks)
         
         
         except Exception, err:
         except Exception, err:
-            logging.error(traceback.format_exc())        
+            logging.error('OptionsChain:cal_option_greeks. Error retrieving uspot_last  greeks for option %s' % ContractHelper.makeRedisKeyEx(o))
+            logging.error(traceback.format_exc())     
+            greeks = {Option.DELTA: float('nan'), Option.GAMMA: float('nan'), 
+                      Option.THETA: float('nan'), Option.VEGA: float('nan'),
+                      Option.IMPL_VOL: float('nan'), Option.PREMIUM: float('nan')}   
+
 
 
         return greeks
         return greeks
      
      
@@ -245,9 +274,9 @@ class OptionsChain(Publisher):
                                                format_tick_val(x[1].get_tick_value(1), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(1), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(2), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(2), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(3), fmt_specq),
                                                format_tick_val(x[1].get_tick_value(3), fmt_specq),
-                                               format_tick_val(x[1].get_analytics()[Option.IMPL_VOL], fmt_spec2),
-                                               format_tick_val(x[1].get_analytics()[Option.DELTA], fmt_spec2),
-                                               format_tick_val(x[1].get_analytics()[Option.THETA], fmt_spec2),
+                                               format_tick_val(x[1].get_tick_value(Option.IMPL_VOL), fmt_spec2),
+                                               format_tick_val(x[1].get_tick_value(Option.DELTA), fmt_spec2),
+                                               format_tick_val(x[1].get_tick_value(Option.THETA), fmt_spec2),
                                                )), sorted_call)
                                                )), sorted_call)
         
         
         fmt_put = map(lambda x: (x[0], '%s,%s,%s,%s,%s,%s,%s,%s' % (format_tick_val(x[1].get_tick_value(4), fmt_spec),
         fmt_put = map(lambda x: (x[0], '%s,%s,%s,%s,%s,%s,%s,%s' % (format_tick_val(x[1].get_tick_value(4), fmt_spec),
@@ -255,9 +284,9 @@ class OptionsChain(Publisher):
                                                format_tick_val(x[1].get_tick_value(1), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(1), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(2), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(2), fmt_spec),
                                                format_tick_val(x[1].get_tick_value(3), fmt_specq),
                                                format_tick_val(x[1].get_tick_value(3), fmt_specq),
-                                               format_tick_val(x[1].get_analytics()[Option.IMPL_VOL], fmt_spec2),
-                                               format_tick_val(x[1].get_analytics()[Option.DELTA], fmt_spec2),
-                                               format_tick_val(x[1].get_analytics()[Option.THETA], fmt_spec2),                    
+                                               format_tick_val(x[1].get_tick_value(Option.IMPL_VOL), fmt_spec2),
+                                               format_tick_val(x[1].get_tick_value(Option.DELTA), fmt_spec2),
+                                               format_tick_val(x[1].get_tick_value(Option.THETA), fmt_spec2),                    
                                                )), sorted_put)
                                                )), sorted_put)
         
         
         undlypx = '%s,%s,%s,%s,%s' % (format_tick_val(self.get_underlying().get_tick_value(4), fmt_spec), 
         undlypx = '%s,%s,%s,%s,%s' % (format_tick_val(self.get_underlying().get_tick_value(4), fmt_spec), 

+ 4 - 3
src/rethink/tick_datastore.py

@@ -156,16 +156,17 @@ class TickDataStore(Publisher):
             self.lock.acquire()
             self.lock.acquire()
             if contract_key in self.symbols:
             if contract_key in self.symbols:
                 map(lambda e: e.set_tick_value(field, price), self.symbols[contract_key]['syms'])
                 map(lambda e: e.set_tick_value(field, price), self.symbols[contract_key]['syms'])
+                self.dispatch(TickDataStore.EVENT_TICK_UPDATED, {'contract_key': contract_key, 'field': field, 
+                                                             'price': price, 'syms': self.symbols[contract_key]['syms']})                
             
             
         except:
         except:
             # contract not set up in the datastore, ignore message
             # contract not set up in the datastore, ignore message
-            logging.error('set_symbol_price: exception occured to: %s' % contract_key)
+            logging.error('set_symbol_tick_price: exception occured to: %s' % contract_key)
             #self.dump()
             #self.dump()
             pass
             pass
         finally:
         finally:
             self.lock.release()
             self.lock.release()
-            self.dispatch(TickDataStore.EVENT_TICK_UPDATED, {'contract_key': contract_key, 'field': field, 
-                                                             'price': price, 'syms': self.symbols[contract_key]['syms']})
+
             
             
 
 
     def set_symbol_analytics(self, contract_key, field, value):
     def set_symbol_analytics(self, contract_key, field, value):