def __init__(self, df_metrics, df_baseindex=None, cd_strategy='naked_put', id_baseindex=c.Util.STR_INDEX_300SH, cd_marutity_days=3): self.start_date = df_metrics[c.Util.DT_DATE].values[0] self.end_date = df_metrics[c.Util.DT_DATE].values[-1] if df_baseindex is None: df_baseindex = get_data.get_index_mktdata(self.start_date, self.end_date, c.Util.STR_INDEX_300SH) self.min_holding = 20 self.init_fund = c.Util.BILLION self.slippage = 0 self.m = 1 # 期权notional倍数 if cd_strategy == 'short_straddle': self.m = 0.5 self.moneyness_rank = -4 self.nbr_maturity = 0 self.cd_trade_price = c.CdTradePrice.VOLUME_WEIGHTED self.account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.03) self.optionset = BaseOptionSet(df_metrics) self.optionset.init() self.index = BaseInstrument(df_baseindex) self.index.init() self.cd_strategy = cd_strategy self.cd_maturity_days = cd_marutity_days self.init_index = self.index.mktprice_close()
def __init__(self, df_index=None, df_future_c1=None, df_future_all=None): if df_index is not None: self.df_base = df_index self.base = BaseInstrument(df_index) else: self.df_base = df_future_c1 self.base = BaseFutureCoutinuous( df_future_c1=df_future_c1, df_futures_all_daily=df_future_all) self.base.init() self.account = BaseAccount(c.Util.BILLION * 10) self._prepare_data() self.leverage = 0.75 # Will be multiplied to delta equivalent position self.rf = 0.03 self.slippage_date = 1 / 1000.0 self.hedge_multiplier = 1 self.hold_unit = 0 self.target_option = None self.cd_model = 'ww' # Delta调仓模型 self.delta_criterian = 0.1 # 固定delta变化值调仓条件 self.delta_last_rebalanced = 0.0 self.ttm = 50 # 期权固定期限 self.k = 1.1 # 期权行权价比率 self.H = None self.delta_upper_bound = 0.99 self.flag_fix_ttm = True self.rho = 0.01
def __init__(self, df_c1, df_all, df_baseindex): self.slippage = 0 self.cd_trade_price = c.CdTradePrice.VOLUME_WEIGHTED dt_start = max(df_baseindex[c.Util.DT_DATE].values[0], df_c1[c.Util.DT_DATE].values[0]) self.end_date = min(df_baseindex[c.Util.DT_DATE].values[-1], df_c1[c.Util.DT_DATE].values[-1]) df_baseindex = df_baseindex[ df_baseindex[c.Util.DT_DATE] >= dt_start].reset_index(drop=True) df_c1 = df_c1[df_c1[c.Util.DT_DATE] >= dt_start].reset_index(drop=True) df_all = df_all[df_all[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) self.invst_portfolio = BaseFutureCoutinuous( df_c1, df_futures_all_daily=df_all) # e.g., top 50 low volatility index self.invst_portfolio.init() self.index = BaseInstrument(df_baseindex) self.index.init() self.account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.03)
def __init__(self, start_date, end_date): self.ttm = 30 self.buywrite = BuyWrite.BUY self.fund = Util.BILLION self.invest_underlying_ratio = 0.7 # self.invest_underlying_ratio = 1 self.slippage = 2 self.start_date = start_date self.end_date = end_date hist_date = start_date - datetime.timedelta(days=40) df_future_c1 = get_dzqh_cf_c1_minute(start_date, end_date, 'if') df_future_c1_daily = get_dzqh_cf_c1_daily(hist_date, end_date, 'if') df_futures_all_daily = get_dzqh_cf_daily( start_date, end_date, 'if') # daily data of all future contracts df_index = get_index_mktdata( start_date, end_date, 'index_300sh') # daily data of underlying index df_index = df_index[df_index[Util.DT_DATE].isin( Util.DZQH_CF_DATA_MISSING_DATES) == False].reset_index(drop=True) # df_index.to_csv('df_index.csv') self.trade_dates = sorted(df_future_c1_daily[Util.DT_DATE].unique()) self.df_vol_1m = Histvol.hist_vol(df_future_c1_daily) # df_parkinson_1m = Histvol.parkinson_number(df_future_c1_daily) self.df_garman_klass = Histvol.garman_klass(df_future_c1_daily) # df_hist_vol = self.df_vol_1m.join(self.df_garman_klass, how='left') # df_hist_vol.to_csv('../../data/df_hist_vol.csv') self.underlying = BaseInstrument(df_data=df_index) self.underlying.init() self.synthetic_option = SytheticOption( df_c1_data=df_future_c1, # df_c1_daily=df_future_c1_daily, df_futures_all_daily=df_futures_all_daily, df_index_daily=df_index) self.synthetic_option.init() self.account = BaseAccount(self.fund, leverage=20.0, rf=0.0) self.trading_desk = Trade() self.init_spot = self.synthetic_option.underlying_state_daily[ Util.AMT_CLOSE] self.df_analysis = pd.DataFrame()
def init(self): self.underlying = None self.futureset = None self.baseindex = None self.optionset = BaseOptionSet(self.df_option) self.optionset.init() if self.name_code == c.Util.STR_50ETF: if self.df_etf is not None: self.underlying = BaseInstrument(self.df_etf) # 50ETF self.underlying.init() if self.df_future_all is not None: self.futureset = BaseFutureSet(self.df_future_all) # IH self.futureset.init() self.future_unit_ratio = 1/1000.0 if self.df_index is not None: self.baseindex = BaseInstrument(self.df_index) # SH50 self.baseindex.init() else: # 商品期权 if self.df_future_all is not None: self.futureset = BaseFutureSet(self.df_future_all) # IH self.futureset.init() self.future_unit_ratio = 1.0
class ParityArbitrage(object): def __init__(self,name_code, df_option, df_etf=None, df_future_all=None,df_index=None): self.name_code = name_code self.df_option = df_option self.df_etf = df_etf self.df_future_all = df_future_all self.df_index = df_index self.rf = 0.03 self.m = 0.9 self.account = BaseAccount(c.Util.BILLION / 10,rf=self.rf) self.unit = 50 self.min_holding = 6 # 50ETF与IH到期日相差5天 self.nbr_maturity = 0 self.rank = 3 self.slippage = 0 self.aggregate_costs = 0.5/100.0 self.cd_price = c.CdTradePrice.CLOSE self.df_arbitrage_window = pd.DataFrame() def init(self): self.underlying = None self.futureset = None self.baseindex = None self.optionset = BaseOptionSet(self.df_option) self.optionset.init() if self.name_code == c.Util.STR_50ETF: if self.df_etf is not None: self.underlying = BaseInstrument(self.df_etf) # 50ETF self.underlying.init() if self.df_future_all is not None: self.futureset = BaseFutureSet(self.df_future_all) # IH self.futureset.init() self.future_unit_ratio = 1/1000.0 if self.df_index is not None: self.baseindex = BaseInstrument(self.df_index) # SH50 self.baseindex.init() else: # 商品期权 if self.df_future_all is not None: self.futureset = BaseFutureSet(self.df_future_all) # IH self.futureset.init() self.future_unit_ratio = 1.0 # self.optionset = BaseOptionSet(self.df_option) # self.optionset.init() def update_sythetics(self): if self.name_code == c.Util.STR_50ETF: dt_maturity = self.optionset.select_maturity_date(nbr_maturity=self.nbr_maturity, min_holding=self.min_holding) contract_month = self.optionset.get_dict_options_by_maturities()[dt_maturity][0].contract_month() self.t_quote = self.optionset.get_T_quotes(dt_maturity, self.cd_price) self.t_quote.loc[:, 'diff'] = abs( self.t_quote.loc[:, c.Util.AMT_APPLICABLE_STRIKE] - self.t_quote.loc[:, c.Util.AMT_UNDERLYING_CLOSE]) self.t_quote.loc[:, 'rank'] = self.t_quote.index - self.t_quote['diff'].idxmin() discount = c.PricingUtil.get_discount(self.optionset.eval_date, dt_maturity, self.rf) self.t_quote.loc[:, 'sythetic_underlying'] = self.t_quote.loc[:, c.Util.AMT_CALL_QUOTE] \ - self.t_quote.loc[:,c.Util.AMT_PUT_QUOTE] \ + self.t_quote.loc[:,c.Util.AMT_APPLICABLE_STRIKE] * discount df_window = self.t_quote[(self.t_quote['rank']<=self.rank)&(self.t_quote['rank']>=-self.rank)] # 只考虑rank以内期权 self.row_max_sythetic = df_window.loc[df_window['sythetic_underlying'].idxmax()] self.row_min_sythetic = df_window.loc[df_window['sythetic_underlying'].idxmin()] self.df_arbitrage_window.loc[self.optionset.eval_date,'50etf'] = self.underlying.mktprice_close() self.df_arbitrage_window.loc[self.optionset.eval_date,'sythetic_underlying_max'] = self.row_max_sythetic['sythetic_underlying'] self.df_arbitrage_window.loc[self.optionset.eval_date,'sythetic_underlying_min'] = self.row_min_sythetic['sythetic_underlying'] if self.futureset is not None: future = self.futureset.select_future_by_contract_month(contract_month) self.row_max_sythetic['future'] = future if future is None: return self.basis_to_etf = future.mktprice_close() - self.underlying.mktprice_close()/self.future_unit_ratio self.df_arbitrage_window.loc[self.optionset.eval_date, 'basis_to_etf'] = self.basis_to_etf self.df_arbitrage_window.loc[self.optionset.eval_date, 'ih'] = future.mktprice_close() if self.baseindex is not None: self.basis_to_index = future.mktprice_close() - self.baseindex.mktprice_close() self.tracking_error = self.underlying.mktprice_close()/self.future_unit_ratio - self.baseindex.mktprice_close() self.df_arbitrage_window.loc[self.optionset.eval_date, 'basis_to_index'] = self.basis_to_index self.df_arbitrage_window.loc[self.optionset.eval_date, 'tracking_error'] = self.tracking_error self.df_arbitrage_window.loc[self.optionset.eval_date, 'index_50'] = self.baseindex.mktprice_close() else: dt_maturity = self.optionset.select_maturity_date(nbr_maturity=self.nbr_maturity, min_holding=self.min_holding) contract_month = self.optionset.get_dict_options_by_maturities()[dt_maturity][0].contract_month() self.t_quote = self.optionset.get_T_quotes(dt_maturity, self.cd_price) self.t_quote.loc[:, 'diff'] = abs( self.t_quote.loc[:, c.Util.AMT_APPLICABLE_STRIKE] - self.t_quote.loc[:, c.Util.AMT_UNDERLYING_CLOSE]) self.t_quote.loc[:, 'rank'] = self.t_quote.index - self.t_quote['diff'].idxmin() discount = c.PricingUtil.get_discount(self.optionset.eval_date, dt_maturity, self.rf) self.t_quote.loc[:, 'sythetic_underlying'] = self.t_quote.loc[:, c.Util.AMT_CALL_QUOTE] \ - self.t_quote.loc[:,c.Util.AMT_PUT_QUOTE] \ + self.t_quote.loc[:,c.Util.AMT_APPLICABLE_STRIKE] * discount df_window = self.t_quote[(self.t_quote['rank']<=self.rank)&(self.t_quote['rank']>=-self.rank)] # 只考虑rank以内期权 self.row_max_sythetic = df_window.loc[df_window['sythetic_underlying'].idxmax()] self.row_min_sythetic = df_window.loc[df_window['sythetic_underlying'].idxmin()] future = self.futureset.select_future_by_contract_month(contract_month) self.underlying = future self.df_arbitrage_window.loc[self.optionset.eval_date, 'underlying'] = self.underlying.mktprice_close() self.df_arbitrage_window.loc[self.optionset.eval_date, 'sythetic_underlying_max'] = self.row_max_sythetic[ 'sythetic_underlying'] self.df_arbitrage_window.loc[self.optionset.eval_date, 'sythetic_underlying_min'] = self.row_min_sythetic[ 'sythetic_underlying'] def open_signal(self,cd_strategy): if cd_strategy == 'box': if (self.row_max_sythetic['sythetic_underlying'] - self.row_min_sythetic['sythetic_underlying'])/self.underlying.mktprice_close() > self.aggregate_costs: df = pd.DataFrame(columns=['dt_date','id_instrument','base_instrument','long_short']) df = self.short_sythetic(df) df = self.long_sythetic(df) return df else: return None elif cd_strategy == 'conversion': # Converion : Short Sythetic, Long ETF if (self.row_max_sythetic['sythetic_underlying'] - self.underlying.mktprice_close())/self.underlying.mktprice_close() > self.aggregate_costs: df = pd.DataFrame(columns=['dt_date','id_instrument','base_instrument','long_short']) df = self.short_sythetic(df) df = self.long_etf(df) return df else: return None elif cd_strategy == 'conversion_ih': # Converion : Short Sythetic, Long IH # 主要布局IH负基差套利 if self.optionset.eval_date.month ==5: return None #5月由于股票集中现金分红不做空Synthetic future = self.row_max_sythetic['future'] if future is None: return None self.future = future if (self.row_max_sythetic['sythetic_underlying']/self.future_unit_ratio - future.mktprice_close()- self.df_arbitrage_window.loc[self.optionset.eval_date,'tracking_error'])/future.mktprice_close() > self.aggregate_costs: df = pd.DataFrame(columns=['dt_date', 'id_instrument', 'base_instrument', 'long_short']) df = self.short_sythetic(df) df = self.long_ih(df,future) return df else: return None elif cd_strategy == 'ih_basis_arbitrage': future = self.row_max_sythetic['future'] if future is None: return None self.future = future if self.df_arbitrage_window.loc[self.optionset.eval_date, 'basis_to_index'] < -self.aggregate_costs: # 期货贴水 df = pd.DataFrame(columns=['dt_date', 'id_instrument', 'base_instrument', 'long_short']) df = self.short_sythetic(df) df = self.long_ih(df,future) return df else: return None elif cd_strategy == 'may_effect': # Reverse: Long Sythetic, Short IH # 5-9月分红期 if self.optionset.eval_date.month ==5: #5月由于股票集中现金分红不做空Synthetic df = pd.DataFrame(columns=['dt_date', 'id_instrument', 'base_instrument', 'long_short']) df = self.long_sythetic(df) df = self.short_ih(df) return df else: return None def close_signal(self,cd_strategy,df_position): if cd_strategy == 'box': if self.reverse_call.maturitydt() == self.optionset.eval_date or self.conversion_call.maturitydt() == self.optionset.eval_date : return True discount_r = c.PricingUtil.get_discount(self.optionset.eval_date, self.reverse_put.maturitydt(), self.rf) discount_c = c.PricingUtil.get_discount(self.optionset.eval_date, self.conversion_put.maturitydt(), self.rf) reverse_sythetic = self.reverse_call.mktprice_close()-self.reverse_put.mktprice_close()+self.reverse_put.applicable_strike()*discount_r # Longed conversion_sythetic = self.conversion_call.mktprice_close()-self.conversion_put.mktprice_close()+self.conversion_put.applicable_strike()*discount_c # shorted if conversion_sythetic <= reverse_sythetic: return True else: return False elif cd_strategy == 'conversion': # Short Sythetic, Long Underlying # 主要布局IH负基差套利 if self.conversion_call.maturitydt() == self.optionset.eval_date: return True discount_c = c.PricingUtil.get_discount(self.optionset.eval_date, self.conversion_put.maturitydt(), self.rf) conversion_sythetic = self.conversion_call.mktprice_close() - self.conversion_put.mktprice_close() + self.conversion_put.applicable_strike() * discount_c # shorted if conversion_sythetic/self.future_unit_ratio <= self.underlying.mktprice_close(): return True else: return False elif cd_strategy == 'conversion_ih': # Short Sythetic, Long IH # 主要布局IH负基差套利 if self.conversion_call.maturitydt() == self.optionset.eval_date or self.future.maturitydt() == self.optionset.eval_date: return True discount_c = c.PricingUtil.get_discount(self.optionset.eval_date, self.conversion_put.maturitydt(), self.rf) conversion_sythetic = self.conversion_call.mktprice_close() - self.conversion_put.mktprice_close() + self.conversion_put.applicable_strike() * discount_c # shorted if conversion_sythetic/self.future_unit_ratio <= self.future.mktprice_close(): return True else: return False elif cd_strategy == 'ih_basis_arbitrage': if self.df_arbitrage_window.loc[self.optionset.eval_date, 'basis_to_index'] >= 0: return True else: return False elif cd_strategy == 'may_effect': # Reverse: Long Sythetic, Short IH # 5-9月分红期 if self.optionset.eval_date.month !=5: #5月由于股票集中现金分红不做空Synthetic return True else: return False def open_excute(self,open_signal): if open_signal is None: return False else: fund_per_unit = open_signal['fund_requirement'].sum() unit = np.floor(self.account.cash*self.m/fund_per_unit) for (idx,row) in open_signal.iterrows(): option = row['base_instrument'] order = self.account.create_trade_order(option, row['long_short'], unit*row['unit_ratio'], cd_trade_price=self.cd_price) record = option.execute_order(order, slippage=self.slippage) self.account.add_record(record, option) print(self.optionset.eval_date, ' open position') return True def close_excute(self): self.close_out() print(self.optionset.eval_date, ' close position') return True # else: # for (idx,row) in close_signal.iterrows(): # option = row['base_instrument'] # order = self.account.create_trade_order(option, row['long_short'], row['unit'], # cd_trade_price=self.cd_price) # record = option.execute_order(order, slippage=self.slippage) # self.account.add_record(record, option) # return True def close_out(self): close_out_orders = self.account.creat_close_out_order(cd_trade_price=c.CdTradePrice.CLOSE) for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record(execution_record, self.account.dict_holding[order.id_instrument]) def short_sythetic(self,df): # Short Sythetic self.conversion_call = self.optionset.get_baseoption_by_id(self.row_max_sythetic[c.Util.ID_CALL]) fund_requirement = self.conversion_call.get_fund_required(c.LongShort.SHORT) df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'C_call', 'id_instrument': self.row_max_sythetic[c.Util.ID_CALL], 'base_instrument': self.conversion_call, 'long_short': c.LongShort.SHORT, 'fund_requirement': fund_requirement, 'cashflow_t0': self.conversion_call.mktprice_close() * self.conversion_call.multiplier(), 'unit_ratio' : 1}, ignore_index=True) self.conversion_put = self.optionset.get_baseoption_by_id(self.row_max_sythetic[c.Util.ID_PUT]) fund_requirement = self.conversion_put.get_fund_required(c.LongShort.LONG) df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'C_put', 'id_instrument': self.row_max_sythetic[c.Util.ID_PUT], 'base_instrument': self.conversion_put, 'long_short': c.LongShort.LONG, 'fund_requirement': fund_requirement, 'cashflow_t0': -self.conversion_put.mktprice_close() * self.conversion_put.multiplier(), 'unit_ratio' : 1}, ignore_index=True) return df def long_sythetic(self,df): # Reverse : Long Sythetic self.reverse_call = self.optionset.get_baseoption_by_id(self.row_min_sythetic[c.Util.ID_CALL]) fund_requirement = self.reverse_call.get_fund_required(c.LongShort.LONG) df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'R_call', 'id_instrument': self.row_min_sythetic[c.Util.ID_CALL], 'base_instrument': self.reverse_call, 'long_short': c.LongShort.LONG, 'fund_requirement': fund_requirement, 'cashflow_t0': -self.reverse_call.mktprice_close() * self.reverse_call.multiplier()}, ignore_index=True) self.reverse_put = self.optionset.get_baseoption_by_id(self.row_min_sythetic[c.Util.ID_PUT]) fund_requirement = self.reverse_put.get_fund_required(c.LongShort.SHORT) df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'R_put', 'id_instrument': self.row_min_sythetic[c.Util.ID_PUT], 'base_instrument': self.reverse_put, 'long_short': c.LongShort.SHORT, 'fund_requirement': fund_requirement, 'cashflow_t0': self.reverse_put.mktprice_close() * self.reverse_put.multiplier()}, ignore_index=True) return df def long_etf(self,df): unit_ratio = self.conversion_put.multiplier() fund_requirement = self.conversion_put.multiplier() * self.underlying.mktprice_close() df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'underlying', 'id_instrument': self.underlying.id_instrument(), 'base_instrument': self.underlying, 'long_short': c.LongShort.LONG, 'fund_requirement': fund_requirement, 'cashflow_t0': -self.underlying.mktprice_close() * self.underlying.multiplier()*unit_ratio, 'unit_ratio' : unit_ratio}, ignore_index=True) return df def long_ih(self,df,future): unit_ratio = self.conversion_put.multiplier()/future.multiplier()/1000.0 fund_requirement = future.mktprice_close()*future.multiplier()*unit_ratio df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'underlying', 'id_instrument': future.id_instrument(), 'base_instrument': future, 'long_short': c.LongShort.LONG, 'fund_requirement': fund_requirement, 'cashflow_t0': -future.mktprice_close() * future.multiplier()*unit_ratio, 'unit_ratio' : unit_ratio}, ignore_index=True) return df def short_ih(self,df): unit_ratio = self.reverse_put.multiplier()/self.future.multiplier()/1000.0 fund_requirement = self.future.mktprice_close()*self.future.multiplier()*unit_ratio df = df.append({'dt_date': self.optionset.eval_date, 'cd_posiiton': 'underlying', 'id_instrument': self.future.id_instrument(), 'base_instrument': self.future, 'long_short': c.LongShort.SHORT, 'fund_requirement': fund_requirement, 'cashflow_t0': -self.future.mktprice_close() * self.future.multiplier()*unit_ratio, 'unit_ratio' : unit_ratio}, ignore_index=True) return df def back_test(self, cd_strategy): # TODO: DIVIDEND empty_position = True df_position = None while self.optionset.has_next(): # if self.optionset.eval_date == datetime.date(2015,5,18): # print('') self.update_sythetics() if empty_position: df_position = self.open_signal(cd_strategy) empty_position = not self.open_excute(df_position) elif self.close_signal(cd_strategy,df_position): empty_position = self.close_excute() # if isinstance(self.underlying,BaseFutureCoutinuous): # self.underlying.shift_contract_month(self.account,self.slippage) self.account.daily_accounting(self.optionset.eval_date) self.optionset.next() self.underlying.next() if self.futureset is not None: self.futureset.next() if self.baseindex is not None: self.baseindex.next() # print(self.optionset.eval_date) return self.account def back_test_comdty(self, cd_strategy): empty_position = True df_position = None while self.optionset.has_next(): # if self.optionset.eval_date == datetime.date(2015,5,18): # print('') self.update_sythetics() if empty_position: df_position = self.open_signal(cd_strategy) empty_position = not self.open_excute(df_position) elif self.close_signal(cd_strategy,df_position): empty_position = self.close_excute() # if isinstance(self.underlying,BaseFutureCoutinuous): # self.underlying.shift_contract_month(self.account,self.slippage) self.account.daily_accounting(self.optionset.eval_date) self.optionset.next() self.futureset.next() # if self.baseindex is not None: self.baseindex.next() # print(self.optionset.eval_date) return self.account
list_pct_option_amt = [] for moneyness in [0, -1, -2, -3, -4]: # for moneyness in [-1, -2, -3]: # for moneyness in [-3]: dict_annualized_yield = {'m': moneyness} dict_annualized_volatility = {'m': moneyness} dict_max_drawdown = {'m': moneyness} dict_sharpe_ratio = {'m': moneyness} dict_pct_option_amt = {'m': moneyness} # for target_delta in [-0.1,-0.2,-0.3,-0.4]: for target_delta in [None]: option_amt = [] optionset = BaseOptionSet(df_metrics) optionset.init() underlying = BaseInstrument(df_underlying) underlying.init() account = BaseAccount(init_fund=10000000, leverage=1.0, rf=0.03) """ init open position """ unit_underlying = np.floor(pct_underlying_invest * account.cash / underlying.mktprice_close() / underlying.multiplier()) order_underlying = account.create_trade_order(underlying, c.LongShort.LONG, unit_underlying) record_underlying = underlying.execute_order(order_underlying, slippage=slippage) account.add_record(record_underlying, underlying) maturity1 = optionset.select_maturity_date(nbr_maturity=nbr_maturity, min_holding=min_holding) list_atm_call, list_atm_put = optionset.get_options_list_by_moneyness_mthd1(
df_stocks[c.Util.AMT_CLOSE] = df_stocks['close'] df_stocks[c.Util.ID_INSTRUMENT] = '十大龙头股组合' df_metrics = get_data.get_50option_mktdata(start_date, end_date) df_index = get_data.get_index_mktdata(start_date, end_date, c.Util.STR_INDEX_50ETF) d1 = df_index[c.Util.DT_DATE].values[0] d2 = df_metrics[c.Util.DT_DATE].values[0] d = max(d1, d2) df_metrics = df_metrics[df_metrics[c.Util.DT_DATE] >= d].reset_index(drop=True) df_index = df_index[df_index[c.Util.DT_DATE] >= d].reset_index(drop=True) init_index = df_index[c.Util.AMT_CLOSE].values[0] benchmark = [1] benchmark1 = [1] """ Collar """ optionset = BaseOptionSet(df_metrics) optionset.init() index = BaseInstrument(df_index) index.init() stock = BaseInstrument(df_stocks) stock.init() account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.0) maturity = optionset.select_maturity_date(nbr_maturity=nbr_maturity, min_holding=min_holding) # 标的指数开仓 # unit_index = np.floor(m*account.cash/index.mktprice_close()/index.multiplier()) # init_mktvalue = unit_index*index.mktprice_close()*index.multiplier() # order_index = account.create_trade_order(index, c.LongShort.LONG, unit_index, cd_trade_price=c.CdTradePrice.CLOSE) # record_index = index.execute_order(order_index, slippage=slippage) # account.add_record(record_index, index) # 标的换成股票指数 init_mktvalue = m*account.cash unit_stock = np.floor(init_mktvalue/stock.mktprice_close()/stock.multiplier())
df_index = df_index[df_index[Util.DT_DATE].isin( Util.DZQH_CF_DATA_MISSING_DATES) == False].reset_index(drop=True) df_vol_1m = Histvol.hist_vol(df_future_c1_daily) # df_parkinson_1m = Histvol.parkinson_number(df_future_c1_daily) # df_garman_klass = Histvol.garman_klass(df_future_c1_daily) # df_hist_vol = df_vol_1m.join(df_parkinson_1m, how='left') # df_hist_vol = df_hist_vol.join(df_garman_klass, how='left') df_future_c1_daily = df_future_c1_daily[ df_future_c1_daily[Util.DT_DATE] >= start_date].reset_index(drop=True) synthetic_option = SytheticOption(df_c1_minute=df_future_c1, df_c1_daily=df_future_c1_daily, df_futures_all_daily=df_futures_all_daily, df_index_daily=df_index) synthetic_option.init() underlying = BaseInstrument(df_data=df_index) underlying.init() account = BaseAccount(2 * Util.BILLION, leverage=10.0, rf=0.0) trading_desk = Trade() ##################################################################### # """ Init position """ strike = synthetic_option.underlying_index_state_daily[Util.AMT_CLOSE] dt_maturity = synthetic_option.eval_date + datetime.timedelta(days=30) vol = 0.2 Option = EuropeanOption(strike, dt_maturity, OptionType.PUT) delta = synthetic_option.get_black_delta(Option, vol) id_future = synthetic_option.current_state[Util.ID_INSTRUMENT] synthetic_unit = synthetic_option.get_synthetic_unit(delta) if synthetic_unit > 0: long_short = LongShort.LONG
class HoldFutureContinuous(object): def __init__(self, df_c1, df_all, df_baseindex): self.slippage = 0 self.cd_trade_price = c.CdTradePrice.VOLUME_WEIGHTED dt_start = max(df_baseindex[c.Util.DT_DATE].values[0], df_c1[c.Util.DT_DATE].values[0]) self.end_date = min(df_baseindex[c.Util.DT_DATE].values[-1], df_c1[c.Util.DT_DATE].values[-1]) df_baseindex = df_baseindex[ df_baseindex[c.Util.DT_DATE] >= dt_start].reset_index(drop=True) df_c1 = df_c1[df_c1[c.Util.DT_DATE] >= dt_start].reset_index(drop=True) df_all = df_all[df_all[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) self.invst_portfolio = BaseFutureCoutinuous( df_c1, df_futures_all_daily=df_all) # e.g., top 50 low volatility index self.invst_portfolio.init() self.index = BaseInstrument(df_baseindex) self.index.init() self.account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.03) def close_all_options(self): for option in self.account.dict_holding.values(): if isinstance(option, BaseOption): order = self.account.create_close_order( option, cd_trade_price=self.cd_trade_price) record = option.execute_order(order, slippage=self.slippage) self.account.add_record(record, option) self.dict_strategy = {} def close_out(self): close_out_orders = self.account.creat_close_out_order( cd_trade_price=c.CdTradePrice.CLOSE) for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) def back_test(self): self.unit_index = np.floor(self.account.cash / self.index.mktprice_close() / self.index.multiplier()) unit_portfolio = np.floor(self.account.cash / self.invst_portfolio.mktprice_close() / self.invst_portfolio.multiplier()) order_index = self.account.create_trade_order( self.invst_portfolio, c.LongShort.LONG, unit_portfolio, cd_trade_price=c.CdTradePrice.CLOSE) record_index = self.invst_portfolio.execute_order( order_index, slippage=self.slippage) self.account.add_record(record_index, self.invst_portfolio) init_index = self.index.mktprice_close() index_npv = [] while self.invst_portfolio.eval_date <= self.end_date: if self.invst_portfolio.eval_date >= self.end_date: # Final close out all. close_out_orders = self.account.creat_close_out_order() for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) self.account.daily_accounting(self.invst_portfolio.eval_date) index_npv.append(self.index.mktprice_close() / init_index) print(self.invst_portfolio.eval_date, ' close out ') break #移仓换月 self.invst_portfolio.shift_contract_month(self.account, self.slippage) self.account.daily_accounting(self.invst_portfolio.eval_date) index_npv.append(self.index.mktprice_close() / init_index) if not self.invst_portfolio.has_next(): break self.invst_portfolio.next() self.index.next() self.account.account['baseindex_npv'] = index_npv return self.account
df_underlying_with_alpha.loc[ idx, 'close_alpha'] = df_underlying_with_alpha.loc[ idx - 1, 'close_alpha'] * np.exp( df_underlying_with_alpha.loc[idx, 'r1']) df_underlying_with_alpha = df_underlying_with_alpha[[ c.Util.DT_DATE, c.Util.ID_INSTRUMENT, c.Util.AMT_CLOSE, 'close_alpha' ]].rename(columns={c.Util.AMT_CLOSE: 'etf_close'}) df_underlying_with_alpha = df_underlying_with_alpha.rename( columns={'close_alpha': c.Util.AMT_CLOSE}) # df_underlying_with_alpha.to_csv('../accounts_data/df_underlying_with_alpha='+str(alpha)+'.csv') """ Init Portfolio and Account """ init_fund = 10000000 optionset = BaseOptionSet(df_metrics_1) optionset.init() underlying = BaseInstrument(df_underlying_with_alpha) underlying.init() account = BaseAccount(init_fund, leverage=1.0, rf=0.03) """ 初始开仓 """ unit_underlying = np.floor(pct_underlying_invest * account.cash / underlying.mktprice_close() / underlying.multiplier()) order_underlying = account.create_trade_order(underlying, c.LongShort.LONG, unit_underlying) record_underlying = underlying.execute_order(order_underlying, slippage=slippage) account.add_record(record_underlying, underlying) maturity1 = optionset.select_maturity_date(nbr_maturity=nbr_maturity, min_holding=min_holding) equal_50etf_unit = unit_underlying * underlying.mktprice_close( ) / optionset.eligible_options[0].underlying_close()
class HedgeIndexByOptions(object): def __init__(self, df_baseindex, df_option_metrics, df_c1=None, df_all=None, cd_direction_timing='ma', cd_strategy='bull_spread', cd_volatility='close_std', cd_short_ma='ma_5', cd_long_ma='ma_60', cd_std='std_10'): self.min_holding = 20 self.slippage = 0 self.nbr_maturity = 0 self.moneyness_rank = 0 self.cd_trade_price = c.CdTradePrice.VOLUME_WEIGHTED # self.cd_trade_price = c.CdTradePrice.CLOSE if df_c1 is None: dt_start = max(df_option_metrics[c.Util.DT_DATE].values[0], df_baseindex[c.Util.DT_DATE].values[0]) self.end_date = min(df_option_metrics[c.Util.DT_DATE].values[-1], df_baseindex[c.Util.DT_DATE].values[-1]) df_metrics = df_option_metrics[ df_option_metrics[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_baseindex = df_baseindex[ df_baseindex[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) self.invst_portfolio = BaseInstrument( df_baseindex) # e.g., top 50 low volatility index self.invst_portfolio.init() else: dt_start = max(df_option_metrics[c.Util.DT_DATE].values[0], df_baseindex[c.Util.DT_DATE].values[0], df_c1[c.Util.DT_DATE].values[0]) self.end_date = min(df_option_metrics[c.Util.DT_DATE].values[-1], df_baseindex[c.Util.DT_DATE].values[-1], df_c1[c.Util.DT_DATE].values[-1]) df_metrics = df_option_metrics[ df_option_metrics[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_baseindex = df_baseindex[ df_baseindex[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_c1 = df_c1[df_c1[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_all = df_all[df_all[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) self.invst_portfolio = BaseFutureCoutinuous( df_c1, df_futures_all_daily=df_all ) # e.g., top 50 low volatility index self.invst_portfolio.init() self.optionset = BaseOptionSet(df_metrics) self.index = BaseInstrument(df_baseindex) self.optionset.init() self.index.init() self.account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.03) self.prepare_timing(df_baseindex) self.cd_direction_timing = cd_direction_timing self.cd_strategy = cd_strategy self.cd_volatility = cd_volatility self.cd_short_ma = cd_short_ma self.cd_long_ma = cd_long_ma self.cd_std = cd_std self.dict_strategy = {} self.nbr_timing = 0 self.nbr_stop_loss = 0 self.nvp_adjustment = 0 self.sl_npv_high_point = 1.0 self.strategy_pause = False def prepare_timing(self, df_index): df_index['ma_3'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=3).shift() df_index['ma_5'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=5).shift() df_index['ma_10'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=10).shift() df_index['ma_15'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=15).shift() df_index['ma_20'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=20).shift() df_index['ma_30'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=30).shift() df_index['ma_40'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=40).shift() df_index['ma_50'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=50).shift() df_index['ma_60'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=60).shift() df_index['ma_120'] = c.Statistics.moving_average( df_index[c.Util.AMT_CLOSE], n=120).shift() df_index['std_5'] = c.Statistics.standard_deviation( df_index[c.Util.AMT_CLOSE], n=5).shift() df_index['std_10'] = c.Statistics.standard_deviation( df_index[c.Util.AMT_CLOSE], n=10).shift() df_index['std_15'] = c.Statistics.standard_deviation( df_index[c.Util.AMT_CLOSE], n=15).shift() df_index['std_20'] = c.Statistics.standard_deviation( df_index[c.Util.AMT_CLOSE], n=20).shift() df_index['ma_3-20'] = df_index['ma_3'] - df_index['ma_20'] self.df_timing = df_index.set_index(c.Util.DT_DATE) def open_signal(self): if self.cd_direction_timing == 'ma': return self.open_position_ma() def close_signal(self): if self.cd_direction_timing == 'ma': return self.close_position_ma() def stop_loss_beg(self, drawdown, P_mdd): if drawdown.loc[self.optionset.eval_date, c.Util.DRAWDOWN] <= P_mdd: return True def stop_loss_end(self, drawdown, P_mdd): if drawdown.loc[ self.optionset.eval_date, c.Util.PORTFOLIO_NPV] >= self.account.account[ c.Util.PORTFOLIO_NPV].values[-1] + self.nvp_adjustment: self.nvp_adjustment = drawdown.loc[ self.optionset.eval_date, c.Util.PORTFOLIO_NPV] - self.account.account[ c.Util.PORTFOLIO_NPV].values[-1] self.nbr_stop_loss += 1 print(self.optionset.eval_date, ' stop loss end ') print(self.nvp_adjustment, self.account.account[c.Util.PORTFOLIO_NPV].values[-1], drawdown.loc[self.optionset.eval_date, c.Util.PORTFOLIO_NPV]) return True def strategy(self, cd_price=c.CdPriceType.OPEN): if self.cd_strategy == 'bull_spread': if self.cd_volatility == 'close_std': dt_date = self.optionset.eval_date std_close = self.df_timing.loc[dt_date, self.cd_std] k_short = self.index.mktprice_open() - std_close put_long, put_short = self.bull_spread(k_short, cd_price) return { c.LongShort.SHORT: put_short, c.LongShort.LONG: put_long } def shift(self): if self.cd_strategy == 'bull_spread': return self.shift_bull_spread() def open_position_ma(self): dt_date = self.optionset.eval_date if dt_date not in self.df_timing.index: return False ma_5 = self.df_timing.loc[dt_date, self.cd_short_ma] ma_60 = self.df_timing.loc[dt_date, self.cd_long_ma] if ma_5 < ma_60: return True else: return False def close_position_ma(self): dt_date = self.optionset.eval_date dt_maturity = None for option in self.account.dict_holding.values(): if isinstance(option, BaseOption) and option is not None: dt_maturity = option.maturitydt() break if dt_maturity is not None and (dt_maturity - dt_date).days <= 5: return True ma_5 = self.df_timing.loc[dt_date, self.cd_short_ma] ma_60 = self.df_timing.loc[dt_date, self.cd_long_ma] if ma_5 >= ma_60: print(self.optionset.eval_date) self.nbr_timing += 1 return True else: return False def bull_spread(self, k_short, cd_price=c.CdPriceType.OPEN): maturity = self.optionset.select_maturity_date( nbr_maturity=self.nbr_maturity, min_holding=self.min_holding) xx, list_put0 = self.optionset.get_options_list_by_moneyness_mthd1( moneyness_rank=self.moneyness_rank, maturity=maturity, cd_price=cd_price) put_long = self.optionset.select_higher_volume(list_put0) # if put_long is None: # xxx, list_put0 = optionset.get_options_list_by_moneyness_mthd1(moneyness_rank=0, # maturity=maturity, # cd_price=c.CdPriceType.OPEN) # put_long = optionset.select_higher_volume(list_put0) put_short = self.optionset.select_higher_volume( self.optionset.get_option_closest_strike(c.OptionType.PUT, k_short, maturity)) if put_short is not None: if put_short.strike() >= (k_short + put_long.strike()) / 2.0: put_short = None elif put_short.id_instrument() == put_long.id_instrument(): xx, list_put1 = self.optionset.get_options_list_by_moneyness_mthd1( moneyness_rank=-1, maturity=maturity, cd_price=cd_price) put_short = self.optionset.select_higher_volume(list_put1) # put_short = None return put_long, put_short def shift_bull_spread(self): option_short = self.dict_strategy[c.LongShort.SHORT] option_long = self.dict_strategy[c.LongShort.LONG] if option_short is None: return self.strategy() else: if self.index.mktprice_last_close() <= (option_long.strike() + option_short.strike()) / 2: return self.strategy() else: return None def excute(self, dict_strategy, cd_trade_price=None): if cd_trade_price is None: cd_trade_price = self.cd_trade_price if dict_strategy is None: return for long_short in dict_strategy.keys(): option = dict_strategy[long_short] if option is None: continue elif long_short in self.dict_strategy.keys() and self.dict_strategy[long_short] is not None \ and option.id_instrument() == self.dict_strategy[long_short].id_instrument(): continue unit = self.unit_index / option.multiplier() order = self.account.create_trade_order( option, long_short, unit, cd_trade_price=cd_trade_price) record = option.execute_order(order, slippage=self.slippage) self.account.add_record(record, option) self.dict_strategy = dict_strategy def close_options(self): for option in self.account.dict_holding.values(): if isinstance(option, BaseOption): order = self.account.create_close_order( option, cd_trade_price=self.cd_trade_price) record = option.execute_order(order, slippage=self.slippage) self.account.add_record(record, option) self.dict_strategy = {} def close_out(self): close_out_orders = self.account.creat_close_out_order( cd_trade_price=c.CdTradePrice.CLOSE) for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) def back_test(self): self.unit_index = np.floor(self.account.cash / self.index.mktprice_close() / self.index.multiplier()) unit_portfolio = np.floor(self.account.cash / self.invst_portfolio.mktprice_close() / self.invst_portfolio.multiplier()) order_index = self.account.create_trade_order( self.invst_portfolio, c.LongShort.LONG, unit_portfolio, cd_trade_price=c.CdTradePrice.CLOSE) record_index = self.invst_portfolio.execute_order( order_index, slippage=self.slippage) self.account.add_record(record_index, self.invst_portfolio) empty_position = True init_index = self.index.mktprice_close() init_portfolio = self.invst_portfolio.mktprice_close() base_npv = [] index_npv = [] while self.optionset.eval_date <= self.end_date: # if self.optionset.eval_date == datetime.date(2016,5,20): # print('') # print(self.optionset.eval_date) if self.optionset.eval_date >= self.end_date: # Final close out all. close_out_orders = self.account.creat_close_out_order() for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) self.account.daily_accounting(self.optionset.eval_date) base_npv.append(self.invst_portfolio.mktprice_close() / init_portfolio) index_npv.append(self.index.mktprice_close() / init_index) print(self.optionset.eval_date, ' close out ') break if not empty_position: if self.close_signal(): self.close_options() empty_position = True else: strategy = self.shift() if strategy is not None: self.close_options() self.excute(strategy) if empty_position and self.open_signal(): self.excute(self.strategy()) empty_position = False #TODO:移仓换月 if isinstance(self.invst_portfolio, BaseFutureCoutinuous): self.invst_portfolio.shift_contract_month( self.account, self.slippage) self.account.daily_accounting(self.optionset.eval_date) self.account.account.loc[self.optionset.eval_date, 'unit_index'] = self.unit_index self.account.account.loc[ self.optionset.eval_date, 'close_index'] = self.index.mktprice_close() # print(self.optionset.eval_date,estimated_npv1,estimated_npv2,estimated_npv3,self.account.account.loc[self.optionset.eval_date,c.Util.PORTFOLIO_NPV]) base_npv.append(self.invst_portfolio.mktprice_close() / init_portfolio) index_npv.append(self.index.mktprice_close() / init_index) # print(self.invst_portfolio.eval_date, self.account.account.loc[self.optionset.eval_date,c.Util.PORTFOLIO_NPV], # self.invst_portfolio.mktprice_close() / init_index) if not self.optionset.has_next(): break self.optionset.next() self.index.next() self.invst_portfolio.next() self.account.account['base_npv'] = base_npv self.account.account['index_npv'] = index_npv # active_npv = self.df_index[self.df_index[c.Util.DT_DATE]<=self.optionset.eval_date].reset_index(drop=True) # self.account.account['active_npv'] = active_npv[c.Util.AMT_CLOSE] self.account.nbr_timing = self.nbr_timing # print(self.account.account.loc[self.invst_portfolio.eval_date,c.Util.PORTFOLIO_NPV]) return self.account def back_test_with_stop_loss(self, drawdown, P_mdd): self.P_mdd = P_mdd self.unit_index = np.floor(self.account.cash / self.index.mktprice_close() / self.index.multiplier()) order_index = self.account.create_trade_order( self.index, c.LongShort.LONG, self.unit_index, cd_trade_price=c.CdTradePrice.CLOSE) record_index = self.index.execute_order(order_index, slippage=self.slippage) self.account.add_record(record_index, self.index) empty_position = True init_index = self.index.mktprice_close() base_npv = [] stop_loss_paused = False while self.optionset.eval_date <= self.end_date: # if self.optionset.eval_date == datetime.date(2016,5,20): # print('') # print(self.optionset.eval_date) if self.optionset.eval_date >= self.end_date: # Final close out all. close_out_orders = self.account.creat_close_out_order() for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) self.account.daily_accounting(self.optionset.eval_date) base_npv.append(self.index.mktprice_close() / init_index) print(self.optionset.eval_date, ' close out ') break # Option Hedge if not stop_loss_paused: if not empty_position: if self.close_signal(): self.close_all_options() empty_position = True else: strategy = self.shift() if strategy is not None: self.close_all_options() self.excute(strategy) if empty_position and self.open_signal(): self.excute(self.strategy()) empty_position = False estimated_npv = self.account.estimate_npv() self.sl_npv_high_point = max(self.sl_npv_high_point, estimated_npv) # if self.account.account.loc[self.optionset.eval_date, c.Util.DRAWDOWN]>= 0.0: # self.P_mdd = P_mdd # 止损控制 if (estimated_npv - self.sl_npv_high_point ) / self.sl_npv_high_point < self.P_mdd: self.close_out() self.sl_npv_high_point = estimated_npv self.strategy_npv_paused = drawdown.loc[ self.optionset.eval_date, c.Util.PORTFOLIO_NPV] print(self.optionset.eval_date, 'stop loss', self.sl_npv_high_point, self.P_mdd) self.account.daily_accounting(self.optionset.eval_date, False) base_npv.append(self.index.mktprice_close() / init_index) if not self.optionset.has_next(): break self.optionset.next() self.index.next() stop_loss_paused = True empty_position = True # self.P_mdd = -0.02 continue if stop_loss_paused: strategy_npv = drawdown.loc[self.optionset.eval_date, c.Util.PORTFOLIO_NPV] # 止损后空仓 # if strategy_npv <= self.strategy_npv_paused: if (strategy_npv - self.strategy_npv_paused ) / self.strategy_npv_paused < 0.01: self.account.daily_accounting(self.optionset.eval_date) base_npv.append(self.index.mktprice_close() / init_index) if not self.optionset.has_next(): break self.optionset.next() self.index.next() continue # 止损信号解除 else: order_index = self.account.create_trade_order( self.index, c.LongShort.LONG, self.unit_index, cd_trade_price=c.CdTradePrice.CLOSE) record_index = self.index.execute_order( order_index, slippage=self.slippage) self.account.add_record(record_index, self.index) stop_loss_paused = False self.nbr_stop_loss += 1 print(self.optionset.eval_date, 'stop loss end') # if empty_position and self.open_signal(): # self.excute(self.strategy(cd_price=c.CdPriceType.CLOSE),cd_trade_price=c.CdTradePrice.CLOSE) # empty_position = False # 每日结算 self.account.daily_accounting(self.optionset.eval_date) base_npv.append(self.index.mktprice_close() / init_index) if not self.optionset.has_next(): break self.optionset.next() self.index.next() self.account.account['base_npv'] = base_npv # active_npv = self.df_index[self.df_index[c.Util.DT_DATE] <= self.optionset.eval_date].reset_index(drop=True) # self.account.account['active_npv'] = active_npv[c.Util.AMT_CLOSE] self.account.nbr_timing = self.nbr_timing self.account.nbr_stop_loss = self.nbr_stop_loss return self.account
def __init__(self, df_baseindex, df_option_metrics, df_c1=None, df_all=None, cd_direction_timing='ma', cd_strategy='bull_spread', cd_volatility='close_std', cd_short_ma='ma_5', cd_long_ma='ma_60', cd_std='std_10'): self.min_holding = 20 self.slippage = 0 self.nbr_maturity = 0 self.moneyness_rank = 0 self.cd_trade_price = c.CdTradePrice.VOLUME_WEIGHTED # self.cd_trade_price = c.CdTradePrice.CLOSE if df_c1 is None: dt_start = max(df_option_metrics[c.Util.DT_DATE].values[0], df_baseindex[c.Util.DT_DATE].values[0]) self.end_date = min(df_option_metrics[c.Util.DT_DATE].values[-1], df_baseindex[c.Util.DT_DATE].values[-1]) df_metrics = df_option_metrics[ df_option_metrics[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_baseindex = df_baseindex[ df_baseindex[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) self.invst_portfolio = BaseInstrument( df_baseindex) # e.g., top 50 low volatility index self.invst_portfolio.init() else: dt_start = max(df_option_metrics[c.Util.DT_DATE].values[0], df_baseindex[c.Util.DT_DATE].values[0], df_c1[c.Util.DT_DATE].values[0]) self.end_date = min(df_option_metrics[c.Util.DT_DATE].values[-1], df_baseindex[c.Util.DT_DATE].values[-1], df_c1[c.Util.DT_DATE].values[-1]) df_metrics = df_option_metrics[ df_option_metrics[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_baseindex = df_baseindex[ df_baseindex[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_c1 = df_c1[df_c1[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) df_all = df_all[df_all[c.Util.DT_DATE] >= dt_start].reset_index( drop=True) self.invst_portfolio = BaseFutureCoutinuous( df_c1, df_futures_all_daily=df_all ) # e.g., top 50 low volatility index self.invst_portfolio.init() self.optionset = BaseOptionSet(df_metrics) self.index = BaseInstrument(df_baseindex) self.optionset.init() self.index.init() self.account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.03) self.prepare_timing(df_baseindex) self.cd_direction_timing = cd_direction_timing self.cd_strategy = cd_strategy self.cd_volatility = cd_volatility self.cd_short_ma = cd_short_ma self.cd_long_ma = cd_long_ma self.cd_std = cd_std self.dict_strategy = {} self.nbr_timing = 0 self.nbr_stop_loss = 0 self.nvp_adjustment = 0 self.sl_npv_high_point = 1.0 self.strategy_pause = False
class SyntheticOptionHedgedPortfolio(): def __init__(self, start_date, end_date): self.ttm = 30 self.buywrite = BuyWrite.BUY self.fund = Util.BILLION self.invest_underlying_ratio = 0.7 # self.invest_underlying_ratio = 1 self.slippage = 2 self.start_date = start_date self.end_date = end_date hist_date = start_date - datetime.timedelta(days=40) df_future_c1 = get_dzqh_cf_c1_minute(start_date, end_date, 'if') df_future_c1_daily = get_dzqh_cf_c1_daily(hist_date, end_date, 'if') df_futures_all_daily = get_dzqh_cf_daily( start_date, end_date, 'if') # daily data of all future contracts df_index = get_index_mktdata( start_date, end_date, 'index_300sh') # daily data of underlying index df_index = df_index[df_index[Util.DT_DATE].isin( Util.DZQH_CF_DATA_MISSING_DATES) == False].reset_index(drop=True) # df_index.to_csv('df_index.csv') self.trade_dates = sorted(df_future_c1_daily[Util.DT_DATE].unique()) self.df_vol_1m = Histvol.hist_vol(df_future_c1_daily) # df_parkinson_1m = Histvol.parkinson_number(df_future_c1_daily) self.df_garman_klass = Histvol.garman_klass(df_future_c1_daily) # df_hist_vol = self.df_vol_1m.join(self.df_garman_klass, how='left') # df_hist_vol.to_csv('../../data/df_hist_vol.csv') self.underlying = BaseInstrument(df_data=df_index) self.underlying.init() self.synthetic_option = SytheticOption( df_c1_data=df_future_c1, # df_c1_daily=df_future_c1_daily, df_futures_all_daily=df_futures_all_daily, df_index_daily=df_index) self.synthetic_option.init() self.account = BaseAccount(self.fund, leverage=20.0, rf=0.0) self.trading_desk = Trade() self.init_spot = self.synthetic_option.underlying_state_daily[ Util.AMT_CLOSE] self.df_analysis = pd.DataFrame() def next(self): if self.synthetic_option.is_last_minute(): self.underlying.next() self.synthetic_option.next() def init_portfolio(self, fund): """ Init position """ dt_maturity = self.synthetic_option.eval_date + datetime.timedelta( days=self.ttm) # strike = self.underlying.mktprice_close() strike = self.synthetic_option.mktprice_close() # dt_maturity = self.synthetic_option.eval_date + datetime.timedelta(days=30) self.Option = EuropeanOption(strike, dt_maturity, OptionType.PUT) # self.Option = EuropeanOption(strike, dt_maturity, OptionType.CALL) """ 用第一天的日收盘价开仓标的现货多头头寸 """ underlying_unit = np.floor(fund * self.invest_underlying_ratio / self.underlying.mktprice_close()) order_underlying = self.account.create_trade_order( self.underlying, LongShort.LONG, underlying_unit) execution_record = self.underlying.execute_order( order_underlying, slippage=0, execute_type=ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record(execution_record, self.underlying) self.synthetic_option.amt_option = underlying_unit """ 用第一天的成交量加权均价开仓/调整复制期权头寸 """ vol = self.get_vol() self.delta = self.synthetic_option.get_black_delta(self.Option, vol) synthetic_unit = self.synthetic_option.get_synthetic_unit( self.delta, self.buywrite) self.synthetic_option.synthetic_unit = synthetic_unit if synthetic_unit > 0: long_short = LongShort.LONG else: long_short = LongShort.SHORT order = self.account.create_trade_order(self.synthetic_option, long_short, synthetic_unit) execution_record = self.synthetic_option.execute_order_by_VWAP( order, slippage=0, execute_type=ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record(execution_record, self.synthetic_option) self.account.daily_accounting(self.synthetic_option.eval_date) self.add_additional_to_account() self.disp() self.next() def rebalance_sythetic_option(self): """ Reset and Rebalance sythetic option """ dt_maturity = self.synthetic_option.eval_date + datetime.timedelta( days=self.ttm) # strike = self.underlying.mktprice_close() strike = self.synthetic_option.mktprice_close() self.Option = EuropeanOption(strike, dt_maturity, OptionType.PUT) # self.Option = EuropeanOption(strike, dt_maturity, OptionType.CALL) """ 用成交量加权均价调整复制期权头寸 """ vol = self.get_vol() self.delta = self.synthetic_option.get_black_delta(self.Option, vol) synthetic_unit = self.synthetic_option.get_rebalancing_unit( self.delta, self.Option, vol, self.synthetic_option.mktprice_close(), DeltaBound.NONE, self.buywrite) self.synthetic_option.synthetic_unit += synthetic_unit if synthetic_unit > 0: long_short = LongShort.LONG else: long_short = LongShort.SHORT order = self.account.create_trade_order(self.synthetic_option, long_short, synthetic_unit) execution_record = self.synthetic_option.execute_order_by_VWAP( order, slippage=0, execute_type=ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record(execution_record, self.synthetic_option) self.account.daily_accounting(self.synthetic_option.eval_date) self.add_additional_to_account() self.disp() self.next() return def hedge(self, dt_end=None): id_future = self.synthetic_option.current_state[Util.ID_INSTRUMENT] if dt_end is None: dt_end = self.Option.dt_maturity dt_time_end = datetime.datetime(dt_end.year, dt_end.month, dt_end.day, 15, 00, 0) while self.synthetic_option.has_next( ) and self.synthetic_option.eval_datetime <= dt_time_end: if id_future != self.synthetic_option.current_state[ Util.ID_INSTRUMENT]: long_short = self.account.trade_book.loc[id_future, Util.TRADE_LONG_SHORT] hold_unit = -self.account.trade_book.loc[id_future, Util.TRADE_UNIT] spot = self.synthetic_option.mktprice_close() vol = self.get_vol() self.delta = self.synthetic_option.get_black_delta( self.Option, vol, spot) synthetic_unit = self.synthetic_option.get_synthetic_unit( self.delta, self.buywrite) # 按照移仓换月日的收盘价计算Delta id_c2 = self.synthetic_option.current_state[Util.ID_INSTRUMENT] open_unit = synthetic_unit self.synthetic_option.synthetic_unit += open_unit - hold_unit close_execution_record, open_execution_record \ = self.synthetic_option.shift_contract_by_VWAP(id_c1=id_future, id_c2=id_c2, hold_unit=hold_unit, open_unit=open_unit, long_short=long_short, slippage=self.slippage, execute_type=ExecuteType.EXECUTE_ALL_UNITS ) self.account.add_record(close_execution_record, self.synthetic_option) self.synthetic_option._id_instrument = id_c2 self.account.add_record(open_execution_record, self.synthetic_option) """ 更新当前持仓头寸 """ """ USE SAME UNIT TO SHIFT CONTRACT AND USE CLOSE PRICE TO REBALANCING DELTA CHANGE. """ print(' Relancing after shift contract, ', self.synthetic_option.eval_date) id_future = id_c2 if self.synthetic_option.eval_datetime.time() == datetime.time( 9, 30, 0): self.next() if self.synthetic_option.eval_date == self.synthetic_option.get_next_state_date( ): if not self.if_hedge('5min'): self.next() continue self.rebalancing() if self.synthetic_option.is_last_minute(): self.account.daily_accounting( self.synthetic_option.eval_date) # 该日的收盘结算 self.add_additional_to_account() self.disp() if self.synthetic_option.eval_date == dt_end and self.synthetic_option.is_last_minute( ): self.close_out() self.next() def if_hedge(self, cd): if cd == '1h': """ 1h """ if self.synthetic_option.eval_datetime.minute == 0: return True else: return False elif cd == '10min': """ 10min """ if self.synthetic_option.eval_datetime.minute % 10 == 0: return True else: return False elif cd == '5min': """ 5min """ if self.synthetic_option.eval_datetime.minute % 5 == 0: return True else: return False elif cd == '1min': return True elif cd == 'half_day': if self.synthetic_option.eval_datetime.time() == datetime.time(11, 29, 00) or \ self.synthetic_option.eval_datetime.time() == datetime.time(14, 59, 00): return True else: return False def rebalancing(self): vol = self.get_vol() self.delta = self.synthetic_option.get_black_delta(self.Option, vol) rebalance_unit = self.synthetic_option.get_rebalancing_unit( self.delta, self.Option, vol, self.synthetic_option.mktprice_close(), DeltaBound.WHALLEY_WILLMOTT, self.buywrite) self.synthetic_option.synthetic_unit += rebalance_unit if rebalance_unit > 0: long_short = LongShort.LONG else: long_short = LongShort.SHORT order = self.account.create_trade_order(self.synthetic_option, long_short, rebalance_unit) execution_record = self.synthetic_option.execute_order( order, slippage=self.slippage, execute_type=ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record(execution_record, self.synthetic_option) def close_out(self): while not self.synthetic_option.is_last_minute(): self.next() close_out_orders = self.account.creat_close_out_order() for order in close_out_orders: execution_record = self.account.dict_holding[ order.id_instrument].execute_order( order, slippage=0, execute_type=ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) self.account.daily_accounting(self.synthetic_option.eval_date) self.add_additional_to_account() self.disp() self.synthetic_option.sythetic_unit = 0 """ Final NPV check """ self.df_records = pd.DataFrame(self.account.list_records) total_pnl = self.df_records[Util.TRADE_REALIZED_PNL].sum() final_npv = (self.fund + total_pnl) / self.fund print('calculate final npv from adding up realized pnl ; ', final_npv) def get_vol(self): date = self.synthetic_option.eval_date if date in self.df_vol_1m.index: # vol = self.df_vol_1m.loc[date, Util.AMT_HISTVOL] vol = self.df_garman_klass.loc[self.synthetic_option.eval_date, Util.AMT_GARMAN_KLASS] else: dt1 = Util.largest_element_less_than(port.trade_dates, date) vol = self.df_garman_klass.loc[dt1, Util.AMT_GARMAN_KLASS] # vol = self.df_vol_1m.loc[dt1, Util.AMT_HISTVOL] return vol def add_additional_to_account(self): # self.account.account.loc[ # self.synthetic_option.eval_date, 'underlying_npv_1'] = self.invest_underlying_ratio * self.underlying.mktprice_close() / self.init_spot + 1 - self.invest_underlying_ratio self.account.account.loc[ self.synthetic_option.eval_date, 'underlying_npv'] = self.underlying.mktprice_close( ) / self.init_spot self.account.account.loc[ self.synthetic_option.eval_date, 'underlying_price'] = self.underlying.mktprice_close() self.account.account.loc[ self.synthetic_option.eval_date, 'if_c1'] = self.synthetic_option.mktprice_close() self.account.account.loc[self.synthetic_option.eval_date, 'hedge_position'] \ = - self.account.trade_book[self.account.trade_book[Util.TRADE_LONG_SHORT] == LongShort.SHORT][ Util.TRADE_UNIT].sum() self.account.account.loc[self.synthetic_option.eval_date, 'hedge_ratio'] = \ self.account.account.loc[self.synthetic_option.eval_date, Util.PORTFOLIO_SHORT_POSITION_SCALE] / \ self.account.account.loc[self.synthetic_option.eval_date, Util.PORTFOLIO_LONG_POSITION_SCALE] self.account.account.loc[self.synthetic_option.eval_date, 'pct_margin_unrealized_pnl'] = \ self.account.account.loc[ self.synthetic_option.eval_date, Util.MARGIN_UNREALIZED_PNL] / self.account.init_fund self.account.account.loc[self.synthetic_option.eval_date, 'pct_nonmargin_unrealized_pnl'] = \ self.account.account.loc[ self.synthetic_option.eval_date, Util.NONMARGIN_UNREALIZED_PNL] / self.account.init_fund self.account.account.loc[self.synthetic_option.eval_date, 'pct_realized_pnl'] = \ self.account.account.loc[self.synthetic_option.eval_date, Util.TRADE_REALIZED_PNL] / self.account.init_fund self.account.account.loc[self.synthetic_option.eval_date, 'delta'] = self.delta def save_results(self): self.df_records.to_csv('../../data/trade_records.csv') self.account.account.to_csv('../../data/account.csv') # self.df_hedge_info = pd.DataFrame(self.list_hedge_info) # self.df_hedge_info.to_csv('../../data/hedge_info.csv') self.df_analysis.to_csv('../../data/df_analysis.csv') self.account.trade_book_daily.to_csv('../../data/trade_book_daily.csv') def disp(self): if self.synthetic_option.eval_date != self.underlying.eval_date: print('Date miss matched!') try: average_cost = int(self.account.trade_book[self.account.trade_book[ Util.TRADE_LONG_SHORT] == LongShort.SHORT][ Util.AVERAGE_POSITION_COST].values[0]) except: average_cost = 0 pass print( self.synthetic_option.eval_datetime, self.account.account.loc[self.synthetic_option.eval_date, Util.PORTFOLIO_NPV], self.underlying.mktprice_close() / self.init_spot, # self.account.account.loc[self.synthetic_option.eval_date, 'hedge_position'], # self.synthetic_option.synthetic_unit, int(self.Option.strike), int(self.underlying.mktprice_close()), int(self.synthetic_option.mktprice_close()), average_cost, round(self.delta, 2), round( self.account.account.loc[self.synthetic_option.eval_date, 'hedge_ratio'], 2), # self.account.cash, round( 100 * self.account.account.loc[self.synthetic_option.eval_date, 'pct_margin_unrealized_pnl'], 1), '%', round( 100 * self.account.account.loc[self.synthetic_option.eval_date, 'pct_nonmargin_unrealized_pnl'], 1), '%', round( 100 * self.account.account.loc[self.synthetic_option.eval_date, 'pct_realized_pnl'], 1), '%', self.underlying.eval_date, ) def reset_option_maturity(self, dt_maturity=None): if dt_maturity is None: dt_maturity = self.synthetic_option.eval_date + datetime.timedelta( days=self.ttm) self.Option.dt_maturity = dt_maturity def reset_option_strike(self): strike = self.synthetic_option.mktprice_close() self.Option.strike = strike def analysis(self, dt_start, dt_end): """ Replicate Period Result Analysis """ self.df_records = pd.DataFrame(self.account.list_records) analysis = pd.Series() df_hedge_records = self.df_records[ (self.df_records[Util.ID_INSTRUMENT] != 'index_300sh') & (self.df_records[Util.DT_TRADE] >= dt_start) & (self.df_records[Util.DT_TRADE] <= dt_end)] init_stock_value = self.account.account.loc[ dt_start, Util.PORTFOLIO_TRADES_VALUE] init_stock_price = \ self.underlying.df_data[self.underlying.df_data[Util.DT_DATE] == dt_start][Util.AMT_CLOSE].values[0] terminal_stock_price = \ self.underlying.df_data[self.underlying.df_data[Util.DT_DATE] == dt_end][Util.AMT_CLOSE].values[0] replicate_pnl = df_hedge_records[Util.TRADE_REALIZED_PNL].sum() option_payoff = self.synthetic_option.amt_option * max( init_stock_price - terminal_stock_price, 0) replicate_cost = replicate_pnl - option_payoff replicate_cost_future = replicate_pnl - self.synthetic_option.amt_option * max( self.Option.strike - terminal_stock_price, 0) pct_replicate_cost = replicate_cost / init_stock_value pct_replicate_pnl = replicate_pnl / init_stock_value transaction_cost = df_hedge_records[Util.TRANSACTION_COST].sum() init_portfolio_value = self.account.account.loc[dt_start, Util.PORTFOLIO_VALUE] trade_value = np.abs(df_hedge_records[Util.TRADE_BOOK_VALUE]).sum() ratio = trade_value / init_portfolio_value pct_underlying_pnl = (terminal_stock_price - init_stock_price) / init_stock_price analysis['ratio'] = ratio analysis['dt_start'] = dt_start analysis['dt_end'] = dt_end analysis['init_stock_value'] = init_stock_value analysis['replicate_pnl'] = replicate_pnl analysis['option_payoff'] = option_payoff analysis['replicate_cost_spot'] = replicate_cost analysis['replicate_cost_future'] = replicate_cost_future analysis['pct_replicate_cost'] = pct_replicate_cost analysis['pct_replicate_pnl'] = pct_replicate_pnl analysis['pct_underlying_pnl'] = pct_underlying_pnl analysis['transaction_cost'] = transaction_cost analysis['dt_maturity'] = self.Option.dt_maturity self.df_analysis = self.df_analysis.append(analysis, ignore_index=True)
class NakedShort(object): def __init__(self, df_metrics, df_baseindex=None, cd_strategy='naked_put', id_baseindex=c.Util.STR_INDEX_300SH, cd_marutity_days=3): self.start_date = df_metrics[c.Util.DT_DATE].values[0] self.end_date = df_metrics[c.Util.DT_DATE].values[-1] if df_baseindex is None: df_baseindex = get_data.get_index_mktdata(self.start_date, self.end_date, c.Util.STR_INDEX_300SH) self.min_holding = 20 self.init_fund = c.Util.BILLION self.slippage = 0 self.m = 1 # 期权notional倍数 if cd_strategy == 'short_straddle': self.m = 0.5 self.moneyness_rank = -4 self.nbr_maturity = 0 self.cd_trade_price = c.CdTradePrice.VOLUME_WEIGHTED self.account = BaseAccount(init_fund=c.Util.BILLION, leverage=1.0, rf=0.03) self.optionset = BaseOptionSet(df_metrics) self.optionset.init() self.index = BaseInstrument(df_baseindex) self.index.init() self.cd_strategy = cd_strategy self.cd_maturity_days = cd_marutity_days self.init_index = self.index.mktprice_close() # w.start() # TODO: 统一 check dt_first; 将base_npv写入accout def close_signal(self): dt_maturity = None for option in self.account.dict_holding.values(): if isinstance(option, BaseOption) and option is not None: dt_maturity = option.maturitydt() break # t = w.tdayscount(self.optionset.eval_date.strftime("%Y-%m-%d"), dt_maturity.strftime("%Y-%m-%d"), "").Data[0][0] t = c.QuantlibUtil.get_business_between(self.optionset.eval_date, dt_maturity) if t <= self.cd_maturity_days: # if (dt_maturity - self.optionset.eval_date).days <= self.cd_maturity_days: return True else: return False def close_out(self): close_out_orders = self.account.creat_close_out_order( cd_trade_price=c.CdTradePrice.CLOSE) for order in close_out_orders: execution_record = self.account.dict_holding[order.id_instrument] \ .execute_order(order, slippage=self.slippage, execute_type=c.ExecuteType.EXECUTE_ALL_UNITS) self.account.add_record( execution_record, self.account.dict_holding[order.id_instrument]) def close_all_options(self): for option in self.account.dict_holding.values(): if isinstance(option, BaseOption): order = self.account.create_close_order( option, cd_trade_price=self.cd_trade_price) record = option.execute_order(order, slippage=self.slippage) self.account.add_record(record, option) def strategy(self): if self.cd_strategy == 'short_straddle': return self.short_straddle() elif self.cd_strategy == 'short_put': return self.short_put() elif self.cd_strategy == 'short_call': return self.short_call() def short_straddle(self): maturity1 = self.optionset.select_maturity_date( nbr_maturity=self.nbr_maturity, min_holding=self.min_holding) list_atm_call, list_atm_put = self.optionset.get_options_list_by_moneyness_mthd1( moneyness_rank=self.moneyness_rank, maturity=maturity1, cd_price=c.CdPriceType.OPEN) atm_call = self.optionset.select_higher_volume(list_atm_call) atm_put = self.optionset.select_higher_volume(list_atm_put) if atm_call is None or atm_put is None: return else: return [atm_call, atm_put] def short_put(self): maturity1 = self.optionset.select_maturity_date( nbr_maturity=self.nbr_maturity, min_holding=self.min_holding) list_atm_call, list_atm_put = self.optionset.get_options_list_by_moneyness_mthd1( moneyness_rank=self.moneyness_rank, maturity=maturity1, cd_price=c.CdPriceType.OPEN) atm_put = self.optionset.select_higher_volume(list_atm_put) if atm_put is None: return else: return [atm_put] def short_call(self): maturity1 = self.optionset.select_maturity_date( nbr_maturity=self.nbr_maturity, min_holding=self.min_holding) list_atm_call, list_atm_put = self.optionset.get_options_list_by_moneyness_mthd1( moneyness_rank=self.moneyness_rank, maturity=maturity1, cd_price=c.CdPriceType.OPEN) atm_call = self.optionset.select_higher_volume(list_atm_call) if atm_call is None: return else: return [atm_call] def excute(self, strategy): if strategy is None: return True else: pv = self.account.portfolio_total_value for option in strategy: unit = np.floor( np.floor(pv / option.strike()) / option.multiplier()) * self.m order = self.account.create_trade_order( option, c.LongShort.SHORT, unit, cd_trade_price=self.cd_trade_price) record = option.execute_order(order, slippage=self.slippage) self.account.add_record(record, option) return False def back_test(self): empty_position = True index_npv = [] while self.optionset.eval_date <= self.end_date: # print(optionset.eval_date) # if self.account.cash <= 0: break if self.optionset.eval_date >= self.end_date: # Final close out all. self.close_out() self.account.daily_accounting(self.optionset.eval_date) index_npv.append(self.index.mktprice_close() / self.init_index) break # 平仓 if not empty_position and self.close_signal(): self.close_all_options() empty_position = True # 开仓 if empty_position: empty_position = self.excute(self.strategy()) self.account.daily_accounting(self.optionset.eval_date) index_npv.append(self.index.mktprice_close() / self.init_index) # print(self.optionset.eval_date,self.account.account.loc[self.optionset.eval_date,c.Util.PORTFOLIO_NPV]) if not self.optionset.has_next(): break self.optionset.next() self.index.next() self.account.account['index_npv'] = index_npv