def get_implied_risk_free(self, future_quote: Quote, strike_price: int, call_quote: Quote, put_quote: Quote) -> dict: """ TODO: 根据put-call parity计算“隐含无风险收益率” Return: 下述方程中分别解出risk_free之解 last 成交价计算:call_last - put_last = (future_last - strike) * exp(-ttm * risk_free) mid 中间价计算:call_mid - put_mid = (future_mid - strike) * exp(-ttm * risk_free) long_call 买call、卖put、空期货策略:call_ask - put_bid = (future_bid - strike) * exp(-ttm * risk_free) short_call 买put、卖call、多期货策略:call_bid - put_ask = (future_ask - strike) * exp(-ttm * risk_free) """ ttm = (time_to_datetime(call_quote.expire_datetime) - time_to_datetime(future_quote.datetime)).days # 到期日 call_quote_mid = (call_quote.ask_price1 + call_quote.bid_price1) / 2 put_quote_mid = (put_quote.ask_price1 + put_quote.bid_price1) / 2 future_mid = (future_quote.ask_price1 + future_quote.bid_price1) / 2 risk_free_last = np.log( (call_quote.last_price - put_quote.last_price) / (future_quote.last_price - strike_price)) / (-ttm) * 365 risk_free_mid = np.log((call_quote_mid - put_quote_mid) / (future_mid - strike_price)) / (-ttm) * 365 risk_free_long_call = np.log( (call_quote.ask_price1 - put_quote.bid_price1) / (future_quote.bid_price1 - strike_price)) / (-ttm) * 365 risk_free_short_call = np.log( (call_quote.bid_price1 - put_quote.ask_price1) / (future_quote.ask_price1 - strike_price)) / (-ttm) * 365 return { 'last': risk_free_last, 'mid': risk_free_mid, 'long_call': risk_free_long_call, 'short_call': risk_free_short_call }
def get_parity_residual(self, future_quote: Quote, strike_price: float, call_quote: Quote, put_quote: Quote, risk_free: float = 0.0208) -> dict: """ TODO: 计算折溢价 Return: premium_last 成交价计算:call_last - put_last - (future_last - strike) * exp(-ttm * risk_free) premium_mid 中间价计算:call_mid - put_mid - (future_mid - strike) * exp(-ttm * risk_free) premium_call < 0: 买call、卖put、空期货策略:call_ask - put_bid - (future_bid - strike) * exp(-ttm * risk_free) premium_put < 0: 买put、卖call、多期货策略:-(call_bid - put_ask - (future_ask - strike) * exp(-ttm * risk_free)) """ ttm = (time_to_datetime(future_quote.expire_datetime) - time_to_datetime(future_quote.datetime)).days / 365 # 到期日 call_quote_mid = (call_quote.ask_price1 + call_quote.bid_price1) / 2 put_quote_mid = (put_quote.ask_price1 + put_quote.bid_price1) / 2 future_mid = (future_quote.ask_price1 + future_quote.bid_price1) / 2 residual_last = call_quote.last_price - put_quote.last_price - \ (future_quote.last_price - strike_price) * np.exp(-ttm*risk_free) residual_mid = call_quote_mid - put_quote_mid - \ (future_mid - strike_price) * np.exp(-ttm*risk_free) call_premium = call_quote.ask_price1 - put_quote.bid_price1 - \ (future_quote.bid_price1 - strike_price) * np.exp(-ttm*risk_free) #long call 策略的理论到行权日的年化收益率 long_call_cost = call_quote.bid_price1 * call_quote.volume_multiple + self.get_margin_rate( put_quote) + self.get_margin_rate(future_quote) long_call_return = max( 0, -call_premium * call_quote.volume_multiple / long_call_cost) / ttm put_premium = -(call_quote.bid_price1 - put_quote.ask_price1 - (future_quote.ask_price1 - strike_price) * np.exp(-ttm * risk_free)) long_put_cost = put_quote.bid_price1 * put_quote.volume_multiple + self.get_margin_rate( call_quote) + self.get_margin_rate(future_quote) long_put_return = max( 0, -put_premium * put_quote.volume_multiple / long_put_cost) / ttm return { 'tq_time': future_quote.datetime, 'premium_last': residual_last, 'premium_mid': residual_mid, 'premium_call': call_premium, 'premium_put': put_premium, 'long_call_cost': long_call_cost, 'long_call_return': long_call_return, 'long_put_cost': long_put_cost, 'long_put_return': long_put_return, 'ttm': ttm, 'rf': risk_free, 'strike': strike_price }
def triangle(self, data: pd.DataFrame): data.sort_values(by='high', ascending=False) self.keypoint['high'] = { 1: {'value': data.iloc[0]['high'], 'dt': time_to_datetime(data.iloc[0]['datetime']) }, 2: {'value': data.iloc[1]['high'], 'dt': time_to_datetime(data.iloc[1]['datetime']) }, 3: {'value': data.iloc[3]['high'], 'dt': time_to_datetime(data.iloc[3]['datetime']) }, }
def run(self): # 局部变量 open_order: Order # 开仓委托单 close_order: Order # 平仓委托单 remote_order: Order # 经天勤从服务器发来的委托单 remote_order_id: str remote_trade: Trade # 成交记录,来自远端 remote_trade_id: str try: while True: if not self.api.wait_update(deadline=time.time() + self.timeout): print('未在超时限制内接收到数据。') if self.api.is_changing(self.tq_quote, ['ask_price1', 'bid_price1']): # tq_quote 中的信息 self.price_ask = self.tq_quote.ask_price1 # 当前卖一价 self.price_bid = self.tq_quote.bid_price1 # 当前买一价 self.remote_datetime = time_to_datetime(self.tq_quote.datetime) # 当前 datetime # 非交易时间 if not self.is_trading_time(self.remote_datetime): self.logger.info(f'{self.remote_datetime}, 【状态】, ——非交易时间') continue # log 当前状态 self.log_status() # 处理委托单回报 if self.api.is_changing(self.tq_order): for remote_order_id, remote_order in self.tq_order.items(): self.handle_orders(remote_order) # 开仓 if self.is_open_condition(): order_open = self.api.insert_order(symbol=self.symbol, direction='BUY', offset='OPEN', volume=self._settings['volume_per_order'], limit_price=self.price_bid ) self.log_order(order_open) except BacktestFinished: self.api.close() exit()
def processKline(self, kline): # 成交量 trade_volume = kline["volume"] # 增仓量 net_incr_volume = kline["close_oi"] - kline["open_oi"] # 结算价 close = kline["close"] # 日期 datetime = kline["datetime"] data = { 'datetime': datetime, 'trade_volume': trade_volume, 'net_incr_volume': net_incr_volume, 'close': close, } staticData = pd.DataFrame(data) staticData.to_csv("./download/staticData.csv") for index, row in staticData.iterrows(): staticData.loc[index, 'datetime'] = tafunc.time_to_datetime(row['datetime']) x = staticData['datetime'] y1 = staticData['trade_volume'] y2 = staticData['net_incr_volume'] y3 = staticData['close'] # 设置图形大小 plt.figure(figsize=(20, 8), dpi=80) plt.subplot(311) plt.ylabel("trade_volume") plt.plot(x, y1) plt.subplot(312) plt.ylabel("net_incr_volume") plt.plot(x, y2) plt.subplot(313) plt.ylabel("close") plt.plot(x, y3) plt.show()
def __init__(self, api: TqApi, future_product_id: str = None, option_product_id: str = None, underlying_future_id: str = None): """ Args: api (TqApi): 天勤Api future_product_id (str): 期货product_id option_product_id (str): 期权product_id underlying_future_id (str): 期货代码查期权 """ self._api = api self._now = time_to_datetime( api._backtest._current_dt ) if api._backtest is not None else datetime.now() self._future_prod_id = future_product_id self._option_prod_id = option_product_id self._future_infoes = self._init_future_infoes( ) if underlying_future_id is None else [ self._api.get_quote(underlying_future_id) ] self.future_delivery_dates = self._fetch_delivery_dates() self._opt_infoes = self._init_opt_infoes( ) if underlying_future_id is None else self._get_opt_infoes_by_underlying( underlying_future_id) self.strike_dates = self._fetch_strike_dates() self.future_opt_matched_dates = list(self.future_delivery_dates & self.strike_dates) # 取期货期权同到期日 self.future_opt_matched_dates.sort() self.strike_dates = list(self.strike_dates) self.strike_dates.sort() self.margin_rates = dict() # 期权保证金率dict
def run(self): try: while True: if not self.api.wait_update(deadline=time.time() + self.timeout): print('未在超时限制内接收到数据。') if self.api.is_changing(self.candlestick.iloc[-1], 'datetime'): # candlestick columns # 'datetime', 'id', 'open', 'high', 'low', 'close', 'volume', 'open_oi', 'close_oi', # 'symbol', 'duration' self.logger.info(time_to_datetime(self.candlestick.iloc[-1]['datetime'])) self.data = self.candlestick.loc[:, ['datetime', 'high', 'low']].iloc[-self.period:] # self.triangle(self.data) except BacktestFinished: print(self.candlestick) print('='*20) # print(self.keypoint) print('=' * 20) self.draw() self.api.close() exit()
def is_finish_order(self) -> bool: order_flow = self._order_factory.get_order_flow() trade_price = [] is_finish = True for order in order_flow: logger.info("订单Id:", order.order_id, order.instrument_id, order.direction, order.offset, " vol_ori:", order.volume_orign, " vol_left:", order.volume_left, " is_dead:", order.is_dead, " is_error: ", order.is_error, " is_online:", order.is_online, "last_msg:", order.last_msg) if not order.is_dead: is_finish = False # 挂单超时 撤单 self._order_factory.cancel_over_time( order, tafunc.time_to_datetime(self._quote.datetime), datetime.timedelta(seconds=self._order_vilid_time)) trade_price.append(order.trade_price) # 可能部分成交 if not pd.isna(pd.Series(trade_price, dtype='float64').mean()): self.state["last_price"] = self._quote["last_price"] self.state["position"] = self._pos.pos return is_finish
################################################################################# df_long = reset_df_long(quote, GRID_AMOUNT, grid_region_long, grid_volume_long) df_short = reset_df_short(quote, GRID_AMOUNT, grid_region_short, grid_volume_short) ################################################################################# while True: api.wait_update() ################################################################################# if api.is_changing(ticks): now = time_to_datetime(ticks.iloc[-1].datetime) if (now.hour >= 9 and now.hour < 15) or (now.hour >= 21 and now.hour < 23): if is_clear_all1: api.insert_order(symbol, "SELL", close, position.pos_long, quote.bid_price1 - 2) is_clear_all1 = False if is_clear_all2: api.insert_order(symbol, "BUY", close, position.pos_short, quote.ask_price1 + 2) is_clear_all2 = False ################################################################################# if api.is_changing(quote): df = pd.DataFrame(api.get_order().values()) if not df.empty: df_long_open = df[
def process_data(data: DataFrame): data['datetime'] = data['datetime'].apply(lambda time: time_to_datetime(time)) data['local_symbol'] = data['symbol'].apply(lambda symbol: ".".join(reversed(symbol.split(".")))) data['type'] = "bar" return data.to_dict("index")
if __name__ == '__main__': model = xgb.XGBClassifier() model.load_model('../model_repo/allset_portion_05.20210404.0.7.model') # klines = api.get_kline_serial(RawList.realtime_tq_symbols, 300, 1000) # print(klines) while True: kline_list = [] for tmp_symbol in RawList.realtime_tq_symbols: tmp_kline = api.get_kline_serial(tmp_symbol, 300, 1000) kline_list.append(tmp_kline) api.wait_update() data_sequence = [] result_json_obj = {'data': []} for klines in kline_list: kline_time = tafunc.time_to_datetime(klines.iloc[-1]["datetime"]) print(kline_time) item_unit = pd.DataFrame() item_unit['datetime'] = pd.to_datetime( klines['datetime']) + pd.Timedelta('08:00:00') item_symbol_raw = klines.iloc[-1]["symbol"] item_unit['close'] = klines['close'] vc_real, v_prob_real, v_prone_real = get_predict_result( model, item_symbol_raw, item_unit) # print(vc_real, v_prob_real, v_prone_real) tmp_json_unit = get_display_json_and_order(item_symbol_raw, item_unit, vc_real, v_prob_real, v_prone_real)
def handle_orders(self, order: Order): """ 处理委托单回报。 根据 Order.status, Order.volume_orign 和 Order.volume_left 判断: 1, volume_left = 0 全部成交 2, 0 < volume_left < volume_orign 2A, status = FINISHED 部分撤单 2B, status = ALIVE 部分成交 3, volume_left = volume_orign 3A, status = FINISHED 全部撤单 3B, status = ALIVE 报单 :param order: :return: """ db_order: BacktestOrder db_trade: BacktestTrade new_status: str if order.volume_left == 0: if order.status == 'FINISHED': new_status = '全部成交' else: raise RuntimeError('不能理解的委托单状态: order.volume_left = 0 and order.status = ALIVE') elif 0 < order.volume_left < order.volume_orign: if order.status == 'FINISHED': new_status = '部分撤单' else: new_status = '部分成交' else: if order.status == 'FINISHED': new_status = '全部撤单' else: new_status = '报单' if new_status == '报单': try: # 存在报单回报信息滞后的情况。所以还不能触发异常。 db_session.query(BacktestOrder).filter_by(order_id=order.order_id).one() # if db_order: # raise RuntimeError('新报单不应该在数据库中有记录,但是在数据库中查到了。') except NoResultFound: db_session.add( BacktestOrder( insert_datetime=time_to_datetime(order.insert_date_time), order_id=order.order_id, direction=order.direction, offset=order.offset, price=order.limit_price, volume_orign=order.volume_orign, volume_left=order.volume_orign, status='ALIVE' ) ) db_session.commit() self.log_accept(order) if new_status == '全部成交' or new_status == '部分成交': # 修正 order 状态 try: db_order = db_session.query(BacktestOrder).filter_by(order_id=order.order_id).one() db_order.status = new_status db_order.last_datetime = self.remote_datetime db_order.volume_left = order.volume_left db_session.commit() except NoResultFound: # 有报单即成交的可能 db_session.add( BacktestOrder( insert_datetime=time_to_datetime(order.insert_date_time), last_datetime=self.remote_datetime, order_id=order.order_id, direction=order.direction, offset=order.offset, price=order.limit_price, volume_orign=order.volume_orign, volume_left=order.volume_left, status=new_status ) ) db_session.commit() db_order = db_session.query(BacktestOrder).filter_by(order_id=order.order_id).one() self.log_accept(order) # 查询 trade for _, trade in order.trade_records.items(): # 新 trade if not self.get_trade(trade.trade_id): try: db_trade = db_session.query(BacktestTrade).filter_by(trade_id=trade.trade_id).one() if db_trade: raise RuntimeError('新成交记录不应该在数据库中有记录,但是在数据库中查到了。') except NoResultFound: db_session.add( BacktestTrade( backtest_order_id=db_order.id, order_id=order.order_id, trade_id=trade.trade_id, datetime=time_to_datetime(trade.trade_date_time), exchange_trade_id=trade.exchange_trade_id, exchange_id=trade.exchange_id, instrument_id=trade.instrument_id, direction=trade.direction, offset=trade.offset, price=trade.price, volume=trade.volume ) ) db_session.commit() self.log_fill(order, trade.trade_id) if new_status == '全部撤单' or new_status == '部分撤单': try: db_order = db_session.query(BacktestOrder).filter_by(order_id=order.order_id).one() db_order.status = new_status db_order.last_datetime = self.remote_datetime db_order.volume_left = order.volume_left db_session.commit() except NoResultFound: print('ERROR in 撤单', order.order_id, '未在数据库中找到') self.api.close() exit() self.log_cancel(order)
def run(self): """ 策略运行。 :return: """ # 局部变量 open_order: Order # 开仓委托单 close_order: Order # 平仓委托单 remote_order: Order # 经天勤从服务器发来的委托单 remote_order_id: str remote_trade: Trade # 成交记录,来自远端 remote_trade_id: str try: while True: if not self.api.wait_update(deadline=time.time() + self.timeout): self.log_no_data() if self.api.is_changing(self.tq_quote, ['ask_price1', 'bid_price1']): # tq_quote 中的信息 self.price_ask = self.tq_quote.ask_price1 # 当前卖一价 self.price_bid = self.tq_quote.bid_price1 # 当前买一价 self.remote_datetime = time_to_datetime( self.tq_quote.datetime) # 当前 datetime # 非交易时间 if not self.is_trading_time(self.remote_datetime): self.logger.info( f'{self.remote_datetime}, 【状态】, ——非交易时间') continue # log 当前状态 self.log_status() # 临近收盘,平仓 if self.is_about_to_close(self.remote_datetime): self.close_before_market_close() # 处理委托单回报 if self.api.is_changing(self.tq_order): for remote_order_id, remote_order in self.tq_order.items( ): self.handle_orders(remote_order) # 开仓 # 1、总持仓(多仓 + 空仓)手数 < 【策略】最大持仓手数; # 2、买一价挂单手数 + 卖一价挂单手数 + 每笔委托手数 < 【策略】每价位手数 # 3、根据 均线?MACD?判断多空。 if self.is_open_condition(): order_open = self.api.insert_order( symbol=self.symbol, direction='BUY', offset='OPEN', volume=self.settings['volume_per_order'], limit_price=self.price_bid) self.log_order(order_open) except BacktestFinished: self.api.close() exit()