예제 #1
0
    def handle_bar(self, event_market):
        print("-- this is handle_bar() method @ {0}".format(event_market.dt))

        # 取当前bar的持仓情况
        available_position_dict = {}
        for position in self.context.bar_position_data_list:
            available_position_dict[position.symbol] = position

        # 当前bar的具体时间,时间str转换成int,方便后面取数据时过滤
        current_date_int = date_str_to_int(event_market.dt)
        cur_start_date = to_datetime(event_market.dt) - Timedelta(days=40)
        cur_start_date_int = date_str_to_int(str(cur_start_date)[:10])

        # 循环遍历股票池
        for stock in self.universe:
            # 取当前股票的数据
            close_price = self.get_data.get_market_data(
                self.context.daily_data,
                stock_code=[stock],
                field=["close"],
                start=cur_start_date_int,
                end=current_date_int)
            close_array = array(close_price)
            if len(close_array) > 0:
                # 利用talib计算MA
                ma5 = talib.MA(array(close_price), timeperiod=5)
                ma20 = talib.MA(array(close_price), timeperiod=20)

                # 过滤因为停牌没有数据
                if current_date_int in close_price.keys() and (not isnull(
                        ma5[-1])) and (not isnull(ma20[-1])):
                    # 如果5日均线突破20日均线,并且没有持仓,则买入这只股票100股,委托价为当前bar的收盘价
                    if ma5[-1] > ma20[
                            -1] and stock not in available_position_dict.keys(
                            ):
                        comments = "限价买入"
                        self.buy(event_market.dt, self.account[0]['name'],
                                 stock, close_array[-1], 100, False, comments)

                        print("发出委托买入股票 {0} {1} 股,委托价为 {2},资金账号为 {3} ".format(
                            stock, 100, close_array[-1],
                            self.account[0]['name']))

                    # 如果20日均线突破5日均线,并且有持仓,则卖出这只股票100股,委托价为当前bar的收盘价
                    elif ma5[-1] < ma20[
                            -1] and stock in available_position_dict.keys():
                        pos_abs = abs(available_position_dict[stock].volume)
                        comments = "限价卖出"
                        self.sell(event_market.dt, self.account[0]['name'],
                                  stock, close_array[-1], pos_abs, False,
                                  comments)

                        print("发出委托卖出股票 {0} {1} 股,委托价为 {2},资金账号为 {3} ".format(
                            stock, pos_abs, close_array[-1],
                            self.account[0]['name']))
예제 #2
0
    def update_bar(self, event_market):
        """新出现市场事件 event_bar 时的监听/回调函数,在回测模式下,模拟委托单的撮合动作"""
        print("this is update_bar() @ {0}".format(event_market.dt))

        self.bar_index += 1
        if self.run_mode == RunMode_BACKTESTING:  # 回测模式下的报单反馈
            # 处理股票今日持仓的冻结数量(股票当日买入不能卖出)
            self.update_position_frozen(event_market.dt)

            # 取最新的市场数据
            cur_mkt_data = {'low': {}, 'high': {}, 'open': {}}
            for uii in self.universe:
                cur_date = date_str_to_int(event_market.dt)
                cur_mkt_data['low'][uii] = self.context.daily_data['low'].loc[
                    uii][cur_date]
                cur_mkt_data['high'][uii] = self.context.daily_data[
                    'high'].loc[uii][cur_date]
                cur_mkt_data['open'][uii] = self.context.daily_data[
                    'open'].loc[uii][cur_date]
            self.cross_limit_order(event_market,
                                   cur_mkt_data)  # 处理委托时间早于当前bar的未成交限价单
            self.cross_stop_order(event_market,
                                  cur_mkt_data)  # 处理委托时间早于当前bar的未成交止损单
        else:  # live模式下的报单反馈(未完成)
            pass

        self.handle_bar(event_market)
        self.update_bar_info(event_market)
