一份用交易数据预测股票代码分享

策略分享
标签: #<Tag:0x00007fc069c673a8>

(lu0817) #1

ps:非本人代码,来自网络开源分享
分享一篇,科赛网《〈 公开新闻预测A股行业板块动向〉〉比赛第三名的开源方案:
本次比赛使用的tushare免费数据,个人可以复现。

import datetime
import os
import sys
from multiprocessing.pool import Pool

import numpy as np
import pandas as pd
import talib
from loguru import logger
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold
from sklearn.svm import SVC
In [6]:
def channel_index_cross(close_list, lowerband_list, upperband_list):
    """
    轨道类指标的交叉序列
    :param close_list:日线收盘价
    :param lowerband_list:下行轨道
    :param upperband_list:上行轨道
    :return:
    """
    result = []
    result.append(0)
    for i in range(1, len(close_list)):
        if close_list[i - 1] < lowerband_list[i - 1] and close_list[i] > lowerband_list[i]:
            result.append(1)
        elif close_list[i - 1] > upperband_list[i - 1] and close_list[i] < upperband_list[i]:
            result.append(-1)
        else:
            result.append(0)
    return result

def index_cross(short_index_values, long_index_values):
    """
    计算指标金叉死叉的序列
    :param short_index_values: 短周期指标的值
    :param long_index_values: 长周期指标的值
    :return:
    """
    result = []
    result.append(0)  # 补齐第一天
    for i in range(1, len(short_index_values)):
        if short_index_values[i - 1] < long_index_values[i] and short_index_values[i] > long_index_values[i]:
            result.append(1)
        elif short_index_values[i - 1] > long_index_values[i] and short_index_values[i] < long_index_values[i]:
            result.append(-1)
        else:
            result.append(0)
    return result
    
def index_oversold_overbought(day_index_values, min_index_value=20, max_index_value=80):
    """
    计算指标值满足超买超卖情况的序列
    :param day_index_values: 日线指标的值
    :param min_index_value:超卖状态的指标的值,如果指标小于该值,则记录为1
    :param max_index_value:超买状态的指标的值,如果指标大于该值,则记录为-1
    :return:
    """
    res = []
    condition_min_list = (day_index_values < min_index_value).tolist()
    condition_max_list = (day_index_values > max_index_value).tolist()
    for i in range(len(condition_max_list)):
        if condition_min_list[i]:
            res.append(1)
        elif condition_max_list[i]:
            res.append(-1)
        else:
            res.append(0)
    return res
    
def calc_oversold_overbought_value(n, bins):
    """
    计算超卖值,超买值
    :param n: hist统计出来的n
    :param bins:hist统计出来的bins
    :return:(超卖值,超买值)
    """
    oversold = 0
    overbought = 0
    for i in range(len(n)):
        if n[i] > 0:
            oversold = bins[i].right
            break
    for i in range(len(n) - 1, -1, -1):
        if n[i] > 0:
            overbought = bins[i].left
            break
    return oversold, overbought
    
def calculate_oversold_overbought(index_values, min_value=0, max_value=100, step=10):
    """
    计算超买超卖区域
    :param index_values: 指标值
    :param min_value: 指标最小值
    :param max_value: 指标最大值
    :param step: 统计超买超卖区域的步长
    :return: (超卖值,超买值)
    """
    index_counter_series = pd.Series(index_values).value_counts(normalize=False, sort=False, ascending=True,
                                                                bins=[t for t in
                                                                      range(min_value, max_value + step, step)])
    n = index_counter_series.values.tolist()
    bins = index_counter_series.index.values
    return calc_oversold_overbought_value(n, bins)
In [7]:
pd.set_option('mode.chained_assignment', None)
logger.add("data_hive.log", format="{time} {level} {line} {message}", level='DEBUG', rotation="5 MB")

algorithms = [
    [RandomForestClassifier(random_state=1, n_estimators=100, min_samples_split=4, min_samples_leaf=2),
     ["boll_upper", "boll_middle", "boll_lower", "k", "d", "j", "macd", "macd_signal", "macd_hist",
      "cci6", "rsi6", "willr6", "cci10", "rsi10", "willr10",
      'boll_cross', 'kd_cross', 'kj_cross', 'cci_cross', 'rsi_cross', 'willr_cross',
      'over_cci6', 'over_cci10', 'over_willr6', 'over_willr10', 'over_j']],
    [LogisticRegression(random_state=1, solver='liblinear'),
     ["boll_upper", "boll_middle", "boll_lower", "k", "d", "j", "macd", "macd_signal", "macd_hist",
      "cci6", "rsi6", "willr6", "cci10", "rsi10", "willr10",
      'boll_cross', 'kd_cross', 'kj_cross', 'cci_cross', 'rsi_cross', 'willr_cross',
      'over_cci6', 'over_cci10', 'over_willr6', 'over_willr10', 'over_j']],
    [SVC(C=1.0, kernel='linear', probability=True),
     ["boll_upper", "boll_middle", "boll_lower", "k", "d", "j", "macd", "macd_signal", "macd_hist",
      "cci6", "rsi6", "willr6", "cci10", "rsi10", "willr10",
      'boll_cross', 'kd_cross', 'kj_cross', 'cci_cross', 'rsi_cross', 'willr_cross',
      'over_cci6', 'over_cci10', 'over_willr6', 'over_willr10', 'over_j']]
]


def __get_n_day_str():
    """
    获取未来三天日期
    :return:
    """
    today = datetime.date.today()
    today_str = datetime.datetime.strftime(today, "%Y%m%d")
    dt = datetime.datetime.strptime(today_str, "%Y%m%d")
    delta_day = datetime.timedelta(days=1)
    date1 = dt + delta_day
    date2 = date1 + delta_day
    date3 = date2 + delta_day
    return [int(datetime.datetime.strftime(date1, "%Y%m%d")), int(datetime.datetime.strftime(date2, "%Y%m%d")), int(datetime.datetime.strftime(date3, "%Y%m%d"))]


date_list = __get_n_day_str()


def load_data(csv_data_fullname):
    day_dataframe = pd.read_csv(csv_data_fullname)
    result_list = method_name2(day_dataframe)
    if os.path.exists('result.csv'):
        os.remove('result.csv')
    with open('result.csv', 'w') as f:
        f.write('{0},{1},{2}\n'.format('ts_code', 'trade_date', 'p'))
        for p_result in result_list:
            f.write('{0},{1},{2}\n'.format(p_result[0][0:6], p_result[1], p_result[2]))


def method_name2(dataframe):
    result_list = []
    pool = Pool()
    tuple_list = list()
    for stock_id, day_dataframe in dataframe.groupby('ts_code'):
        day_dataframe = day_dataframe.sort_values(by=['trade_date'])
        tuple_list.append((stock_id, day_dataframe))
    temp_result_list_2d = pool.map(task, tuple_list)

    for temp_list in temp_result_list_2d:
        result_list.extend(temp_list)
    pool.close()
    pool.join()
    return result_list


def task(tuple_stockid_daydataframe):
    stock_id = tuple_stockid_daydataframe[0]
    day_dataframe = tuple_stockid_daydataframe[1]
    logger.debug('板块ID:{0}'.format(stock_id))
    result_list = list()
    stock_name = day_dataframe.iloc[0]['name']

    day_open_series = day_dataframe['open']
    day_high_series = day_dataframe['high']
    day_low_series = day_dataframe['low']
    day_close_series = day_dataframe['close']

    logger.debug('初始化结果值开始:{0}'.format(stock_id))
    y1, y2, y3 = init_target_values(day_close_series, day_open_series)
    day_dataframe['y1'] = y1
    day_dataframe['y2'] = y2
    day_dataframe['y3'] = y3
    logger.debug('初始化结果值完成:{0}'.format(stock_id))

    logger.debug('初始化指标值开始:{0}'.format(stock_id))
    init_index_values(day_high_series, day_low_series, day_close_series, day_dataframe)
    logger.debug('初始化指标值完成:{0}'.format(stock_id))

    day_data_dataframe = pd.DataFrame(day_dataframe,
                                      columns=['open', 'low', 'low', 'close', 'change', 'vol', 'amount',
                                               'pe', 'pb',
                                               'y1', 'y2', 'y3',
                                               'boll_upper', 'boll_middle', 'boll_lower',
                                               'k', 'd', 'j',
                                               'macd', 'macd_signal', 'macd_hist',
                                               'cci6', 'rsi6', 'willr6',
                                               'cci10', 'rsi10', 'willr10',
                                               'boll_cross', 'kd_cross', 'kj_cross', 'cci_cross', 'rsi_cross', 'willr_cross',
                                               'over_cci6', 'over_cci10', 'over_willr6', 'over_willr10', 'over_j'
                                               ])
    logger.debug('开始预测:{0}'.format(stock_id))
    pre_value1 = get_pre_value(algorithms=algorithms, data_dataframe=day_data_dataframe, target_label='y1')
    pre_value2 = get_pre_value(algorithms=algorithms, data_dataframe=day_data_dataframe, target_label='y2')
    pre_value3 = get_pre_value(algorithms=algorithms, data_dataframe=day_data_dataframe, target_label='y3')
    logger.debug('预测完成:{0}'.format(stock_id))

    result_list.append((stock_id, date_list[0], pre_value1))
    result_list.append((stock_id, date_list[1], pre_value2))
    result_list.append((stock_id, date_list[2], pre_value3))
    return result_list


