예제 #1
0
    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
        }
예제 #2
0
    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
        }
예제 #3
0
 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'])
             },
     }
예제 #4
0
    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()
예제 #5
0
    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()
예제 #6
0
    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
예제 #7
0
    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()
예제 #8
0
 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
예제 #9
0

#################################################################################

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[
예제 #10
0
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")
예제 #11
0
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)
예제 #12
0
    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)
예제 #13
0
    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()