예제 #3
0
    def init_strategy(self):       # 父类中有定义,但是没有实现,此处实现
        # 设置运行模式,回测或者交易
        self.run_mode = RunMode_BACKTESTING
        self.start = date_str_to_int("20050104")     # 设置回测起止时间
        self.end = date_str_to_int("20060222")
        self.interval = "d"       # 设置运行周期
        self.account = {"acc0": 1000000, "acc1": 1000}     # 设置回测资金账号及初始资金量
        self.benchmark = "000300.SH"        # 设置回测基准
        self.rights_adjustment = RightsAdjustment_NONE    # 设置复权方式
        self.get_data = GetMongoData()

        # 设置股票池
        self.universe = ['000001.SZ', '000002.SZ', '600000.SH', '600001.SH']
        # self.context.logger.info(self.universe)

        # 回测滑点设置
        self.set_slippage_type = 'FIX'
예제 #4
0
    def init_strategy(self):  # 父类中有定义,但是没有实现,此处实现
        # 设置运行模式,回测或者交易
        self.gateway = 'ctp'
        self.run_mode = RunMode_BACKTESTING
        self.start = date_str_to_int("20050104")  # 设置回测起止时间
        self.end = date_str_to_int("20060222")
        # self.interval = "d"  # 设置运行周期
        self.account = [{
            'name': 'acc0',
            'equity': 1000000
        }, {
            'name': 'acc1',
            'equity': 1000
        }]  # 设置资金账号及初始资金量
        self.benchmark = "000300.SH"  # 设置回测基准
        # self.rights_adjustment = RightsAdjustment_NONE  # 设置复权方式

        # 设置股票池
        # self.universe = ['000001.SZ', '000002.SZ', '600000.SH', '600001.SH']
        self.universe = ['000001.SZ', '600000.SH']

        # 组合中所有合约的持仓量初始化
        self.pos = {}
        for ss in self.universe:
            self.pos[ss] = 0

        # 回测滑点设置
        self.set_slippage(stock_type=Product_STOCK,
                          slippage_type=SLIPPAGE_FIX,
                          value=0.01)

        # 回测股票手续费和印花税,卖出印花税,千分之一;开仓手续费,万分之三;平仓手续费,万分之三,最低手续费,5元
        # 沪市,卖出有万分之二的过户费,加入到卖出手续费
        self.set_commission(stock_type=Product_STOCK_SH,
                            tax=0.001,
                            open_commission=0.0003,
                            close_commission=0.0003,
                            close_today_commission=0,
                            min_commission=5)
        # 深市不加过户费
        self.set_commission(stock_type=Product_STOCK_SZ,
                            tax=0.001,
                            open_commission=0.0003,
                            close_commission=0.0005,
                            close_today_commission=0,
                            min_commission=5)
예제 #5
0
    def init_strategy(self,
                      log_full_path: list,
                      color_log=True,
                      start_str='20180101',
                      end_str='20200222'):  # 确定参数值
        self.gateway = 'ctp'
        self.run_mode = RunMode.BACKTESTING
        self.start = date_str_to_int(start_str)
        self.end = date_str_to_int(end_str)
        self.account = [{'name': 'acc0', 'equity': 200000}]
        self.benchmark = "000300.SH"
        # self.rights_adjustment = RightsAdjustment.NONE  # 只在画 K 线时有效,对策略运行无影响

        # 动态股票池(沪深300指数成分股)
        self.is_universe_dynamic = '000300.SH'

        # 固定股票池
        # self.is_universe_dynamic = False
        # self.universe = ['000562.SZ', '600710.SH', '600757.SH', '600761.SH']

        # 设置回测滑点
        self.set_slippage(symbol_type=Product.STOCK.value,
                          slippage_type=Slippage.FIX,
                          value=0.01)

        # 设置沪市交易成本
        self.set_commission(symbol_type=Product.STOCK_SH,
                            tax=0.001,
                            open_commission=0.0003,
                            close_commission=0.0005,
                            close_today_commission=0,
                            min_commission=5)
        # 设置深市交易成本
        self.set_commission(symbol_type=Product.STOCK_SZ,
                            tax=0.001,
                            open_commission=0.0003,
                            close_commission=0.0003,
                            close_today_commission=0,
                            min_commission=5)
        if not color_log:
            self.context.logger = Logger(log_full_path[0])
        else:
            self.context.logger = ColorLogger(log_full_path[0] +
                                              log_full_path[1])  # color log