def get_pre_value(algorithms, data_dataframe, target_label='y1'):
    # pre_value = 0.5
    pre_value1 = get_pre_value_by_alg(algorithms[0][0], algorithms[0][1], target_label, data_dataframe)
    pre_value2 = get_pre_value_by_alg(algorithms[1][0], algorithms[1][1], target_label, data_dataframe)
    pre_value3 = get_pre_value_by_alg(algorithms[2][0], algorithms[2][1], target_label, data_dataframe)
    logger.debug('alg1:{0}'.format(pre_value1))
    logger.debug('alg2:{0}'.format(pre_value2))
    logger.debug('alg3:{0}'.format(pre_value3))
    if pre_value1 + pre_value2 + pre_value3 > 1.0:  # 三种算法举手表决,如果两个算法预测上涨,则为上涨,否则为下跌
        pre_value = 1
    else:
        pre_value = 0
    return pre_value


def get_pre_value_by_alg(alg, predictors, target_label, data_dataframe):
    train_target1 = data_dataframe[target_label].iloc[:]
    alg.fit(data_dataframe[predictors].iloc[:], train_target1)
    alg_result1 = alg.predict([data_dataframe[predictors].iloc[-1, :].values.tolist()])
    return alg_result1[0]


def init_index_values(high_series, low_series, close_series, group):
    lowerband, middleband, upperband = calc_boll_values(close_series)
    k, d, j = calc_kdj_values(close_series, high_series, low_series)
    macd, macd_hist, macd_signal = calc_macd_values(close_series)
    cci_6 = calc_cci_values(close_series, high_series, low_series, timeperiod=6)
    rsi_6 = calc_rsi_values(close_series, timeperiod=6)
    willr_6 = calc_willr_values(close_series, high_series, low_series, timeperiod=6)
    cci_10 = calc_cci_values(close_series, high_series, low_series, timeperiod=10)
    rsi_10 = calc_rsi_values(close_series, timeperiod=10)
    willr_10 = calc_willr_values(close_series, high_series, low_series, timeperiod=10)
    group['boll_upper'] = upperband
    group['boll_middle'] = middleband
    group['boll_lower'] = lowerband
    group['k'] = k
    group['d'] = d
    group['j'] = j
    group['macd'] = macd
    group['macd_signal'] = macd_signal
    group['macd_hist'] = macd_hist
    group['cci6'] = cci_6
    group['rsi6'] = rsi_6
    group['willr6'] = willr_6
    group['cci10'] = cci_10
    group['rsi10'] = rsi_10
    group['willr10'] = willr_10
    boll_cross_list = channel_index_cross(close_series.values.tolist(), lowerband.tolist(), upperband.tolist())
    kd_cross = index_cross(k.tolist(), d.tolist())
    kj_cross = index_cross(k.tolist(), j.tolist())
    cci_cross = index_cross(cci_6.tolist(), cci_10.tolist())
    rsi_cross = index_cross(rsi_6.tolist(), rsi_10.tolist())
    willr_cross = index_cross(willr_6.tolist(), willr_10.tolist())
    group['boll_cross'] = boll_cross_list
    group['kd_cross'] = kd_cross
    group['kj_cross'] = kj_cross
    group['cci_cross'] = cci_cross
    group['rsi_cross'] = rsi_cross
    group['willr_cross'] = willr_cross

    oversold_cci6, overbought_cci6 = calculate_oversold_overbought(cci_6, min_value=-100, max_value=100)
    over_cci6 = index_oversold_overbought(cci_6, oversold_cci6, overbought_cci6)
    oversold_cci10, overbought_cci10 = calculate_oversold_overbought(cci_10, min_value=-100, max_value=100)
    over_cci10 = index_oversold_overbought(cci_10, oversold_cci10, overbought_cci10)
    oversold_willr6, overbought_willr6 = calculate_oversold_overbought(willr_6, min_value=-100, max_value=100)
    over_willr6 = index_oversold_overbought(willr_6, oversold_willr6, overbought_willr6)
    oversold_willr10, overbought_willr10 = calculate_oversold_overbought(willr_10, min_value=-100, max_value=100)
    over_willr10 = index_oversold_overbought(willr_10, oversold_willr10, overbought_willr10)
    oversold_j, overbought_j = calculate_oversold_overbought(j, min_value=-100, max_value=100)
    over_j = index_oversold_overbought(j, oversold_j, overbought_j)

    group['over_cci6'] = over_cci6
    group['over_cci10'] = over_cci10
    group['over_willr6'] = over_willr6
    group['over_willr10'] = over_willr10
    group['over_j'] = over_j
    # deviate_cci_6 = bottom_deviate(close_series.values, cci_6, timeperiod=5)
    # deviate_cci_10 = bottom_deviate(close_series.values, cci_10, timeperiod=5)
    # deviate_willr_6 = bottom_deviate(close_series.values, willr_6, timeperiod=5)
    # deviate_willr_10 = bottom_deviate(close_series.values, willr_10, timeperiod=5)
    # deviate_macd = bottom_deviate(close_series.values, macd, timeperiod=5)
    # deviate_macd_hist = bottom_deviate(close_series.values, macd_hist, timeperiod=5)
    # deviate_macd_signal = bottom_deviate(close_series.values, macd_signal, timeperiod=5)
    # group['deviate_cci6'] = deviate_cci_6
    # group['deviate_cci10'] = deviate_cci_10
    # group['deviate_willr6'] = deviate_willr_6
    # group['deviate_willr10'] = deviate_willr_10
    # group['deviate_macd'] = deviate_macd
    # group['deviate_macd_hist'] = deviate_macd_hist
    # group['deviate_macd_signal'] = deviate_macd_signal


def calc_willr_values(close_series, high_series, low_series, timeperiod=6):
    willr_series = talib.WILLR(high_series, low_series, close_series, timeperiod=timeperiod)
    willr = np.where(np.isnan(willr_series), -50, willr_series)
    return willr


def calc_rsi_values(close_series, timeperiod=6):
    rsi_series = talib.RSI(close_series, timeperiod=timeperiod)
    rsi = np.where(np.isnan(rsi_series), 50, rsi_series)
    return rsi


def calc_macd_values(close_series):
    macd_series, macd_signal_series, macd_hist_series = talib.MACD(close_series, fastperiod=12, slowperiod=26,
                                                                   signalperiod=9)
    macd = np.where(np.isnan(macd_series), 0, macd_series)
    macd_signal = np.where(np.isnan(macd_signal_series), 0, macd_signal_series)
    macd_hist = np.where(np.isnan(macd_hist_series), 0, macd_hist_series)
    return macd, macd_hist, macd_signal


def calc_kdj_values(close_series, high_series, low_series):
    k_series, d_series = talib.STOCH(high_series, low_series, close_series, fastk_period=9, slowk_period=3,
                                     slowk_matype=0, slowd_period=3, slowd_matype=0)
    k = np.where(np.isnan(k_series), 50, k_series)
    d = np.where(np.isnan(d_series), 50, d_series)
    j = 3 * k - 2 * d
    return k, d, j


def calc_cci_values(close_series, high_series, low_series, timeperiod=6):
    cci_series = talib.CCI(high_series, low_series, close_series, timeperiod=timeperiod)
    cci = np.where(np.isnan(cci_series), 0, cci_series)
    return cci


def calc_boll_values(close_series):
    upperband_series, middleband_series, lowerband_series = talib.BBANDS(close_series, timeperiod=20, nbdevup=2,
                                                                         nbdevdn=2, matype=0)
    upperband = np.where(np.isnan(upperband_series), 0, upperband_series)
    middleband = np.where(np.isnan(middleband_series), 0, middleband_series)
    lowerband = np.where(np.isnan(lowerband_series), 0, lowerband_series)
    return lowerband, middleband, upperband


def init_target_values(close_series, open_series):
    y1 = []
    y2 = []
    y3 = []
    for i in range(close_series.shape[0] - 1):
        if i + 1 < close_series.shape[0]:
            if close_series.iloc[i + 1] > open_series.iloc[i]:
                y1.append(1)
            else:
                y1.append(0)
        if i + 2 < close_series.shape[0]:
            if close_series.iloc[i + 2] > open_series.iloc[i]:
                y2.append(1)
            else:
                y2.append(0)
        if i + 3 < close_series.shape[0]:
            if close_series.iloc[i + 3] > open_series.iloc[i]:
                y3.append(1)
            else:
                y3.append(0)
    y1.append(0)
    y2.append(0)
    y2.append(0)
    y3.append(0)
    y3.append(0)
    y3.append(0)

    return y1, y2, y3
In [8]:
load_data('/home/kesci/input/input9882/TRAINSET_STOCK.csv')

详情请看连接https://www.kesci.com/home/project/5d353597cf76a60036f579ad
非常欢迎讨论与分享,希望可以在bigquant平台做成策略
QQ2260068285希望可以认识更多大佬


(yangziriver) #2

这是个用新闻数据预测股票趋势的项目,在代码中好象没有看到这方面的信息,都是技术指标。


(lu0817) #3

源代码作者本人说,新闻数据噪声太大,就使用交易数据,比使用新闻数据效果要好.他个人观点


(lu0817) #4

你可以复现的话,我可以分享更多源代码(有nlp新闻预测的).一起学习学习


(yangziriver) #5

我也是新手一个,试试看吧。感到这个策略思路和平台上的不一样,只是技术指标的计算,没有交易方式,没有回回测规则,没有仓位控制。


(lu0817) #6

你说的很对,我们搞机器学习时只顾技术指标(预测的正确率or f1指标),非金融人士。所以要找大神多帮忙。你可以到科赛网,看下比赛要求,更好的理解代码。
https://www.kesci.com/home/project/5d353597cf76a60036f579ad


(yangziriver) #7

看过了,科赛网是个好平台,我先要消化一下代码才行。我不是搞IT的,外行刚接触这一块,理解能力不行,只能依样画瓢。你是搞机器学习的,应该多了解一下这个平台,有很多的交易方面的考虑,再加上你们的编程能力,会提高很快的。


(lu0817) #8

方便研究数据集,上次分享的不知道怎么没用了
链接:https://pan.baidu.com/s/1r22Vm8CxVuqSMkzDaYXGyw
提取码:nh6l


(yangziriver) #9

数据收到了,用excel打开后,中文全是乱码,就着这个代码做个简单的策略也不需要另外的数据了。有几点没明白:1、想怎样用程序结果进行交易?我的理解是用函数 task()得到要交易的股票代码,是想平均分配资金吗?2、如果三个算法投票结果没有股票可以买(卖),就不交易?3、函数 load_data生成的文件’result.csv’是怎么使用的?没看到使用场合。4、很多变量名字好象不一致,group是从哪儿来的,用到哪儿去了?没看出来。
平台上很多技术指标因子是可以直接使用的,不需自己计算。我试试弄个简单的策略看看。不过全部用技术指标做因子,效果肯定不好。


(lu0817) #10

这个代码只是用交易数据预测34板块3天后涨跌概率,没有交易代码.函数task应该是数据预处理部分。load-data生成的文件应该是34板块3天后涨跌概率。至于数据乱吗,反正只使用交易数据,了解数据格式,更好理解代码,反正复现要用自己数据。


(fsm) #11


这一篇用到新闻数据,但是只提供了思路和部分代码


(yangziriver) #12

由于本人编程水平有限,用平台的可视化编程,虽然有些高级功能我也做不了,但是效率高。

分别用StockRank,随机森林,线性回归做了策略,现在还不会将几个策略复合。纯技术指标做因子的效果不好。本人觉得还是随机森林效果最好,方便、快捷,它本身就是打分判断结果的。

总的思路是:

  1. 全A股作股票池;
  2. colse_-7/open_-1作label;
  3. 选“智能家居”概念股训练预测;
  4. 100万元起步资金;
  5. 持股天数5天

使用的因子是文章中提到的,且平台能提供的。自己合成因子也可以,程序上会复杂些,本人还不太熟练。抛砖引玉,欢迎平台上的大佬指正、献技。

克隆策略