예제 #6
0
    def get_all_market_data(self,
                            stock_code=None,
                            field=None,
                            start="",
                            end="",
                            interval=Interval.DAILY):
        """从mongodb取数据"""

        if interval == Interval.DAILY:
            db_name = MongoDbName.MARKET_DATA_DAILY.value
            if isinstance(start, str):
                start = date_str_to_int(start)
                end = date_str_to_int(end)
            values = []
            colum = {"_id": 0, "timetag": 1}
            for i in field:
                colum[i] = 1
            for stock in stock_code:
                self.conn.check_connected()
                stock_market_data = self.conn.select_colum(
                    db_name=db_name,
                    table=stock,
                    value={"timetag": {
                        "$gte": start,
                        "$lte": end
                    }},
                    colum=colum)
                stock_market_data_list = list(stock_market_data)
                if stock_market_data_list:
                    df = pd.DataFrame(stock_market_data_list)
                    values.append(
                        pd.DataFrame(df[field].values,
                                     index=df['timetag'],
                                     columns=field))
            market_data = pd.concat(values, keys=stock_code)
        else:
            market_data = None

        return market_data
예제 #7
0
    def handle_bar(self, bar):
        self.context.logger.info("\n遇到 EventMarket 类事件,回调函数 MaStrategy.handle_bar 按最新市场数据计算一次")

        # 取当前bar的持仓情况
        available_position_dict = {}
        for position in Context.bar_position_data_list:
            available_position_dict[position.instrument + "." + position.exchange] = position.position

        # 当前bar的具体时间
        current_date = timestamp_to_datetime(timestamp=self.timestamp, format="%Y-%m-%d")

        # 时间str转换成int,方便后面取数据时过滤
        current_date_int = date_str_to_int(current_date)
        print("开始日期 {0}, 当前日期 {1}".format(self.start, current_date))

        # 循环遍历股票池
        for stock in self.universe:
            # 取当前股票的收盘价
            close_price = self.get_data.get_market_data(Context.daily_data,
                                                        stock_code=[stock],
                                                        field=["close"],
                                                        end=current_date)
            close_array = array(close_price)
            if len(close_array) > 0:
                # 利用talib计算MA
                ma5 = talib.MA(array(close_price), timeperiod=5)
                ma20 = talib.MA(array(close_price), timeperiod=20)
                # print(type(close_price.keys()))

                # 计算交易信号是否被触发
                if current_date_int in close_price.keys():
                    # 如果5日均线突破20日均线,并且没有持仓,则买入这只股票100股,委托价为当前bar的收盘价
                    if ma5[-1] > ma20[-1] and stock not in available_position_dict.keys():
                        order_data = OrderData(symbol=stock,
                                               exchange=,
                                               orderid=,
                                               type=OrderType_LIMIT,
                                               direction=Direction_LONG,
                                               offset=Offset_OPEN,
                                               price=close_price.loc[],
                                               volumne=100.0,
                        )
                        self.handle_order(order_data)

                        print("买入股票 {0} {1} 股,委托价为 {2},资金账号为 {3} ...".
                              format(stock, 100, close_price[current_date_int],
                                     self.account[list(self.account.keys())[0]]))

                    # 如果20日均线突破5日均线,并且有持仓,则卖出这只股票100股,委托价为当前bar的收盘价
                    elif ma5[-1] < ma20[-1] and stock in available_position_dict.keys():
                        order_data = OrderData(symbol=stock,
                                               exchange=,
                                               orderid=,
                                               type=OrderType_LIMIT,
                                               direction=Direction_LONG,
                                               offset=Offset_OPEN,
                                               price=close_price.loc[],
                                               volumne=100.0
                        )
                        self.handle_order(order_data)
                        print("卖出股票 {0} {1} 股,委托价为 {2},资金账号为 {3} ...".
                              format(stock, 100, close_price[current_date_int],
                                     self.account[list(self.account.keys())[0]]))