条件过滤——概念板块过滤

    {"Description":"实验创建于2017/8/26","Summary":"","Graph":{"EdgesInternal":[{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"-404:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data1","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-404:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-411:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-418:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-425:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60:model","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43:model"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84:input_data","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data"},{"DestinationInputPortId":"-1918:options_data","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60:predictions"},{"DestinationInputPortId":"-418:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62:data"},{"DestinationInputPortId":"-1918:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62:data"},{"DestinationInputPortId":"-2157:input_1","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84:data"},{"DestinationInputPortId":"-2161:input_1","SourceOutputPortId":"-86:data"},{"DestinationInputPortId":"-411:input_data","SourceOutputPortId":"-404:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data2","SourceOutputPortId":"-411:data"},{"DestinationInputPortId":"-425:input_data","SourceOutputPortId":"-418:data"},{"DestinationInputPortId":"-86:input_data","SourceOutputPortId":"-425:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43:training_ds","SourceOutputPortId":"-2157:data_1"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60:data","SourceOutputPortId":"-2161:data_1"}],"ModuleNodes":[{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2013-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":1,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-15","ModuleId":"BigQuantSpace.advanced_auto_labeler.advanced_auto_labeler-v2","ModuleParameters":[{"Name":"label_expr","Value":"# #号开始的表示注释\n# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段\n# 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html\n# 添加benchmark_前缀,可使用对应的benchmark数据\n# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_\n\n# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)\nshift(close, -7) / shift(open, -1)\n\n# 极值处理:用1%和99%分位的值做clip\nclip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))\n\n# 将分数映射到分类,这里使用20个分类\nall_wbins(label, 20)\n\n# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)\nwhere(shift(high, -1) == shift(low, -1), NaN, label)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.SHA","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na_label","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"cast_label_int","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":2,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"# #号开始的表示注释\n# 多个特征,每行一个,可以包含基础特征和衍生特征\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'long')\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'short')\nta_macd_macd_12_26_9_0\nta_macd(close_0,'long')\nta_macd(close_0,'short')\nta_macd(close_0,'golden_cross')\nta_macd(close_0,'death_cross')\nta_rsi_14_0\nta_willr_14_0\nta_cci_14_0\nta_bbands_upperband_28_0\nta_bbands_lowerband_28_0\nta_bbands_middleband_28_0\nta_stoch_slowk_5_3_0_3_0_0*3-ta_stoch_slowd_5_3_0_3_0_0*2\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'golden_cross')\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'death_cross')\n","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":3,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43","ModuleId":"BigQuantSpace.stock_ranker_train.stock_ranker_train-v5","ModuleParameters":[{"Name":"learning_algorithm","Value":"排序","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"number_of_leaves","Value":30,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"minimum_docs_per_leaf","Value":1000,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"number_of_trees","Value":20,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"learning_rate","Value":0.1,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_bins","Value":1023,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"feature_fraction","Value":1,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"m_lazy_run","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"training_ds","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"test_ds","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"base_model","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"}],"OutputPortsInternal":[{"Name":"model","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43","OutputType":null},{"Name":"feature_gains","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43","OutputType":null},{"Name":"m_lazy_run","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-43","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":6,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","ModuleId":"BigQuantSpace.join.join-v3","ModuleParameters":[{"Name":"on","Value":"date,instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"how","Value":"inner","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"sort","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data1","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data2","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":7,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60","ModuleId":"BigQuantSpace.stock_ranker_predict.stock_ranker_predict-v5","ModuleParameters":[{"Name":"m_lazy_run","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"model","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60"}],"OutputPortsInternal":[{"Name":"predictions","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60","OutputType":null},{"Name":"m_lazy_run","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-60","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":8,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-62","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":"交易日期"},{"Name":"end_date","Value":"2019-08-07","ValueType":"Literal","LinkedGlobalParameter":"交易日期"},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":9,"IsPartOfPartialRun":null,"Comment":"预测数据,用于回测和模拟","CommentCollapsed":false},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-84","ModuleId":"BigQuantSpace.dropnan.dropnan-v1","ModuleParameters":[],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":13,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-86","ModuleId":"BigQuantSpace.dropnan.dropnan-v1","ModuleParameters":[],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-86"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-86","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":14,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-404","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":0,"ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-404"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-404"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-404","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":15,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-411","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-411"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-411"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-411","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":16,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-418","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":0,"ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-418"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-418"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-418","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":17,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-425","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-425"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-425"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-425","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":18,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-1918","ModuleId":"BigQuantSpace.trade.trade-v4","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"initialize","Value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n # 加载预测数据\n context.ranker_prediction = context.options['data'].read_df()\n\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)\n # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只\n stock_count = 10\n # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]\n context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])\n # 设置每只股票占用的最大资金比例\n context.max_cash_per_instrument = 0.2\n context.options['hold_days'] = 5\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"handle_data","Value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n # 按日期过滤得到今日的预测数据\n ranker_prediction = context.ranker_prediction[\n context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]\n\n # 1. 资金分配\n # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金\n # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)\n is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)\n cash_avg = context.portfolio.portfolio_value / context.options['hold_days']\n cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)\n cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)\n positions = {e.symbol: p.amount * p.last_sale_price\n for e, p in context.perf_tracker.position_tracker.positions.items()}\n\n # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰\n if not is_staging and cash_for_sell > 0:\n equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}\n instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(\n lambda x: x in equities and not context.has_unfinished_sell_order(equities[x]))])))\n # print('rank order for sell %s' % instruments)\n for instrument in instruments:\n context.order_target(context.symbol(instrument), 0)\n cash_for_sell -= positions[instrument]\n if cash_for_sell <= 0:\n break\n\n # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票\n buy_cash_weights = context.stock_weights\n buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])\n max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument\n for i, instrument in enumerate(buy_instruments):\n cash = cash_for_buy * buy_cash_weights[i]\n if cash > max_cash_per_instrument - positions.get(instrument, 0):\n # 确保股票持仓量不会超过每次股票最大的占用资金量\n cash = max_cash_per_instrument - positions.get(instrument, 0)\n if cash > 0:\n context.order_value(context.symbol(instrument), cash)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"prepare","Value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n pass\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_trading_start","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"volume_limit","Value":0.025,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_buy","Value":"open","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_sell","Value":"close","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"capital_base","Value":1000000,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"auto_cancel_non_tradable_orders","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"data_frequency","Value":"daily","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"price_type","Value":"后复权","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"product_type","Value":"股票","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"plot_charts","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"backtest_only","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-1918"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"options_data","NodeId":"-1918"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"history_ds","NodeId":"-1918"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"benchmark_ds","NodeId":"-1918"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"trading_calendar","NodeId":"-1918"}],"OutputPortsInternal":[{"Name":"raw_perf","NodeId":"-1918","OutputType":null}],"UsePreviousResults":false,"moduleIdForCode":4,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-2157","ModuleId":"BigQuantSpace.filter_concept.filter_concept-v2","ModuleParameters":[{"Name":"concept_str","Value":"智能家居","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-2157"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-2157","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":10,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-2161","ModuleId":"BigQuantSpace.filter_concept.filter_concept-v2","ModuleParameters":[{"Name":"concept_str","Value":"智能家居","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-2161"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-2161","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":5,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true}],"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-8' Position='211,50,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-15' Position='101,162,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-24' Position='766,-65,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-43' Position='472,515,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-53' Position='286,296,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-60' Position='675,594,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-62' Position='1070,81,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-84' Position='286,372,200,200'/><NodePosition Node='-86' Position='1077,345,200,200'/><NodePosition Node='-404' Position='394,136,200,200'/><NodePosition Node='-411' Position='396,213,200,200'/><NodePosition Node='-418' Position='1069,171,200,200'/><NodePosition Node='-425' Position='1068,255,200,200'/><NodePosition Node='-1918' Position='813,717,200,200'/><NodePosition Node='-2157' Position='284,445,200,200'/><NodePosition Node='-2161' Position='1059,439,200,200'/></NodePositions><NodeGroups /></DataV1>"},"IsDraft":true,"ParentExperimentId":null,"WebService":{"IsWebServiceExperiment":false,"Inputs":[],"Outputs":[],"Parameters":[{"Name":"交易日期","Value":"","ParameterDefinition":{"Name":"交易日期","FriendlyName":"交易日期","DefaultValue":"","ParameterType":"String","HasDefaultValue":true,"IsOptional":true,"ParameterRules":[],"HasRules":false,"MarkupType":0,"CredentialDescriptor":null}}],"WebServiceGroupId":null,"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions></NodePositions><NodeGroups /></DataV1>"},"DisableNodesUpdate":false,"Category":"user","Tags":[],"IsPartialRun":true}
    In [1]:
    # 本代码由可视化策略环境自动生成 2019年8月9日 11:02
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # 回测引擎:初始化函数,只执行一次
    def m4_initialize_bigquant_run(context):
        # 加载预测数据
        context.ranker_prediction = context.options['data'].read_df()
    
        # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
        context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
        # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)
        # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只
        stock_count = 10
        # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]
        context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])
        # 设置每只股票占用的最大资金比例
        context.max_cash_per_instrument = 0.2
        context.options['hold_days'] = 5
    
    # 回测引擎:每日数据处理函数,每天执行一次
    def m4_handle_data_bigquant_run(context, data):
        # 按日期过滤得到今日的预测数据
        ranker_prediction = context.ranker_prediction[
            context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]
    
        # 1. 资金分配
        # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金
        # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)
        is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)
        cash_avg = context.portfolio.portfolio_value / context.options['hold_days']
        cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)
        cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)
        positions = {e.symbol: p.amount * p.last_sale_price
                     for e, p in context.perf_tracker.position_tracker.positions.items()}
    
        # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰
        if not is_staging and cash_for_sell > 0:
            equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}
            instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(
                    lambda x: x in equities and not context.has_unfinished_sell_order(equities[x]))])))
            # print('rank order for sell %s' % instruments)
            for instrument in instruments:
                context.order_target(context.symbol(instrument), 0)
                cash_for_sell -= positions[instrument]
                if cash_for_sell <= 0:
                    break
    
        # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票
        buy_cash_weights = context.stock_weights
        buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])
        max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
        for i, instrument in enumerate(buy_instruments):
            cash = cash_for_buy * buy_cash_weights[i]
            if cash > max_cash_per_instrument - positions.get(instrument, 0):
                # 确保股票持仓量不会超过每次股票最大的占用资金量
                cash = max_cash_per_instrument - positions.get(instrument, 0)
            if cash > 0:
                context.order_value(context.symbol(instrument), cash)
    
    # 回测引擎:准备数据,只执行一次
    def m4_prepare_bigquant_run(context):
        pass
    
    
    m1 = M.instruments.v2(
        start_date='2013-01-01',
        end_date='2018-01-01',
        market='CN_STOCK_A',
        instrument_list='',
        max_count=0
    )
    
    m2 = M.advanced_auto_labeler.v2(
        instruments=m1.data,
        label_expr="""# #号开始的表示注释
    # 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
    # 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html
    #   添加benchmark_前缀,可使用对应的benchmark数据
    # 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_
    
    # 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
    shift(close, -7) / shift(open, -1)
    
    # 极值处理:用1%和99%分位的值做clip
    clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))
    
    # 将分数映射到分类,这里使用20个分类
    all_wbins(label, 20)
    
    # 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
    where(shift(high, -1) == shift(low, -1), NaN, label)
    """,
        start_date='',
        end_date='',
        benchmark='000300.SHA',
        drop_na_label=True,
        cast_label_int=True
    )
    
    m3 = M.input_features.v1(
        features="""# #号开始的表示注释
    # 多个特征,每行一个,可以包含基础特征和衍生特征
    ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'long')
    ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'short')
    ta_macd_macd_12_26_9_0
    ta_macd(close_0,'long')
    ta_macd(close_0,'short')
    ta_macd(close_0,'golden_cross')
    ta_macd(close_0,'death_cross')
    ta_rsi_14_0
    ta_willr_14_0
    ta_cci_14_0
    ta_bbands_upperband_28_0
    ta_bbands_lowerband_28_0
    ta_bbands_middleband_28_0
    ta_stoch_slowk_5_3_0_3_0_0*3-ta_stoch_slowd_5_3_0_3_0_0*2
    ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'golden_cross')
    ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'death_cross')
    """
    )
    
    m15 = M.general_feature_extractor.v7(
        instruments=m1.data,
        features=m3.data,
        start_date='',
        end_date='',
        before_start_days=0
    )
    
    m16 = M.derived_feature_extractor.v3(
        input_data=m15.data,
        features=m3.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=False
    )
    
    m7 = M.join.v3(
        data1=m2.data,
        data2=m16.data,
        on='date,instrument',
        how='inner',
        sort=False
    )
    
    m13 = M.dropnan.v1(
        input_data=m7.data
    )
    
    m10 = M.filter_concept.v2(
        input_1=m13.data,
        concept_str='智能家居'
    )
    
    m6 = M.stock_ranker_train.v5(
        training_ds=m10.data_1,
        features=m3.data,
        learning_algorithm='排序',
        number_of_leaves=30,
        minimum_docs_per_leaf=1000,
        number_of_trees=20,
        learning_rate=0.1,
        max_bins=1023,
        feature_fraction=1,
        m_lazy_run=False
    )
    
    m9 = M.instruments.v2(
        start_date=T.live_run_param('trading_date', '2018-01-01'),
        end_date=T.live_run_param('trading_date', '2019-08-07'),
        market='CN_STOCK_A',
        instrument_list='',
        max_count=0
    )
    
    m17 = M.general_feature_extractor.v7(
        instruments=m9.data,
        features=m3.data,
        start_date='',
        end_date='',
        before_start_days=0
    )
    
    m18 = M.derived_feature_extractor.v3(
        input_data=m17.data,
        features=m3.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=False
    )
    
    m14 = M.dropnan.v1(
        input_data=m18.data
    )
    
    m5 = M.filter_concept.v2(
        input_1=m14.data,
        concept_str='智能家居'
    )
    
    m8 = M.stock_ranker_predict.v5(
        model=m6.model,
        data=m5.data_1,
        m_lazy_run=False
    )
    
    m4 = M.trade.v4(
        instruments=m9.data,
        options_data=m8.predictions,
        start_date='',
        end_date='',
        initialize=m4_initialize_bigquant_run,
        handle_data=m4_handle_data_bigquant_run,
        prepare=m4_prepare_bigquant_run,
        volume_limit=0.025,
        order_price_field_buy='open',
        order_price_field_sell='close',
        capital_base=1000000,
        auto_cancel_non_tradable_orders=True,
        data_frequency='daily',
        price_type='后复权',
        product_type='股票',
        plot_charts=True,
        backtest_only=False,
        benchmark=''
    )
    
    设置测试数据集,查看训练迭代过程的NDCG
    bigcharts-data-start/{"__id":"bigchart-b725d7cabb93468f9c52c5f70d81729f","__type":"tabs"}/bigcharts-data-end
    • 收益率-30.61%
    • 年化收益率-21.08%
    • 基准收益率-10.16%
    • 阿尔法-0.16
    • 贝塔0.88
    • 夏普比率-0.75
    • 胜率0.49
    • 盈亏比0.97
    • 收益波动率29.64%
    • 信息比率-0.04
    • 最大回撤39.64%
    bigcharts-data-start/{"__id":"bigchart-8ca8c4537f934b60b1121711cff046be","__type":"tabs"}/bigcharts-data-end
    In [2]:
    m4.risk_analyze()
    

    (yangziriver) #13
    克隆策略

      {"Description":"实验创建于2017/8/26","Summary":"","Graph":{"EdgesInternal":[{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"-274:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data1","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84:input_data","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data"},{"DestinationInputPortId":"-288:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62:data"},{"DestinationInputPortId":"-250:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62:data"},{"DestinationInputPortId":"-2157:input_1","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84:data"},{"DestinationInputPortId":"-6236:input_1","SourceOutputPortId":"-86:data"},{"DestinationInputPortId":"-281:input_data","SourceOutputPortId":"-274:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data2","SourceOutputPortId":"-281:data"},{"DestinationInputPortId":"-295:input_data","SourceOutputPortId":"-288:data"},{"DestinationInputPortId":"-86:input_data","SourceOutputPortId":"-295:data"},{"DestinationInputPortId":"-250:options_data","SourceOutputPortId":"-9726:predictions"},{"DestinationInputPortId":"-9726:features","SourceOutputPortId":"-1555:data"},{"DestinationInputPortId":"-274:features","SourceOutputPortId":"-1555:data"},{"DestinationInputPortId":"-281:features","SourceOutputPortId":"-1555:data"},{"DestinationInputPortId":"-288:features","SourceOutputPortId":"-1555:data"},{"DestinationInputPortId":"-295:features","SourceOutputPortId":"-1555:data"},{"DestinationInputPortId":"-9726:predict_ds","SourceOutputPortId":"-6236:data_1"},{"DestinationInputPortId":"-9726:training_ds","SourceOutputPortId":"-2157:data_1"}],"ModuleNodes":[{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2013-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":1,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-15","ModuleId":"BigQuantSpace.advanced_auto_labeler.advanced_auto_labeler-v2","ModuleParameters":[{"Name":"label_expr","Value":"# #号开始的表示注释\n# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段\n# 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html\n# 添加benchmark_前缀,可使用对应的benchmark数据\n# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_\n\n# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)\nshift(close, -7) / shift(open, -1)\n\n# 极值处理:用1%和99%分位的值做clip\nclip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))\n\n# 将分数映射到分类,这里使用20个分类\nall_wbins(label, 20)\n\n# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)\nwhere(shift(high, -1) == shift(low, -1), NaN, label)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.SHA","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na_label","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"cast_label_int","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":2,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","ModuleId":"BigQuantSpace.join.join-v3","ModuleParameters":[{"Name":"on","Value":"date,instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"how","Value":"inner","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"sort","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data1","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data2","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":7,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-62","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":"交易日期"},{"Name":"end_date","Value":"2019-08-07","ValueType":"Literal","LinkedGlobalParameter":"交易日期"},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":9,"IsPartOfPartialRun":null,"Comment":"预测数据,用于回测和模拟","CommentCollapsed":false},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-84","ModuleId":"BigQuantSpace.dropnan.dropnan-v1","ModuleParameters":[],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":13,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-86","ModuleId":"BigQuantSpace.dropnan.dropnan-v1","ModuleParameters":[],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-86"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-86","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":14,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-274","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":0,"ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-274"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-274"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-274","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":15,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-281","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-281"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-281"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-281","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":16,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-288","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":"90","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-288"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-288"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-288","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":17,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-295","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-295"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-295"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-295","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":18,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-9726","ModuleId":"BigQuantSpace.random_forest_regressor.random_forest_regressor-v1","ModuleParameters":[{"Name":"iterations","Value":10,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"feature_fraction","Value":1,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_depth","Value":30,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"min_samples_per_leaf","Value":200,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"key_cols","Value":"date,instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"workers","Value":1,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"other_train_parameters","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"training_ds","NodeId":"-9726"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-9726"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"model","NodeId":"-9726"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"predict_ds","NodeId":"-9726"}],"OutputPortsInternal":[{"Name":"output_model","NodeId":"-9726","OutputType":null},{"Name":"predictions","NodeId":"-9726","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":19,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-1555","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'long')\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'short')\nta_macd_macd_12_26_9_0\nta_macd(close_0,'long')\nta_macd(close_0,'short')\nta_rsi_14_0\nta_willr_14_0\nta_cci_14_0\nta_bbands_upperband_28_0\nta_bbands_lowerband_28_0\nta_bbands_middleband_28_0\nta_stoch_slowk_5_3_0_3_0_0*3-ta_stoch_slowd_5_3_0_3_0_0*2\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'golden_cross')\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'death_cross')\n","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"-1555"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-1555","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":4,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-250","ModuleId":"BigQuantSpace.trade.trade-v4","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"initialize","Value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n # 加载预测数据\n \n context.ranker_prediction = context.options['data'].read_df()\n \n\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)\n # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只\n stock_count = 10\n # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]\n context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])\n # 设置每只股票占用的最大资金比例\n context.max_cash_per_instrument = 0.2\n context.options['hold_days'] = 5\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"handle_data","Value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n # 按日期过滤得到今日的预测数据\n ranker_prediction = context.ranker_prediction[\n context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]\n \n ranker_prediction = ranker_prediction.sort_values('pred_label', ascending=False)\n \n \n # 1. 资金分配\n # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金\n # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)\n is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)\n cash_avg = context.portfolio.portfolio_value / context.options['hold_days']\n cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)\n cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)\n positions = {e.symbol: p.amount * p.last_sale_price\n for e, p in context.portfolio.positions.items()}\n\n # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰\n if not is_staging and cash_for_sell > 0:\n equities = {e.symbol: e for e, p in context.portfolio.positions.items()}\n instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(\n lambda x: x in equities)])))\n\n for instrument in instruments:\n context.order_target(context.symbol(instrument), 0)\n cash_for_sell -= positions[instrument]\n if cash_for_sell <= 0:\n break\n\n # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票\n buy_cash_weights = context.stock_weights\n buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])\n max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument\n for i, instrument in enumerate(buy_instruments):\n cash = cash_for_buy * buy_cash_weights[i]\n if cash > max_cash_per_instrument - positions.get(instrument, 0):\n # 确保股票持仓量不会超过每次股票最大的占用资金量\n cash = max_cash_per_instrument - positions.get(instrument, 0)\n if cash > 0:\n context.order_value(context.symbol(instrument), cash)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"prepare","Value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n pass\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_trading_start","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"volume_limit","Value":0.025,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_buy","Value":"open","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_sell","Value":"close","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"capital_base","Value":"1000000","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"auto_cancel_non_tradable_orders","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"data_frequency","Value":"daily","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"price_type","Value":"后复权","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"product_type","Value":"股票","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"plot_charts","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"backtest_only","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.SHA","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-250"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"options_data","NodeId":"-250"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"history_ds","NodeId":"-250"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"benchmark_ds","NodeId":"-250"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"trading_calendar","NodeId":"-250"}],"OutputPortsInternal":[{"Name":"raw_perf","NodeId":"-250","OutputType":null}],"UsePreviousResults":false,"moduleIdForCode":6,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-6236","ModuleId":"BigQuantSpace.filter_concept.filter_concept-v2","ModuleParameters":[{"Name":"concept_str","Value":"智能家居","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-6236"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-6236","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":5,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-2157","ModuleId":"BigQuantSpace.filter_concept.filter_concept-v2","ModuleParameters":[{"Name":"concept_str","Value":"智能家居","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-2157"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-2157","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":3,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true}],"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-8' Position='211,64,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-15' Position='70,183,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-53' Position='249,375,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-62' Position='1013,-119,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-84' Position='250,460,200,200'/><NodePosition Node='-86' Position='1047,200,200,200'/><NodePosition Node='-274' Position='381,188,200,200'/><NodePosition Node='-281' Position='385,280,200,200'/><NodePosition Node='-288' Position='1026,0,200,200'/><NodePosition Node='-295' Position='1030,87,200,200'/><NodePosition Node='-9726' Position='664,670,200,200'/><NodePosition Node='-1555' Position='647,-171.0258026123047,200,200'/><NodePosition Node='-250' Position='743,815,200,200'/><NodePosition Node='-6236' Position='1049,331,200,200'/><NodePosition Node='-2157' Position='275,562,200,200'/></NodePositions><NodeGroups /></DataV1>"},"IsDraft":true,"ParentExperimentId":null,"WebService":{"IsWebServiceExperiment":false,"Inputs":[],"Outputs":[],"Parameters":[{"Name":"交易日期","Value":"","ParameterDefinition":{"Name":"交易日期","FriendlyName":"交易日期","DefaultValue":"","ParameterType":"String","HasDefaultValue":true,"IsOptional":true,"ParameterRules":[],"HasRules":false,"MarkupType":0,"CredentialDescriptor":null}}],"WebServiceGroupId":null,"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions></NodePositions><NodeGroups /></DataV1>"},"DisableNodesUpdate":false,"Category":"user","Tags":[],"IsPartialRun":false}
      In [5]:
      # 本代码由可视化策略环境自动生成 2019年8月8日 20:45
      # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
      
      
      # 回测引擎:初始化函数,只执行一次
      def m6_initialize_bigquant_run(context):
          # 加载预测数据
          
          context.ranker_prediction = context.options['data'].read_df()
          
      
          # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
          context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
          # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)
          # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只
          stock_count = 10
          # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]
          context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])
          # 设置每只股票占用的最大资金比例
          context.max_cash_per_instrument = 0.2
          context.options['hold_days'] = 5
      
      # 回测引擎:每日数据处理函数,每天执行一次
      def m6_handle_data_bigquant_run(context, data):
          # 按日期过滤得到今日的预测数据
          ranker_prediction = context.ranker_prediction[
              context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]
          
          ranker_prediction = ranker_prediction.sort_values('pred_label', ascending=False)
       
          
          # 1. 资金分配
          # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金
          # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)
          is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)
          cash_avg = context.portfolio.portfolio_value / context.options['hold_days']
          cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)
          cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)
          positions = {e.symbol: p.amount * p.last_sale_price
                       for e, p in context.portfolio.positions.items()}
      
          # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰
          if not is_staging and cash_for_sell > 0:
              equities = {e.symbol: e for e, p in context.portfolio.positions.items()}
              instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(
                      lambda x: x in equities)])))
      
              for instrument in instruments:
                  context.order_target(context.symbol(instrument), 0)
                  cash_for_sell -= positions[instrument]
                  if cash_for_sell <= 0:
                      break
      
          # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票
          buy_cash_weights = context.stock_weights
          buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])
          max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
          for i, instrument in enumerate(buy_instruments):
              cash = cash_for_buy * buy_cash_weights[i]
              if cash > max_cash_per_instrument - positions.get(instrument, 0):
                  # 确保股票持仓量不会超过每次股票最大的占用资金量
                  cash = max_cash_per_instrument - positions.get(instrument, 0)
              if cash > 0:
                  context.order_value(context.symbol(instrument), cash)
      
      # 回测引擎:准备数据,只执行一次
      def m6_prepare_bigquant_run(context):
          pass
      
      
      m1 = M.instruments.v2(
          start_date='2013-01-01',
          end_date='2018-01-01',
          market='CN_STOCK_A',
          instrument_list='',
          max_count=0
      )
      
      m2 = M.advanced_auto_labeler.v2(
          instruments=m1.data,
          label_expr="""# #号开始的表示注释
      # 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
      # 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html
      #   添加benchmark_前缀,可使用对应的benchmark数据
      # 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_
      
      # 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
      shift(close, -7) / shift(open, -1)
      
      # 极值处理:用1%和99%分位的值做clip
      clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))
      
      # 将分数映射到分类,这里使用20个分类
      all_wbins(label, 20)
      
      # 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
      where(shift(high, -1) == shift(low, -1), NaN, label)
      """,
          start_date='',
          end_date='',
          benchmark='000300.SHA',
          drop_na_label=True,
          cast_label_int=True
      )
      
      m9 = M.instruments.v2(
          start_date=T.live_run_param('trading_date', '2018-01-01'),
          end_date=T.live_run_param('trading_date', '2019-08-07'),
          market='CN_STOCK_A',
          instrument_list='',
          max_count=0
      )
      
      m4 = M.input_features.v1(
          features="""ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'long')
      ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'short')
      ta_macd_macd_12_26_9_0
      ta_macd(close_0,'long')
      ta_macd(close_0,'short')
      ta_rsi_14_0
      ta_willr_14_0
      ta_cci_14_0
      ta_bbands_upperband_28_0
      ta_bbands_lowerband_28_0
      ta_bbands_middleband_28_0
      ta_stoch_slowk_5_3_0_3_0_0*3-ta_stoch_slowd_5_3_0_3_0_0*2
      ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'golden_cross')
      ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'death_cross')
      """
      )
      
      m15 = M.general_feature_extractor.v7(
          instruments=m1.data,
          features=m4.data,
          start_date='',
          end_date='',
          before_start_days=0
      )
      
      m16 = M.derived_feature_extractor.v3(
          input_data=m15.data,
          features=m4.data,
          date_col='date',
          instrument_col='instrument',
          drop_na=False,
          remove_extra_columns=False
      )
      
      m7 = M.join.v3(
          data1=m2.data,
          data2=m16.data,
          on='date,instrument',
          how='inner',
          sort=False
      )
      
      m13 = M.dropnan.v1(
          input_data=m7.data
      )
      
      m3 = M.filter_concept.v2(
          input_1=m13.data,
          concept_str='智能家居'
      )
      
      m17 = M.general_feature_extractor.v7(
          instruments=m9.data,
          features=m4.data,
          start_date='',
          end_date='',
          before_start_days=90
      )
      
      m18 = M.derived_feature_extractor.v3(
          input_data=m17.data,
          features=m4.data,
          date_col='date',
          instrument_col='instrument',
          drop_na=False,
          remove_extra_columns=False
      )
      
      m14 = M.dropnan.v1(
          input_data=m18.data
      )
      
      m5 = M.filter_concept.v2(
          input_1=m14.data,
          concept_str='智能家居'
      )
      
      m19 = M.random_forest_regressor.v1(
          training_ds=m3.data_1,
          features=m4.data,
          predict_ds=m5.data_1,
          iterations=10,
          feature_fraction=1,
          max_depth=30,
          min_samples_per_leaf=200,
          key_cols='date,instrument',
          workers=1,
          other_train_parameters={}
      )
      
      m6 = M.trade.v4(
          instruments=m9.data,
          options_data=m19.predictions,
          start_date='',
          end_date='',
          initialize=m6_initialize_bigquant_run,
          handle_data=m6_handle_data_bigquant_run,
          prepare=m6_prepare_bigquant_run,
          volume_limit=0.025,
          order_price_field_buy='open',
          order_price_field_sell='close',
          capital_base=1000000,
          auto_cancel_non_tradable_orders=True,
          data_frequency='daily',
          price_type='后复权',
          product_type='股票',
          plot_charts=True,
          backtest_only=False,
          benchmark='000300.SHA'
      )
      
      • 收益率-21.18%
      • 年化收益率-14.29%
      • 基准收益率-10.16%
      • 阿尔法-0.06
      • 贝塔0.93
      • 夏普比率-0.4
      • 胜率0.49
      • 盈亏比1.03
      • 收益波动率32.54%
      • 信息比率-0.01
      • 最大回撤30.53%
      bigcharts-data-start/{"__id":"bigchart-0159f143c5414f7c9f3cd6bfd0153f93","__type":"tabs"}/bigcharts-data-end

      (yangziriver) #14
      克隆策略

        {"Description":"实验创建于2017/8/26","Summary":"","Graph":{"EdgesInternal":[{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"-787:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data1","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15:data"},{"DestinationInputPortId":"-787:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-794:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-803:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-810:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-9053:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-8155:input_2","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"-8144:features","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84:input_data","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data"},{"DestinationInputPortId":"-803:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62:data"},{"DestinationInputPortId":"-822:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62:data"},{"DestinationInputPortId":"-2157:input_1","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84:data"},{"DestinationInputPortId":"-607:input_1","SourceOutputPortId":"-86:data"},{"DestinationInputPortId":"-794:input_data","SourceOutputPortId":"-787:data"},{"DestinationInputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data2","SourceOutputPortId":"-794:data"},{"DestinationInputPortId":"-810:input_data","SourceOutputPortId":"-803:data"},{"DestinationInputPortId":"-86:input_data","SourceOutputPortId":"-810:data"},{"DestinationInputPortId":"-822:options_data","SourceOutputPortId":"-9053:predictions"},{"DestinationInputPortId":"-9053:training_ds","SourceOutputPortId":"-8144:train_data"},{"DestinationInputPortId":"-9053:predict_ds","SourceOutputPortId":"-8144:test_data"},{"DestinationInputPortId":"-8144:train_ds","SourceOutputPortId":"-8155:data_1"},{"DestinationInputPortId":"-8144:test_ds","SourceOutputPortId":"-8155:data_2"},{"DestinationInputPortId":"-8155:input_1","SourceOutputPortId":"-2157:data_1"},{"DestinationInputPortId":"-8155:input_3","SourceOutputPortId":"-607:data_1"}],"ModuleNodes":[{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2013-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":1,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-15","ModuleId":"BigQuantSpace.advanced_auto_labeler.advanced_auto_labeler-v2","ModuleParameters":[{"Name":"label_expr","Value":"# #号开始的表示注释\n# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段\n# 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html\n# 添加benchmark_前缀,可使用对应的benchmark数据\n# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_\n\n# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)\nshift(close, -7) / shift(open, -1)\n\n# 极值处理:用1%和99%分位的值做clip\nclip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))\n\n# 将分数映射到分类,这里使用20个分类\nall_wbins(label, 20)\n\n# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)\nwhere(shift(high, -1) == shift(low, -1), NaN, label)","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.SHA","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na_label","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"cast_label_int","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-15","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":2,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'long')\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'short')\nta_macd_macd_12_26_9_0\nta_macd(close_0,'long')\nta_macd(close_0,'short')\nta_macd(close_0,'golden_cross')\nta_macd(close_0,'death_cross')\nta_rsi_14_0\nta_willr_14_0\nta_cci_14_0\nta_bbands_upperband_28_0\nta_bbands_lowerband_28_0\nta_bbands_middleband_28_0\nta_stoch_slowk_5_3_0_3_0_0*3-ta_stoch_slowd_5_3_0_3_0_0*2\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'golden_cross')\nta_kdj(high_0, low_0, close_0, 50, 9, 3, 'death_cross')\n","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-24","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":3,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","ModuleId":"BigQuantSpace.join.join-v3","ModuleParameters":[{"Name":"on","Value":"date,instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"how","Value":"inner","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"sort","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data1","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"data2","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":7,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-62","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2018-01-01","ValueType":"Literal","LinkedGlobalParameter":"交易日期"},{"Name":"end_date","Value":"2019-08-07","ValueType":"Literal","LinkedGlobalParameter":"交易日期"},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-62","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":9,"IsPartOfPartialRun":null,"Comment":"预测数据,用于回测和模拟","CommentCollapsed":false},{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-84","ModuleId":"BigQuantSpace.dropnan.dropnan-v1","ModuleParameters":[],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-84","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":13,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-86","ModuleId":"BigQuantSpace.dropnan.dropnan-v1","ModuleParameters":[],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-86"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-86","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":14,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-787","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":0,"ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-787"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-787"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-787","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":15,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-794","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-794"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-794"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-794","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":16,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-803","ModuleId":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_start_days","Value":0,"ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-803"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-803"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-803","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":17,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-810","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-810"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-810"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-810","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":18,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-822","ModuleId":"BigQuantSpace.trade.trade-v4","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"initialize","Value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n # 加载预测数据\n context.ranker_prediction = context.options['data'].read_df()\n\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)\n # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只\n stock_count = 10\n # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]\n context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])\n # 设置每只股票占用的最大资金比例\n context.max_cash_per_instrument = 0.2\n context.options['hold_days'] = 5\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"handle_data","Value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n # 按日期过滤得到今日的预测数据\n ranker_prediction = context.ranker_prediction[\n context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')].sort_values('pred_label', ascending=False)\n \n \n\n # 1. 资金分配\n # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金\n # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)\n is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)\n cash_avg = context.portfolio.portfolio_value / context.options['hold_days']\n cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)\n cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)\n positions = {e.symbol: p.amount * p.last_sale_price\n for e, p in context.perf_tracker.position_tracker.positions.items()}\n\n # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰\n if not is_staging and cash_for_sell > 0:\n equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}\n instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(\n lambda x: x in equities and not context.has_unfinished_sell_order(equities[x]))])))\n # print('rank order for sell %s' % instruments)\n for instrument in instruments:\n context.order_target(context.symbol(instrument), 0)\n cash_for_sell -= positions[instrument]\n if cash_for_sell <= 0:\n break\n\n # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票\n buy_cash_weights = context.stock_weights\n buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])\n max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument\n for i, instrument in enumerate(buy_instruments):\n cash = cash_for_buy * buy_cash_weights[i]\n if cash > max_cash_per_instrument - positions.get(instrument, 0):\n # 确保股票持仓量不会超过每次股票最大的占用资金量\n cash = max_cash_per_instrument - positions.get(instrument, 0)\n if cash > 0:\n context.order_value(context.symbol(instrument), cash)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"prepare","Value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n pass\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_trading_start","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"volume_limit","Value":0.025,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_buy","Value":"open","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_sell","Value":"close","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"capital_base","Value":1000000,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"auto_cancel_non_tradable_orders","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"data_frequency","Value":"daily","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"price_type","Value":"后复权","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"product_type","Value":"股票","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"plot_charts","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"backtest_only","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.SHA","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-822"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"options_data","NodeId":"-822"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"history_ds","NodeId":"-822"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"benchmark_ds","NodeId":"-822"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"trading_calendar","NodeId":"-822"}],"OutputPortsInternal":[{"Name":"raw_perf","NodeId":"-822","OutputType":null}],"UsePreviousResults":false,"moduleIdForCode":19,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-9053","ModuleId":"BigQuantSpace.linear_regression.linear_regression-v1","ModuleParameters":[{"Name":"fit_intercept","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"normalize","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"key_cols","Value":"date,instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"workers","Value":1,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"other_train_parameters","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"training_ds","NodeId":"-9053"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-9053"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"model","NodeId":"-9053"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"predict_ds","NodeId":"-9053"}],"OutputPortsInternal":[{"Name":"output_model","NodeId":"-9053","OutputType":null},{"Name":"predictions","NodeId":"-9053","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":4,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-8144","ModuleId":"BigQuantSpace.RobustScaler.RobustScaler-v13","ModuleParameters":[{"Name":"scale_type","Value":"standard","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"quantile_range_min","Value":"0.01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"quantile_range_max","Value":"0.99","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"global_scale","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"train_ds","NodeId":"-8144"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-8144"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"test_ds","NodeId":"-8144"}],"OutputPortsInternal":[{"Name":"train_data","NodeId":"-8144","OutputType":null},{"Name":"test_data","NodeId":"-8144","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":6,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-8155","ModuleId":"BigQuantSpace.cached.cached-v3","ModuleParameters":[{"Name":"run","Value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3):\n train_df = input_1.read()\n features = input_2.read()\n feature_min = train_df[features].quantile(0.005)\n feature_max = train_df[features].quantile(0.995)\n train_df[features] = train_df[features].clip(feature_min,feature_max,axis=1)\n data_1 = DataSource.write_df(train_df)\n test_df = input_3.read()\n test_df[features] = test_df[features].clip(feature_min,feature_max,axis=1)\n data_2 = DataSource.write_df(test_df)\n return Outputs(data_1=data_1, data_2=data_2, data_3=None)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"post_run","Value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"input_ports","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"params","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"output_ports","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-8155"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_2","NodeId":"-8155"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_3","NodeId":"-8155"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-8155","OutputType":null},{"Name":"data_2","NodeId":"-8155","OutputType":null},{"Name":"data_3","NodeId":"-8155","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":5,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-2157","ModuleId":"BigQuantSpace.filter_concept.filter_concept-v2","ModuleParameters":[{"Name":"concept_str","Value":"智能家居","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-2157"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-2157","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":8,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true},{"Id":"-607","ModuleId":"BigQuantSpace.filter_concept.filter_concept-v2","ModuleParameters":[{"Name":"concept_str","Value":"智能家居","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-607"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-607","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":10,"IsPartOfPartialRun":null,"Comment":"","CommentCollapsed":true}],"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-8' Position='298,-7,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-15' Position='133,72,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-24' Position='659,-103,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-53' Position='330,238,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-62' Position='933,20,200,200'/><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-84' Position='321,314,200,200'/><NodePosition Node='-86' Position='969,289,200,200'/><NodePosition Node='-787' Position='454,75,200,200'/><NodePosition Node='-794' Position='414,159,200,200'/><NodePosition Node='-803' Position='935,141,200,200'/><NodePosition Node='-810' Position='976,212,200,200'/><NodePosition Node='-822' Position='788,783,200,200'/><NodePosition Node='-9053' Position='723,685,200,200'/><NodePosition Node='-8144' Position='716,580,200,200'/><NodePosition Node='-8155' Position='720,495,200,200'/><NodePosition Node='-2157' Position='338,408,200,200'/><NodePosition Node='-607' Position='973,386,200,200'/></NodePositions><NodeGroups /></DataV1>"},"IsDraft":true,"ParentExperimentId":null,"WebService":{"IsWebServiceExperiment":false,"Inputs":[],"Outputs":[],"Parameters":[{"Name":"交易日期","Value":"","ParameterDefinition":{"Name":"交易日期","FriendlyName":"交易日期","DefaultValue":"","ParameterType":"String","HasDefaultValue":true,"IsOptional":true,"ParameterRules":[],"HasRules":false,"MarkupType":0,"CredentialDescriptor":null}}],"WebServiceGroupId":null,"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions></NodePositions><NodeGroups /></DataV1>"},"DisableNodesUpdate":false,"Category":"user","Tags":[],"IsPartialRun":true}
        In [3]:
        # 本代码由可视化策略环境自动生成 2019年8月8日 21:58
        # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
        
        
        # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
        def m5_run_bigquant_run(input_1, input_2, input_3):
            train_df = input_1.read()
            features = input_2.read()
            feature_min = train_df[features].quantile(0.005)
            feature_max = train_df[features].quantile(0.995)
            train_df[features] = train_df[features].clip(feature_min,feature_max,axis=1)
            data_1 = DataSource.write_df(train_df)
            test_df = input_3.read()
            test_df[features] = test_df[features].clip(feature_min,feature_max,axis=1)
            data_2 = DataSource.write_df(test_df)
            return Outputs(data_1=data_1, data_2=data_2, data_3=None)
        
        # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
        def m5_post_run_bigquant_run(outputs):
            return outputs
        
        # 回测引擎:初始化函数,只执行一次
        def m19_initialize_bigquant_run(context):
            # 加载预测数据
            context.ranker_prediction = context.options['data'].read_df()
        
            # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
            context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
            # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)
            # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只
            stock_count = 10
            # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]
            context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])
            # 设置每只股票占用的最大资金比例
            context.max_cash_per_instrument = 0.2
            context.options['hold_days'] = 5
        
        # 回测引擎:每日数据处理函数,每天执行一次
        def m19_handle_data_bigquant_run(context, data):
            # 按日期过滤得到今日的预测数据
            ranker_prediction = context.ranker_prediction[
                context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')].sort_values('pred_label', ascending=False)
            
            
        
            # 1. 资金分配
            # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金
            # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)
            is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)
            cash_avg = context.portfolio.portfolio_value / context.options['hold_days']
            cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)
            cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)
            positions = {e.symbol: p.amount * p.last_sale_price
                         for e, p in context.perf_tracker.position_tracker.positions.items()}
        
            # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰
            if not is_staging and cash_for_sell > 0:
                equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}
                instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(
                        lambda x: x in equities and not context.has_unfinished_sell_order(equities[x]))])))
                # print('rank order for sell %s' % instruments)
                for instrument in instruments:
                    context.order_target(context.symbol(instrument), 0)
                    cash_for_sell -= positions[instrument]
                    if cash_for_sell <= 0:
                        break
        
            # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票
            buy_cash_weights = context.stock_weights
            buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])
            max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
            for i, instrument in enumerate(buy_instruments):
                cash = cash_for_buy * buy_cash_weights[i]
                if cash > max_cash_per_instrument - positions.get(instrument, 0):
                    # 确保股票持仓量不会超过每次股票最大的占用资金量
                    cash = max_cash_per_instrument - positions.get(instrument, 0)
                if cash > 0:
                    context.order_value(context.symbol(instrument), cash)
        
        # 回测引擎:准备数据,只执行一次
        def m19_prepare_bigquant_run(context):
            pass
        
        
        m1 = M.instruments.v2(
            start_date='2013-01-01',
            end_date='2018-01-01',
            market='CN_STOCK_A',
            instrument_list='',
            max_count=0
        )
        
        m2 = M.advanced_auto_labeler.v2(
            instruments=m1.data,
            label_expr="""# #号开始的表示注释
        # 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
        # 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html
        #   添加benchmark_前缀,可使用对应的benchmark数据
        # 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_
        
        # 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
        shift(close, -7) / shift(open, -1)
        
        # 极值处理:用1%和99%分位的值做clip
        clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))
        
        # 将分数映射到分类,这里使用20个分类
        all_wbins(label, 20)
        
        # 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
        where(shift(high, -1) == shift(low, -1), NaN, label)""",
            start_date='',
            end_date='',
            benchmark='000300.SHA',
            drop_na_label=True,
            cast_label_int=True
        )
        
        m3 = M.input_features.v1(
            features="""ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'long')
        ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'short')
        ta_macd_macd_12_26_9_0
        ta_macd(close_0,'long')
        ta_macd(close_0,'short')
        ta_macd(close_0,'golden_cross')
        ta_macd(close_0,'death_cross')
        ta_rsi_14_0
        ta_willr_14_0
        ta_cci_14_0
        ta_bbands_upperband_28_0
        ta_bbands_lowerband_28_0
        ta_bbands_middleband_28_0
        ta_stoch_slowk_5_3_0_3_0_0*3-ta_stoch_slowd_5_3_0_3_0_0*2
        ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'golden_cross')
        ta_kdj(high_0, low_0, close_0, 50, 9, 3, 'death_cross')
        """
        )
        
        m15 = M.general_feature_extractor.v7(
            instruments=m1.data,
            features=m3.data,
            start_date='',
            end_date='',
            before_start_days=0
        )
        
        m16 = M.derived_feature_extractor.v3(
            input_data=m15.data,
            features=m3.data,
            date_col='date',
            instrument_col='instrument',
            drop_na=False,
            remove_extra_columns=False
        )
        
        m7 = M.join.v3(
            data1=m2.data,
            data2=m16.data,
            on='date,instrument',
            how='inner',
            sort=False
        )
        
        m13 = M.dropnan.v1(
            input_data=m7.data
        )
        
        m8 = M.filter_concept.v2(
            input_1=m13.data,
            concept_str='智能家居'
        )
        
        m9 = M.instruments.v2(
            start_date=T.live_run_param('trading_date', '2018-01-01'),
            end_date=T.live_run_param('trading_date', '2019-08-07'),
            market='CN_STOCK_A',
            instrument_list='',
            max_count=0
        )
        
        m17 = M.general_feature_extractor.v7(
            instruments=m9.data,
            features=m3.data,
            start_date='',
            end_date='',
            before_start_days=0
        )
        
        m18 = M.derived_feature_extractor.v3(
            input_data=m17.data,
            features=m3.data,
            date_col='date',
            instrument_col='instrument',
            drop_na=False,
            remove_extra_columns=False
        )
        
        m14 = M.dropnan.v1(
            input_data=m18.data
        )
        
        m10 = M.filter_concept.v2(
            input_1=m14.data,
            concept_str='智能家居'
        )
        
        m5 = M.cached.v3(
            input_1=m8.data_1,
            input_2=m3.data,
            input_3=m10.data_1,
            run=m5_run_bigquant_run,
            post_run=m5_post_run_bigquant_run,
            input_ports='',
            params='{}',
            output_ports=''
        )
        
        m6 = M.RobustScaler.v13(
            train_ds=m5.data_1,
            features=m3.data,
            test_ds=m5.data_2,
            scale_type='standard',
            quantile_range_min=0.01,
            quantile_range_max=0.99,
            global_scale=True
        )
        
        m4 = M.linear_regression.v1(
            training_ds=m6.train_data,
            features=m3.data,
            predict_ds=m6.test_data,
            fit_intercept=True,
            normalize=False,
            key_cols='date,instrument',
            workers=1,
            other_train_parameters={}
        )
        
        m19 = M.trade.v4(
            instruments=m9.data,
            options_data=m4.predictions,
            start_date='',
            end_date='',
            initialize=m19_initialize_bigquant_run,
            handle_data=m19_handle_data_bigquant_run,
            prepare=m19_prepare_bigquant_run,
            volume_limit=0.025,
            order_price_field_buy='open',
            order_price_field_sell='close',
            capital_base=1000000,
            auto_cancel_non_tradable_orders=True,
            data_frequency='daily',
            price_type='后复权',
            product_type='股票',
            plot_charts=True,
            backtest_only=False,
            benchmark='000300.SHA'
        )
        
        ('----- ta_kdj    ', 'long')
        
        ('----- ta_kdj    ', 'short')
        
        ('----- ta_kdj    ', 'golden_cross')
        
        ('----- ta_kdj    ', 'death_cross')
        
        • 收益率-44.82%
        • 年化收益率-31.97%
        • 基准收益率-10.16%
        • 阿尔法-0.3
        • 贝塔0.94
        • 夏普比率-1.16
        • 胜率0.48
        • 盈亏比0.9
        • 收益波动率31.37%
        • 信息比率-0.08
        • 最大回撤45.4%
        bigcharts-data-start/{"__id":"bigchart-613559ac51d14b01988800b4b6ef594c","__type":"tabs"}/bigcharts-data-end

        (lu0817) #15

        想请教一个问题,怎么计算沪深300 or 上证50的加权每日股息率。这个指标感觉蛮重要的。


        (yangziriver) #16

        这个真不知道。向平台上的老师请教一下。这是用来计算阿尔法的吧?
        中证公司网站上能查到股息率,怎么加权不知道。
        http://www.csindex.com.cn/zh-CN/downloads/index-information#
        点指数估值


        (lu0817) #17

        看下我做的每日股息率,与原值有误差,是否可以

        克隆策略
        In [1]:
        dd=DataSource('dividend_send_CN_STOCK_A').read(['000001.SZA'],start_date='2019-05-01', fields=['cash_dividend_ratio','dividend_yield'])
        print(dd)
        
                    date  instrument      dividend_yield cash_dividend_ratio
        28679 2019-06-26  000001.SZA  0.0110941086457536                1.45
        
        In [2]:
        da=DataSource('bar1d_CN_STOCK_A').read(instruments=['000001.SZA'],start_date='2019-05-01',end_date='2019-07-01', fields=['adjust_factor','close'])
        print(da.columns)
        
        Index(['date', 'instrument', 'adjust_factor', 'close'], dtype='object')
        
        In [3]:
        da['adp']=da['close']/da['adjust_factor']
        
        In [4]:
        data  = da.merge(dd, 'left', ['date']) 
        #print(data)
        data= data.fillna(method='ffill')
        data.dropna(inplace=True)
        
        In [5]:
        data['cash_dividend_ratio']=data['cash_dividend_ratio'].astype('float')
        
        In [6]:
        data['rate']=data.cash_dividend_ratio/data.adp/10
        
        In [7]:
        print(data)
        
                 date instrument_x  adjust_factor        close        adp  \
        36 2019-06-26   000001.SZA     109.169426  1459.595215  13.370000   
        37 2019-06-27   000001.SZA     109.169426  1496.712891  13.710001   
        38 2019-06-28   000001.SZA     109.169426  1504.354736  13.780001   
        39 2019-07-01   000001.SZA     109.169426  1520.730103  13.930000   
        
           instrument_y      dividend_yield  cash_dividend_ratio      rate  
        36   000001.SZA  0.0110941086457536                 1.45  0.010845  
        37   000001.SZA  0.0110941086457536                 1.45  0.010576  
        38   000001.SZA  0.0110941086457536                 1.45  0.010522  
        39   000001.SZA  0.0110941086457536                 1.45  0.010409  
        

        (lu0817) #18

        按上面算法我做了一个上证50


        有需要的话发到你邮箱(源代码)


        (yangziriver) #19

        好的,谢谢!学习!我还没有接触到股息率这么深的内容。从网上看,有人讲股息率因子回测效果不好。我觉得还是有道理的,就像市值因子一样,不是一直有效的。中国的股市就是不断有新概念,不断有新套路。QQ 149836465