예제 #8
0
    def get_market_data(self,
                        market_data,
                        all_symbol_code=None,
                        field=None,
                        start="",
                        end="",
                        count=-1):
        """
        从 dataframe 解析数据成最终的数据格式
        因为停牌或者其他原因取不到数据的,1 2 3 返回的是-1,其他返回的是 pandas 的空或者 NaN,所以可以使用 >0判断是否取到值
        """
        if start != "":
            if isinstance(start, str):
                start = date_str_to_int(start)
        else:
            start = 0
        if end != "":
            if isinstance(end, str):
                end = date_str_to_int(end)
        else:
            end = 0
        # (1)代码-1,字段-1,时间-1,  return float
        if len(all_symbol_code) == 1 and len(field) == 1 and (
                start == end) and count == -1:
            try:
                return market_data[field[0]].loc[all_symbol_code[0], end]
            # 停牌或者其他情情况取不到数据的返回-1
            except BaseException:
                return -1
        # (2)代码-n,字段-1,时间-1,  return Series
        elif len(all_symbol_code) > 1 and len(field) == 1 and (
                start == end) and count == -1:
            result_dict = {}
            for stock in all_symbol_code:
                try:
                    result_dict[stock] = market_data[field[0]].loc[stock, end]
                except BaseException:
                    result_dict[stock] = -1
            return pd.Series(result_dict)
        # (3)代码-1,字段-n,时间-1,  return Series
        elif len(all_symbol_code) == 1 and len(field) > 1 and (
                start == end) and count == -1:
            result_dict = {}
            for field_one in field:
                try:
                    result_dict[field_one] = market_data[field_one].loc[
                        all_symbol_code[0], end]
                except BaseException:
                    result_dict[field_one] = -1
            return pd.Series(result_dict)
        # (4)代码-1,字段-1,时间-n,  return Series
        elif len(all_symbol_code) == 1 and len(field) == 1 and (
                start != end) and count == -1:
            try:
                series = market_data[field[0]].loc[all_symbol_code[0]]
            except KeyError:
                return pd.Series()

            series = series[series.index >= start]
            series = series[series.index <= end]
            return series
        # (5)代码-n,字段-1,时间-n,  return dataframe 行-timestamp,列-代码
        elif len(all_symbol_code) > 1 and len(field) == 1 and (
                start != end) and count == -1:
            result_dict = {}
            for stock in all_symbol_code:
                index = market_data.loc[stock].index
                index = index[index <= end]
                index = index[index >= start]
                result_dict[stock] = market_data[field[0]].loc[stock][index]
            return pd.DataFrame(result_dict)
        # (6)代码-n,字段-n,时间-1,  return dataframe 行-字段,列-代码
        elif len(all_symbol_code) > 1 and len(field) > 1 and (
                start == end) and count == -1:
            result_dict = {}
            for stock in all_symbol_code:
                try:
                    result_dict[stock] = market_data.loc[stock, end]
                except BaseException:
                    result_dict[stock] = pd.Series()
            return pd.DataFrame(result_dict).loc[field]
        # (7)代码-1,字段-n,时间-n,  return dataframe 行-timestamp,列-字段
        elif len(all_symbol_code) == 1 and len(field) > 1 and (
                start != end) and count == -1:
            index = market_data.loc[all_symbol_code[0]].index
            index = index[index <= end]
            index = index[index >= start]
            return market_data.ix[all_symbol_code[0]][field].loc[index]
        # 代码-n,字段-n,时间-n,  return dataframe 行-代码-timestamp(多层索引),列-字段
        else:
            result_dict = {}
            for stock in all_symbol_code:
                index = market_data.loc[stock].index
                index = index[index <= end]
                index = index[index >= start]
                result_dict[stock] = market_data.loc[stock][field].loc[index]
            return pd.concat(result_dict, keys=all_symbol_code)
예제 #9
0
    def handle_bar(self, event_bar):
        self.context.logger.info("handle_bar() @ {0}".format(event_bar.dt))
        self.activate_trade_signal = False

        available_position_dict = self.context.bar_position_data_dict
        account_data = self.context.current_account_data

        current_date_int = date_str_to_int(event_bar.dt)
        cur_start_date = to_datetime(event_bar.dt) - Timedelta(days=60)
        cur_start_date_int = date_str_to_int(str(cur_start_date)[:10])

        # 循环处理旧持仓
        for pos_symbol in available_position_dict.keys():
            close_price = self.get_data.get_market_data(
                self.context.daily_data,
                all_symbol_code=[pos_symbol],
                field=["close"],
                start=cur_start_date_int,
                end=current_date_int)
            if len(close_price) > 0:
                # 指标计算
                ma5 = talib.MA(array(close_price), timeperiod=5)
                ma20 = talib.MA(array(close_price), timeperiod=20)

                if current_date_int in close_price.keys() and (not isnull(
                        ma5[-1])) and (not isnull(ma20[-1])):
                    if ma5[-1] < ma20[-1]:
                        if available_position_dict[
                                pos_symbol].volume > 0 and available_position_dict[
                                    pos_symbol].direction == Direction.LONG:
                            self.activate_trade_signal = True
                            pos_abs = abs(
                                available_position_dict[pos_symbol].volume)
                            comments = "限价卖出"
                            self.sell(event_bar.dt, self.account[0]['name'],
                                      pos_symbol, close_price.iloc[-1],
                                      pos_abs, False, comments)

                            self.context.logger.info(
                                "-- 资金账号 {3} 发出委托卖出 {0} {1} 股,委托价为 {2}".format(
                                    pos_symbol, pos_abs, close_price.iloc[-1],
                                    self.account[0]['name']))

        # 循环遍历股票池,看是否有新信号
        for symbol in self.universe:
            # 取当前股票的数据
            close_price = self.get_data.get_market_data(
                self.context.daily_data,
                all_symbol_code=[symbol],
                field=["close"],
                start=cur_start_date_int,
                end=current_date_int)
            # close_array = array(close_price)
            if len(close_price) > 0:
                # 指标计算
                ma5 = talib.MA(array(close_price), timeperiod=5)
                ma20 = talib.MA(array(close_price), timeperiod=20)

                # 数据有效时才判断
                if current_date_int in close_price.keys() and (not isnull(
                        ma5[-1])) and (not isnull(ma20[-1])):
                    # 如果5日均线突破20日均线,并且没有持仓,则买入这只股票100股,委托价为当前bar的收盘价
                    if ma5[-1] > ma20[-1]:
                        # live模式下,此处需要更新一次持仓状态,这样判别持仓才准确
                        if symbol not in available_position_dict.keys():
                            self.activate_trade_signal = True
                            comments = "限价买入"
                            # psize = self.calc_position_size(account_data.available, close_price.iloc[-1])
                            psize = 300
                            if psize > 0:
                                self.buy(event_bar.dt, self.account[0]['name'],
                                         symbol, close_price.iloc[-1], psize,
                                         False, comments)

                                self.context.logger.info(
                                    "-- 资金账号 {0} 发出委托买入 {1} {2} 股,委托价为 {3}".
                                    format(self.account[0]['name'], symbol,
                                           psize, close_price.iloc[-1]))