Beispiel #1
0
 def get_cols_to_label_info(cols_to_label_info, col):
     '''需要进行特殊点标注的列绘图设置信息获取'''
     
     to_plots = []
     for label_infos in cols_to_label_info[col]:
     
         lbl_col = label_infos[0]
         
         if label_infos[2] is None:
             label_infos = [lbl_col, label_infos[1], [None]*len(label_infos[1]),
                            label_infos[3]]
         
         if label_infos[3] == False:
             label_infos = [lbl_col, label_infos[1], label_infos[2],
                            [False]*len(label_infos[1])]
         elif isnull(label_infos[3]) or \
                                     all([isnull(x) for x in label_infos[3]]):
             label_infos = [lbl_col, label_infos[1], label_infos[2],
                            label_infos[1]]
         
         vals = label_infos[1]
         for k in range(len(vals)):
             series = df[df[lbl_col] == vals[k]][col]
             ln_styl = label_infos[2][k]
             lbl_str = label_infos[3][k]
             to_plots.append([series, (ln_styl, lbl_str)])
         
     return to_plots    
Beispiel #2
0
 def get_baseVol(Price):
     '''计算底仓交易量'''
     if not isnull(baseMny):
         return 100 * (baseMny // (100 * Price))
     elif isnull(baseVol):
         raise ValueError('baseMny和baseVol必须设置一个!')
     else:
         return baseVol
Beispiel #3
0
    def fit(self, Xtrain, Ytrain):
        '''
        模型训练
        
        Parameters
        ----------
        Xtrain: 训练集输入,pd.DataFrame或np.array,每行一个样本
        Ytrain: 训练集输出,pd.DataFrame或np.array,每行一个样本
        '''

        Xtrain, Ytrain = np.array(Xtrain), np.array(Ytrain)
        Nsmp, NcolX = Xtrain.shape[0], Xtrain.shape[1]  # 样本数和特征数

        # 将标签进行onehot编码
        self.Yonehot = None
        if len(Ytrain.shape) == 1 or Ytrain.shape[1] == 1:
            self.Yonehot = OneHotEncoder()
            Ytrain = self.Yonehot.fit_transform(Ytrain.reshape(-1,
                                                               1)).toarray()

        # 随机数种子
        if isnull(self.random_state):
            rnd_w = np.random.RandomState()
            rnd_b = np.random.RandomState()
        else:
            rnd_w = np.random.RandomState(self.random_state)
            rnd_b = np.random.RandomState(self.random_state)

        # 输入层——>隐藏层权重w随机化
        self.w = rnd_w.uniform(self.w_low, self.w_up, (NcolX, self.Nhide))
        # 输入层——>隐藏层偏置b随机化
        self.b = rnd_b.uniform(self.b_low, self.b_up, (1, self.Nhide))
        Bhide = np.ones([Nsmp, self.Nhide]) * self.b

        # 隐层计算
        Hide = np.matrix(self.funcAct(np.dot(Xtrain, self.w) + Bhide))

        # beta计算
        if isnull(self.C):
            iMP = np.linalg.pinv(Hide)  # Moore–Penrose广义逆
            self.beta = np.dot(iMP, Ytrain)
        else:
            Hide_ = np.dot(Hide.T, Hide) + Nsmp / self.C
            iMP = np.linalg.pinv(Hide_)  # Moore–Penrose广义逆
            iMP_ = np.dot(iMP, Hide.T)
            self.beta = np.dot(iMP_, Ytrain)

        return self
Beispiel #4
0
def DeMarkTD(series, N=9, Lag=4):
    '''
    迪马克TD序列:连续N次出现收盘价高/低于前面第Lag个收盘价就发信号。默认九转序列
    返回df中一列为原始series,一列为label,label取1表示高点信号,-1表示低点信号
    '''

    if series.name is None:
        series.name = 'series'
    col = series.name
    df = pd.DataFrame(series)

    # 是否大于前面第Lag个信号
    df[col + '_preLag'] = df[col].shift(Lag)
    df['more_preLag'] = df[col] > df[col + '_preLag']
    df['more_preLag'] = df[[col+'_preLag', 'more_preLag']].apply(lambda x:
                                    0 if isnull(x[col+'_preLag']) else \
                                    (1 if x['more_preLag'] else -1), axis=1)

    # 计数
    df['count'] = 0
    k = 0
    while k < df.shape[0]:
        if df.loc[df.index[k], 'more_preLag'] == 0:
            k += 1
        elif df.loc[df.index[k], 'more_preLag'] == 1:
            label = 1
            df.loc[df.index[k], 'count'] = label
            ktmp = k + 1
            while ktmp < df.shape[0] and \
                                df.loc[df.index[ktmp], 'more_preLag'] == 1:
                if label == N:
                    label = 1
                else:
                    label += 1
                df.loc[df.index[ktmp], 'count'] = label
                ktmp += 1
            k = ktmp
        else:
            label = -1
            df.loc[df.index[k], 'count'] = label
            ktmp = k + 1
            while ktmp < df.shape[0] and \
                                df.loc[df.index[ktmp], 'more_preLag'] == -1:
                if label == -N:
                    label = -1
                else:
                    label -= 1
                df.loc[df.index[ktmp], 'count'] = label
                ktmp += 1
            k = ktmp

    # 提取有效信号
    df['label'] = df['count'].apply(lambda x: 1 if x == N else \
                                                    (-1 if x == -N else 0))

    return df['label']
Beispiel #5
0
def cal_linear_reg_r(y, x=None):
    '''
    计算y中数据点的斜率(一元线性回归)
    y和x为list或pd.Series或np.array
    '''
    if isnull(x):
        X = pd.DataFrame({'X': range(0, len(y))})
    else:
        X = pd.DataFrame({'X': x})
    y = pd.Series(y)
    mdl = lr().fit(X, y)
    return mdl.coef_[0], mdl.intercept_
Beispiel #6
0
 def get_stopLossTradeVol(Price, VolF_stopLoss, hold_vol):
     '''止损后反向开仓量计算'''
     baseVol = get_baseVol(Price)
     if VolF_stopLoss == 0 or isnull(VolF_stopLoss):
         tradeVol = 0
     elif isinstance(VolF_stopLoss, str) and 'base' in VolF_stopLoss:
         x = int(VolF_stopLoss.split('_')[-1])
         tradeVol = get_stopLossTradeVol_baseX(baseVol, hold_vol, x)
     elif isinstance(VolF_stopLoss, str) and 'hold' in VolF_stopLoss:
         x = int(VolF_stopLoss.split('_')[-1])
         tradeVol = get_stopLossTradeVol_holdX(baseVol, hold_vol, x)
     else:
         tradeVol = VolF_stopLoss(baseVol, hold_vol)
     return tradeVol
Beispiel #7
0
def fillna_ma(series, ma=None, ma_min=2):
    '''
    用移动平均ma填充序列series中的缺失值
    ma设置填充时向前取平均数用的期数,ma_min设置最小期数
    若ma为None,则根据最大连续缺失记录数确定ma期数
    '''

    if series.name is None:
        series.name = 'series'
    col = series.name
    df = pd.DataFrame(series)

    if ma is None:
        tmp = con_count(series, lambda x: True if isnull(x) else False)
        ma = 2 * tmp.max()
        ma = max(ma, ma_min * 2)

    df[col + '_ma'] = df[col].rolling(ma, ma_min).mean()

    df[col] = df[[col, col+'_ma']].apply(lambda x:
               x[col] if not isnull(x[col]) else \
               (x[col+'_ma'] if not isnull(x[col+'_ma']) else x[col]), axis=1)

    return df[col]
Beispiel #8
0
    def predict(self, X):
        '''预测'''

        Nsmp = X.shape[0]
        Bhide = np.ones([Nsmp, self.Nhide]) * self.b
        Hide = np.matrix(self.funcAct(np.dot(X, self.w) + Bhide))
        Ypre_ = np.dot(Hide, self.beta)

        Ypre = np.zeros_like(Ypre_)
        np.put_along_axis(Ypre, Ypre_.argmax(1), 1, 1)
        Ypre = np.asarray(Ypre, dtype=np.int8)

        # 返回形式与训练数据中Y统一
        if not isnull(self.Yonehot):
            Ypre = self.Yonehot.inverse_transform(Ypre).reshape(-1, )

        return Ypre
Beispiel #9
0
def GWO(objf, func_opter_parms):
    '''
    todo: 目前仅考虑自变量连续实数情况,后面可增加自变量为离散的情况
    
    灰狼优化算法(Grey Wolf Optimizer) GWO algorithm
    
    Parameters
    ----------
    objf: 目标函数,须事先转化为求极小值问题
    func_opter_parms: FuncOpterInfo类,须设置parms_func、parms_opter、parms_log
    parms_func: 目标函数参数信息dict,key须包含
        x_lb: 自变量每个维度取值下界,list或数值,为list时长度应等于dim
        x_ub: 自变量每个维度取值上界,list或数值,为list时长度应等于dim
        dim: 自变量维度数
        
        kwargs: 目标函数接收的其它参数
    parms_opter: 优化函数参数信息dict,key须包含
        PopSize: 群体数量(每轮迭代的样本数量)
        Niter: 最大迭代寻优次数
    parms_log: 日志参数信息dict,key须包含
        logger: 日志记录器
        nshow: 若为整数,则每隔nshow轮日志输出当前最优目标函数值
    
    Returns
    -------
    更新优化过程之后的func_opter_parms
    
    参考:
    GWO.pdf
    https://github.com/7ossam81/EvoloPy
    '''

    # 参数提取
    opter_name = func_opter_parms.parms_opter['opter_name']
    if opter_name == '' or isnull(opter_name):
        opter_name = 'GWO'
    func_opter_parms.parms_opter['opter_name'] = opter_name
    # 目标函数参数
    x_lb = func_opter_parms.parms_func['x_lb']
    x_ub = func_opter_parms.parms_func['x_ub']
    dim = func_opter_parms.parms_func['dim']
    kwargs = func_opter_parms.parms_func['kwargs']
    # 优化器参数
    PopSize = func_opter_parms.parms_opter['PopSize']
    Niter = func_opter_parms.parms_opter['Niter']
    # 日志参数
    logger = func_opter_parms.parms_log['logger']
    nshow = func_opter_parms.parms_log['nshow']

    # 边界统一为列表
    if not isinstance(x_lb, list):
        x_lb = [x_lb] * dim
    if not isinstance(x_ub, list):
        x_ub = [x_ub] * dim

    # 初始化alpha, beta, delta
    AlphaPos = np.zeros(dim)
    AlphaVal = float('inf')

    BetaPos = np.zeros(dim)
    BetaVal = float('inf')

    DeltaPos = np.zeros(dim)
    DeltaVal = float('inf')

    # 初始化所有个体|样本(包括Omegas)
    pos = rand_init(PopSize, dim, x_lb, x_ub)  # 样本(个体)随机初始化

    # 保存收敛过程
    convergence_curve = np.zeros(Niter)  # 全局最优值
    convergence_curve_mean = np.zeros(Niter)  # 平均值

    # 时间记录
    strt_tm = time.time()
    func_opter_parms.set_startTime(time.strftime('%Y-%m-%d %H:%M:%S'))

    # 迭代寻优
    for l in range(0, Niter):
        # 位置过界处理
        pos = np.clip(pos, x_lb, x_ub)

        fvals_mean = 0
        for i in range(0, PopSize):
            fval = objf(pos[i, :], **kwargs)  # 目标函数值
            fvals_mean = (fvals_mean * i + fval) / (i + 1)

            # 更新Alpha, Beta, Delta
            # Alpha存放最优解,Beta存放次优解,Delta存放再次优解
            if fval < AlphaVal:
                # DeltaVal = BetaVal
                # DeltaPos = BetaPos.copy()
                # BetaVal = AlphaVal
                # BetaPos = AlphaPos.copy()
                AlphaVal = fval
                AlphaPos = pos[i, :].copy()
            if AlphaVal < fval < BetaVal:
                # DeltaVal = BetaVal
                # DeltaPos = BetaPos.copy()
                BetaVal = fval
                BetaPos = pos[i, :].copy()
            if BetaVal < fval < DeltaVal:
                DeltaVal = fval
                DeltaPos = pos[i, :].copy()

        # 更新所有个体|样本
        a = 2 - l * (2 / Niter)  # a从2线性衰减到0

        r1 = np.random.random(size=(PopSize, dim))  # r1和r2取(0, 1)随机数
        r2 = np.random.random(size=(PopSize, dim))
        A1 = 2 * a * r1 - a  # GWO.pdf (3.3)
        C1 = 2 * r2  # GWO.pdf (3.4)
        D_alpha = abs(C1 * AlphaPos - pos)  # GWO.pdf (3.5)
        X1 = AlphaPos - A1 * D_alpha  # GWO.pdf (3.6)

        r1 = np.random.random(size=(PopSize, dim))
        r2 = np.random.random(size=(PopSize, dim))
        A2 = 2 * a * r1 - a
        C2 = 2 * r2
        D_beta = abs(C2 * BetaPos - pos)
        X2 = BetaPos - A2 * D_beta

        r1 = np.random.random(size=(PopSize, dim))
        r2 = np.random.random(size=(PopSize, dim))
        A3 = 2 * a * r1 - a
        C3 = 2 * r2
        D_delta = abs(C3 * DeltaPos - pos)
        X3 = DeltaPos - A3 * D_delta

        pos = (X1 + X2 + X3) / 3  # GWO.pdf (3.7)

        # # 更新所有个体|样本
        # a = 2 - l * (2 / Niter) # a从2线性衰减到0

        # for i in range(0, PopSize):
        #     for j in range (0, dim):
        #         r1 = random.random() # r1 is a random number in [0,1]
        #         r2 = random.random() # r2 is a random number in [0,1]
        #         A1 = 2 * a * r1 - a # GWO.pdf (3.3)
        #         C1 = 2 * r2 # GWO.pdf (3.4)
        #         D_alpha = abs(C1 * AlphaPos[j] - pos[i, j]) # GWO.pdf (3.5)
        #         X1 = AlphaPos[j] - A1 * D_alpha # GWO.pdf (3.6)

        #         r1 = random.random()
        #         r2 = random.random()
        #         A2 = 2 * a * r1 - a
        #         C2 = 2 * r2
        #         D_beta = abs(C2 * BetaPos[j] - pos[i, j])
        #         X2 = BetaPos[j] - A2 * D_beta

        #         r1 = random.random()
        #         r2 = random.random()
        #         A3 = 2 * a * r1 - a
        #         C3 = 2 * r2
        #         D_delta = abs(C3 * DeltaPos[j] - pos[i, j])
        #         X3 = DeltaPos[j] - A3 * D_delta

        #         pos[i, j] = (X1 + X2 + X3) / 3

        # 每轮迭代都保存最优目标值
        convergence_curve[l] = AlphaVal
        convergence_curve_mean[l] = fvals_mean

        if nshow:
            if (l + 1) % nshow == 0:
                opter_name = func_opter_parms.parms_opter['opter_name']
                func_name = func_opter_parms.parms_func['func_name']
                logger.info(f'{opter_name} for {func_name}, iter: {l+1}, ' + \
                            f'best fval: {AlphaVal}')

    # 更新func_opter_parms
    end_tm = time.time()
    func_opter_parms.set_endTime(time.strftime('%Y-%m-%d %H:%M:%S'))
    func_opter_parms.set_exeTime(end_tm - strt_tm)
    func_opter_parms.set_convergence_curve(convergence_curve)
    func_opter_parms.set_convergence_curve_mean(convergence_curve_mean)
    func_opter_parms.set_best_val(AlphaVal)
    func_opter_parms.set_best_x(AlphaPos)

    return func_opter_parms
Beispiel #10
0
def GA(objf, func_opter_parms):
    '''
    todo: 目前仅考虑自变量连续实数情况,后面可增加自变量为离散的情况
    
    遗传算法(Genetic Algorithm) GA(实数编码)
    
    Parameters
    ----------
    objf: 目标函数,须事先转化为求极小值问题
    func_opter_parms: FuncOpterInfo类,须设置parms_func、parms_opter、parms_log
    parms_func: 目标函数参数信息dict,key须包含
        x_lb: 自变量每个维度取值下界,list或数值,为list时长度应等于dim
        x_ub: 自变量每个维度取值上界,list或数值,为list时长度应等于dim
        dim: 自变量维度数
        
        kwargs: 目标函数接收的其它参数
    parms_opter: 优化函数参数信息dict,key须包含
        PopSize: 群体数量(每轮迭代的样本数量)
        Niter: 最大迭代寻优次数
        
        Pcrs: 交叉概率
        Pmut: 变异概率
        Ntop: 每一轮(代)保留的最优个体数
    parms_log: 日志参数信息dict,key须包含
        logger: 日志记录器
        nshow: 若为整数,则每隔nshow轮日志输出当前最优目标函数值
    
    Returns
    -------
    更新优化过程之后的func_opter_parms
    
    参考:
    https://www.jianshu.com/p/8c0260c21af4
    https://github.com/7ossam81/EvoloPy
    '''
    
    # 参数提取
    opter_name = func_opter_parms.parms_opter['opter_name']
    if opter_name == '' or isnull(opter_name):
        opter_name  = 'GA'
    func_opter_parms.parms_opter['opter_name'] = opter_name
    # 目标函数参数
    x_lb = func_opter_parms.parms_func['x_lb']
    x_ub = func_opter_parms.parms_func['x_ub']
    dim = func_opter_parms.parms_func['dim']
    kwargs = func_opter_parms.parms_func['kwargs']
    # 优化器参数
    PopSize = func_opter_parms.parms_opter['PopSize']
    Niter = func_opter_parms.parms_opter['Niter']
    Pcrs = func_opter_parms.parms_opter['Pcrs']
    Pmut = func_opter_parms.parms_opter['Pmut']
    Ntop = func_opter_parms.parms_opter['Ntop']
    # 日志参数
    logger = func_opter_parms.parms_log['logger']
    nshow = func_opter_parms.parms_log['nshow']
    
    
    # 边界统一为列表
    if not isinstance(x_lb, list):
        x_lb = [x_lb] * dim
    if not isinstance(x_ub, list):
        x_ub = [x_ub] * dim
    
    # 全局最优解和全局最优值
    gBest = np.zeros(dim)
    gBestVal = float('inf')
    
    population = rand_init(PopSize, dim, x_lb, x_ub) # 样本(个体)随机初始化
    fvals = np.random.uniform(0.0, 1.0, PopSize) # 个体函数值
    
    convergence_curve = np.zeros(Niter) # 全局最优值
    convergence_curve_mean = np.zeros(Niter) # 平均值
    
    # 时间记录
    strt_tm = time.time()
    func_opter_parms.set_startTime(time.strftime('%Y-%m-%d %H:%M:%S'))
    
    for l in range(Niter):
        
        # 计算个体值
        fvals = calculateCost(objf, population, PopSize, x_lb, x_ub, **kwargs)            
        
        # 个体排序
        population, fvals = sortPopulation(population, fvals)
        
        # 最优解纪录
        gBestVal = fvals[0]
        gBest = population[0]

        # 交叉
        population = crossoverPopulaton(population, fvals, PopSize, Pcrs, Ntop,
                                        dim)           
        # 变异
        population = mutatePopulaton(population, PopSize, Pmut, Ntop,
                                     x_lb, x_ub)
        # 重复值处理
        population = clearDups(population, dim, x_lb, x_ub)
        
        # 每轮迭代都保存最优目标值
        convergence_curve[l] = gBestVal
        convergence_curve_mean[l] = np.mean(fvals)
      
        if nshow:            
            if (l+1) % nshow ==0:
                opter_name = func_opter_parms.parms_opter['opter_name']
                func_name = func_opter_parms.parms_func['func_name']
                logger.info(f'{opter_name} for {func_name}, iter: {l+1}, ' + \
                            f'best fval: {gBestVal}')
    
    
    # 更新func_opter_parms
    end_tm = time.time()  
    func_opter_parms.set_endTime(time.strftime('%Y-%m-%d %H:%M:%S'))
    func_opter_parms.set_exeTime(end_tm-strt_tm)
    func_opter_parms.set_convergence_curve(convergence_curve)
    func_opter_parms.set_convergence_curve_mean(convergence_curve_mean)
    func_opter_parms.set_best_val(gBestVal)
    func_opter_parms.set_best_x(gBest)

    return func_opter_parms
Beispiel #11
0
def HHO(objf, func_opter_parms):
    '''
    todo: 目前仅考虑自变量连续实数情况,后面可增加自变量为离散的情况
    
    哈里斯鹰优化算法(Harris Hawks Optimizer) HHO algorithm
    
    Parameters
    ----------
    objf: 目标函数,须事先转化为求极小值问题
    func_opter_parms: FuncOpterInfo类,须设置parms_func、parms_opter、parms_log
    parms_func: 目标函数参数信息dict,key须包含
        x_lb: 自变量每个维度取值下界,list或数值,为list时长度应等于dim
        x_ub: 自变量每个维度取值上界,list或数值,为list时长度应等于dim
        dim: 自变量维度数
        
        kwargs: 目标函数接收的其它参数
    parms_opter: 优化函数参数信息dict,key须包含
        PopSize: 群体数量(每轮迭代的样本数量)
        Niter: 最大迭代寻优次数
        
        alpha, beta: Levy飞行参数
    parms_log: 日志参数信息dict,key须包含
        logger: 日志记录器
        nshow: 若为整数,则每隔nshow轮日志输出当前最优目标函数值
    
    Returns
    -------
    更新优化过程之后的func_opter_parms
    
    参考:
    https://github.com/7ossam81/EvoloPy
    '''

    # 参数提取
    opter_name = func_opter_parms.parms_opter['opter_name']
    if opter_name == '' or isnull(opter_name):
        opter_name = 'HHO'
    func_opter_parms.parms_opter['opter_name'] = opter_name
    # 目标函数参数
    x_lb = func_opter_parms.parms_func['x_lb']
    x_ub = func_opter_parms.parms_func['x_ub']
    dim = func_opter_parms.parms_func['dim']
    kwargs = func_opter_parms.parms_func['kwargs']
    # 优化器参数
    PopSize = func_opter_parms.parms_opter['PopSize']
    Niter = func_opter_parms.parms_opter['Niter']
    beta = func_opter_parms.parms_opter['beta']
    alpha = func_opter_parms.parms_opter['alpha']
    # 日志参数
    logger = func_opter_parms.parms_log['logger']
    nshow = func_opter_parms.parms_log['nshow']

    # 边界统一为列表
    if not isinstance(x_lb, list):
        x_lb = [x_lb] * dim
    if not isinstance(x_ub, list):
        x_ub = [x_ub] * dim
    x_lb_, x_ub_ = np.array(x_lb), np.array(x_ub)

    # 初始化
    X = rand_init(PopSize, dim, x_lb, x_ub)

    gBest = np.zeros(dim)  # 全局最优解
    gBestVal = np.inf  # 全局最优值

    # 保存收敛过程
    convergence_curve = np.zeros(Niter)  # 全局最优值
    convergence_curve_mean = np.zeros(Niter)  # 平均值

    # 时间记录
    strt_tm = time.time()
    func_opter_parms.set_startTime(time.strftime('%Y-%m-%d %H:%M:%S'))

    # 迭代寻优
    for t in range(0, Niter):
        E1 = 2 * (1 - (t / Niter))  # 衰减因子

        fvals_mean = 0
        for i in range(0, PopSize):
            X[i, :] = np.clip(X[i, :], x_lb, x_ub)  # 越界处理
            fval = objf(X[i, :], **kwargs)  # 目标函数值
            fvals_mean = (fvals_mean * i + fval) / (i + 1)

            # 更新兔子位置(最优解)
            if fval < gBestVal:
                gBestVal = fval
                gBest = X[i, :].copy()

            # 种群更新
            E0 = 2 * random.random() - 1  # -1 < E0 < 1
            EE = E1 * E0  # HHO.pdf Eq.(3)

            # 探索策略(Exploration phase),HHO.pdf Eq.(1)
            if abs(EE) >= 1:
                q = random.random()
                if q >= 0.5:
                    # 随机选择在别的样本基础上进行探索
                    rnd_idx = math.floor(PopSize * random.random())
                    X_rnd = X[rnd_idx, :]
                    r1 = random.random()
                    r2 = random.random()
                    X[i, :] = X_rnd - r1 * abs(X_rnd - 2 * r2 * X[i, :])
                elif q < 0.5:
                    # 在最优样本上和整体样本均值基础上进行探索
                    r3 = random.random()
                    r4 = random.random()
                    Xm = X.mean(axis=0)
                    X[i, :] = gBest - Xm - r3 * (x_lb_ + r4 * (x_ub_ - x_lb_))

            # 包围策略(Exploitation phase)
            elif abs(EE) < 1:
                r = random.random()

                if r >= 0.5 and abs(EE) < 0.5:
                    # HHO.pdf Eq.(6)
                    X[i, :] = gBest - EE * abs(gBest - X[i, :])

                elif r >= 0.5 and abs(EE) >= 0.5:
                    # HHO.pdf Eq.(4)
                    J = 2 * (1 - random.random())  # 随机跳跃幅度
                    X[i, :] = gBest - X[i, :] - EE * abs(J * gBest - X[i, :])

                elif r < 0.5 and abs(EE) >= 0.5:  # HHO.pdf Eq.(10)
                    J = 2 * (1 - random.random())  # HHO.pdf Eq.(7)
                    Y = gBest - EE * abs(J * gBest - X[i, :])
                    Y = np.clip(Y, x_lb, x_ub)
                    if objf(Y, **kwargs) < fval:
                        X[i, :] = Y.copy()
                    else:
                        # HHO.pdf Eq.(8)
                        S = np.random.randn(dim)
                        Z = Y + S * Levy(dim, beta=beta, alpha=alpha)
                        Z = np.clip(Z, x_lb, x_ub)
                        if objf(Z, **kwargs) < fval:
                            X[i, :] = Z.copy()

                elif r < 0.5 and abs(EE) < 0.5:  # HHO.pdf Eq.(11)
                    J = 2 * (1 - random.random())
                    # HHO.pdf Eq.(12)
                    Y = gBest - EE * abs(J * gBest - X.mean(0))
                    Y = np.clip(Y, x_lb, x_ub)
                    if objf(Y, **kwargs) < fval:
                        X[i, :] = Y.copy()
                    else:
                        # HHO.pdf Eq.(13)
                        S = np.random.randn(dim)
                        Z = Y + S * Levy(dim, beta=beta, alpha=alpha)
                        Z = np.clip(Z, x_lb, x_ub)
                        if objf(Z, **kwargs) < fval:
                            X[i, :] = Z.copy()

        # 每轮迭代都保存最优目标值
        convergence_curve[t] = gBestVal
        convergence_curve_mean[t] = fvals_mean

        if nshow:
            if (t + 1) % nshow == 0:
                opter_name = func_opter_parms.parms_opter['opter_name']
                func_name = func_opter_parms.parms_func['func_name']
                logger.info(f'{opter_name} for {func_name}, iter: {t+1}, ' + \
                            f'best fval: {gBestVal}')

    # 更新func_opter_parms
    end_tm = time.time()
    func_opter_parms.set_endTime(time.strftime('%Y-%m-%d %H:%M:%S'))
    func_opter_parms.set_exeTime(end_tm - strt_tm)
    func_opter_parms.set_convergence_curve(convergence_curve)
    func_opter_parms.set_convergence_curve_mean(convergence_curve_mean)
    func_opter_parms.set_best_val(gBestVal)
    func_opter_parms.set_best_x(gBest)

    return func_opter_parms
Beispiel #12
0
def PSO(objf, func_opter_parms):
    '''
    todo: 目前仅考虑自变量连续实数情况,后面可增加自变量为离散的情况
    
    粒子群优化算法(Particle Swarm Optimization) PSO algorithm
    
    Parameters
    ----------
    objf: 目标函数,须事先转化为求极小值问题
    func_opter_parms: FuncOpterInfo类,须设置parms_func、parms_opter、parms_log
    parms_func: 目标函数参数信息dict,key须包含
        x_lb: 自变量每个维度取值下界,list或数值,为list时长度应等于dim
        x_ub: 自变量每个维度取值上界,list或数值,为list时长度应等于dim
        dim: 自变量维度数
        
        kwargs: 目标函数接收的其它参数
    parms_opter: 优化函数参数信息dict,key须包含
        PopSize: 群体数量(每轮迭代的样本数量)
        Niter: 最大迭代寻优次数
        
        v_maxs: 自变量每个维度单次绝对变化量上界,list或数值,为list时长度应等于dim
        w_max: 惯性因子w最大值,w用于平衡全局搜索和局部搜索,w值越大全局寻优能力更强
        w_min: 惯性因子最小值
        w_fix: 若w_fix设置为(0, 1)之间的值,则惯性因子w固定为w_fix,不进行动态更新
            默认动态更新w时采用线性递减方法
        c1, c2: 学习因子
    parms_log: 日志参数信息dict,key须包含
        logger: 日志记录器
        nshow: 若为整数,则每隔nshow轮日志输出当前最优目标函数值
    
    Returns
    -------
    更新优化过程之后的func_opter_parms
    
    参考:
    https://www.jianshu.com/p/8c0260c21af4
    https://github.com/7ossam81/EvoloPy
    '''

    # 参数提取
    opter_name = func_opter_parms.parms_opter['opter_name']
    if opter_name == '' or isnull(opter_name):
        opter_name = 'PSO'
    func_opter_parms.parms_opter['opter_name'] = opter_name
    # 目标函数参数
    x_lb = func_opter_parms.parms_func['x_lb']
    x_ub = func_opter_parms.parms_func['x_ub']
    dim = func_opter_parms.parms_func['dim']
    kwargs = func_opter_parms.parms_func['kwargs']
    # 优化器参数
    PopSize = func_opter_parms.parms_opter['PopSize']
    Niter = func_opter_parms.parms_opter['Niter']
    v_maxs = func_opter_parms.parms_opter['v_maxs']
    w_max = func_opter_parms.parms_opter['w_max']
    w_min = func_opter_parms.parms_opter['w_min']
    w_fix = func_opter_parms.parms_opter['w_fix']
    c1 = func_opter_parms.parms_opter['c1']
    c2 = func_opter_parms.parms_opter['c2']
    # 日志参数
    logger = func_opter_parms.parms_log['logger']
    nshow = func_opter_parms.parms_log['nshow']

    # 边界统一为列表
    if not isinstance(x_lb, list):
        x_lb = [x_lb] * dim
    if not isinstance(x_ub, list):
        x_ub = [x_ub] * dim

    if not isinstance(v_maxs, list):
        if isnull(v_maxs):
            v_maxs = [(x_ub[_] - x_lb[_]) / 10 for _ in range(dim)]
        else:
            v_maxs = [v_maxs] * dim
    v_mins = [-x for x in v_maxs]

    # 初始化
    vel = np.zeros((PopSize, dim))  # 初始速度

    pBestVals = np.zeros(PopSize)  # 每个个体(样本)迭代过程中的最优值
    pBestVals.fill(float('inf'))  # 最小值问题初始化为正无穷大

    pBest = np.zeros((PopSize, dim))  # 每个个体(样本)迭代过程中的最优解
    gBest = np.zeros(dim)  # 保存全局最优解

    gBestVal = float('inf')  # 全局最优值

    pos = rand_init(PopSize, dim, x_lb, x_ub)  # 样本(个体)随机初始化

    # 保存收敛过程
    convergence_curve = np.zeros(Niter)  # 全局最优值
    convergence_curve_mean = np.zeros(Niter)  # 平均值

    # 时间记录
    strt_tm = time.time()
    func_opter_parms.set_startTime(time.strftime('%Y-%m-%d %H:%M:%S'))

    # 迭代寻优
    for l in range(0, Niter):
        # 位置过界处理
        pos = np.clip(pos, x_lb, x_ub)

        fvals_mean = 0
        for i in range(0, PopSize):
            fval = objf(pos[i, :], **kwargs)  # 目标函数值
            fvals_mean = (fvals_mean * i + fval) / (i + 1)

            # 更新每个个体的最优解(理解为局部最优解)
            if pBestVals[i] > fval:
                pBestVals[i] = fval
                pBest[i, :] = pos[i, :].copy()

            # 更新全局最优解
            if gBestVal > fval:
                gBestVal = fval
                gBest = pos[i, :].copy()

        # 更新w(w为惯性因子,值越大全局寻优能力更强)
        if not w_fix:
            # w采用线型递减方式动态更新,也可采用其它方式更新
            w = w_max - l * ((w_max - w_min) / Niter)
        else:
            if not 0 < w_fix < 1:
                raise ValueError('固定惯性因子w范围应该在(0, 1)内!')
            w = w_fix

        # # 速度和位置更新
        # for i in range(0, PopSize):
        #     for j in range (0, dim):
        #         r1 = random.random()
        #         r2 = random.random()
        #         # 速度更新
        #         vel[i, j] = w * vel[i, j] + \
        #                     c1 * r1 * (pBest[i, j] - pos[i,j]) + \
        #                     c2 * r2 * (gBest[j] - pos[i, j])
        #         # 速度过界处理
        #         if vel[i, j] > v_maxs[j]:
        #             vel[i, j] = v_maxs[j]
        #         if vel[i, j] < v_mins[j]:
        #             vel[i, j] = v_mins[j]
        #         # 位置更新
        #         pos[i, j] = pos[i, j] + vel[i, j]

        # 速度和位置更新
        r1 = np.random.random(size=(PopSize, dim))
        r2 = np.random.random(size=(PopSize, dim))
        # 速度更新
        vel = w * vel + c1 * r1 * (pBest - pos) + c2 * r2 * (gBest - pos)
        vel = np.clip(vel, v_mins, v_maxs)  # 速度过界处理
        pos = pos + vel  # 位置更新

        # 每轮迭代都保存最优目标值
        convergence_curve[l] = gBestVal
        convergence_curve_mean[l] = fvals_mean

        if nshow:
            if (l + 1) % nshow == 0:
                opter_name = func_opter_parms.parms_opter['opter_name']
                func_name = func_opter_parms.parms_func['func_name']
                logger.info(f'{opter_name} for {func_name}, iter: {l+1}, ' + \
                            f'best fval: {gBestVal}')

    # 更新func_opter_parms
    end_tm = time.time()
    func_opter_parms.set_endTime(time.strftime('%Y-%m-%d %H:%M:%S'))
    func_opter_parms.set_exeTime(end_tm - strt_tm)
    func_opter_parms.set_convergence_curve(convergence_curve)
    func_opter_parms.set_convergence_curve_mean(convergence_curve_mean)
    func_opter_parms.set_best_val(gBestVal)
    func_opter_parms.set_best_x(gBest)

    return func_opter_parms
Beispiel #13
0
def lgb_train(X_train,
              y_train,
              X_valid=None,
              y_valid=None,
              objective=None,
              parms_mdl=None,
              parms_train=None,
              mdl_save_path=None,
              logger=None):
    '''
    lightgbm模型训练
    X_train, y_train, X_valid, y_valid为pd或np格式,最好为pd格式数据
    objective为任务类型,支持的任务类型(可添加其他任务类型):
        multiclass、binary、regression
    parms_mdl和parms_train为模型参数和训练参数(dict)
    mdl_save_path为模型本地化路径
    返回训练好的模型和损失函数变化曲线数据
    '''

    logger = simple_logger() if logger is None else logger

    # 检查任务相关参数(注意:若添加其他任务,可能需要添加对应需要检查的参数)
    num_class = len(set(y_train)) if objective == 'multiclass' else 1
    objective, num_class = check_parms_mdl(parms_mdl,
                                           objective,
                                           num_class,
                                           logger=logger)
    # 模型参数和训练参数准备
    parms_mdl = get_parms_mdl(parms_mdl=parms_mdl,
                              objective=objective,
                              num_class=num_class,
                              logger=logger)
    parms_train = get_parms_TrainOrCV(parms_TrainOrCV=parms_train)

    # 数据集准备
    datTrain = lgb.Dataset(
        X_train,
        y_train,
        categorical_feature=parms_train['categorical_feature'])
    if X_valid is None and y_valid is None:
        datValid = None
    else:
        datValid = lgb.Dataset(
            X_valid,
            y_valid,
            categorical_feature=parms_train['categorical_feature'])
    valid_sets = [datTrain, datValid] if datValid is not None else [datTrain]
    valid_names = ['train', 'valid'] if X_valid is not None else ['train']
    evals_result = {}

    # 模型训练
    logger.info('模型训练中...')
    mdl = lgb.train(params=parms_mdl,
                    train_set=datTrain,
                    num_boost_round=parms_train['num_boost_round'],
                    valid_sets=valid_sets,
                    valid_names=valid_names,
                    fobj=parms_train['fobj'],
                    feval=parms_train['feval'],
                    init_model=parms_train['init_model'],
                    feature_name=parms_train['feature_name'],
                    categorical_feature=parms_train['categorical_feature'],
                    early_stopping_rounds=parms_train['early_stopping_rounds'],
                    evals_result=evals_result,
                    verbose_eval=parms_train['verbose_eval'],
                    learning_rates=parms_train['learning_rates'],
                    keep_training_booster=parms_train['keep_training_booster'],
                    callbacks=parms_train['callbacks'])

    # 模型保存
    if not isnull(mdl_save_path):
        # joblib.dump(mdl, 'mdl_save_path')
        pickleFile(mdl, 'mdl_save_path')

    return mdl, evals_result
Beispiel #14
0
def cal_sig_gains(data,
                  sig_col,
                  VolF_add='base_1',
                  VolF_sub='base_1',
                  VolF_stopLoss=0,
                  IgnrSigNoStop=False,
                  col_price='close',
                  col_price_buy='close',
                  col_price_sel='close',
                  baseMny=200000,
                  baseVol=None,
                  fee=1.5 / 1000,
                  max_loss=1.0 / 100,
                  max_gain=2.0 / 100,
                  max_down=0.5 / 100):
    '''
    统计信号收益情况(A股)
    
    Parameters
    ----------
    data: 行情数据,其列须包含:
          sig_col列为信号列,其中1为做空(卖出)信号,-1为做多(买入)信号,0为不操作
          注:sig_col列的值只能包含-1和1和0
          col_price为结算价格列
          col_price_buy和col_price_sel分别为做多(买入)和做空(卖出)操作的价格列
    VolF_add: 自定义开仓/加仓操作时的交易量函数,其输入和输出格式应为:
        def VolF_add(baseVol, holdVol):
            # Parameters:
            #    baseVol:底仓量;
            #    holdVol:当前持仓量
            # Returns:
            # tradeVol:计划交易量    
            ......
            return tradeVol
        当VolF_add指定为'base_x'时,使用预定义函数get_AddTradeVol_baseX,
        其交易计划为:
            无持仓时开底仓,有持仓时开底仓的x倍
        当VolF_add指定为'hold_x'时,使用预定义函数get_AddTradeVol_holdX,
        其交易计划为:
            无持仓时开底仓,有持仓时开持仓的x倍
    VolF_sub: 自定义平仓/减仓操作时的交易量函数,其输入和输出格式应为:
        def VolF_sub(baseVol, holdVol):
            # Parameters:
            #    baseVol:底仓量;
            #    holdVol:当前持仓量
            # Returns:
            # tradeVol:计划交易量    
            ......
            return tradeVol
        当VolF_sub指定为'base_x'时,使用预定义函数get_SubTradeVol_baseX,
        其交易计划为:
            减底仓的x倍(若超过了持仓量相当于平仓后反向开仓)
        当VolF_sub指定为'hold_x'时,使用预定义函数get_SubTradeVol_holdX,
        其交易计划为:
            减持仓的x倍(x大于1时相当于平仓后反向开仓)
        当VolF_sub指定为'hold_base_x'时,使用预定义函数get_SubTradeVol_holdbaseX,
        其交易计划为:
            平仓后反向以baseVol的x倍反向开仓
    VolF_stopLoss: 自定义止损后的反向交易量函数,其输入和输出格式应为:
        def VolF_stopLoss(baseVol, holdVol):
            # Parameters:
            #    baseVol:底仓量;
            #    holdVol:当前持仓量
            # Returns:
            # tradeVol:计划交易量    
            ......
            return tradeVol
        当VolF_stopLoss指定为0或None或np.nan时,止损不反向开仓
        当VolF_stopLoss指定为'base_x'时,使用预定义函数get_stopLossTradeVol_baseX,
        其交易计划为:
            反向开底仓的x倍
        当VolF_stopLoss指定为'hold_x'时,使用预定义函数get_stopLossTradeVol_holdX,
        其交易计划为:
            反向开持仓的x倍
    IgnrSigNoStop: 当有持仓且没有触及止盈止损条件时是否忽略信号,
                   为True时忽略,为False时不忽略
    baseMny: 开底仓交易限额
    baseVol: 开底仓交易限量
        注:同时设置baseMny和baseVol时以baseMny为准
    fee: 单向交易综合成本比例(双向收费)
    max_loss: 止损比例
    max_gain: 止盈比例
    max_down: 平仓最大回撤比例
    
    Returns
    -------
    gain_stats: 包含['收益/最大占用比', '总收益', '总回收', '总投入', '最大占用']列
    df: 包含中间过程数据
    '''
    def get_baseVol(Price):
        '''计算底仓交易量'''
        if not isnull(baseMny):
            return 100 * (baseMny // (100 * Price))
        elif isnull(baseVol):
            raise ValueError('baseMny和baseVol必须设置一个!')
        else:
            return baseVol

    def get_AddTradeVol_baseX(baseVol, holdVol, x):
        '''无持仓则开底仓,有持仓则开底仓的x倍'''
        if abs(holdVol) == 0:
            return baseVol
        return baseVol * x

    def get_AddTradeVol_holdX(baseVol, holdVol, x):
        '''无持仓则开底仓,有持仓则开持仓的x倍'''
        if abs(holdVol) == 0:
            return baseVol
        return abs(holdVol * x)

    def get_SubTradeVol_baseX(baseVol, holdVol, x):
        '''减底仓的x倍(超过持仓即为反向开仓)'''
        return baseVol * x

    def get_SubTradeVol_holdX(baseVol, holdVol, x):
        '''减持仓的x倍(x大于1即为反向开仓)'''
        return abs(holdVol * x)

    def get_SubTradeVol_holdbaseX(baseVol, holdVol, x):
        '''平仓后反向开底仓的x倍'''
        return abs(holdVol) + baseVol * x

    def get_stopLossTradeVol_baseX(baseVol, holdVol, x):
        '''止损后反向开底仓的x倍'''
        return baseVol * x

    def get_stopLossTradeVol_holdX(baseVol, holdVol, x):
        '''止损后反向开持仓的x倍'''
        return abs(holdVol * x)

    def get_AddTradeVol(Price, VolF_add, hold_vol):
        '''开/加仓量计算'''
        baseVol = get_baseVol(Price)
        if isinstance(VolF_add, str) and 'base' in VolF_add:
            x = int(VolF_add.split('_')[-1])
            tradeVol = get_AddTradeVol_baseX(baseVol, hold_vol, x)
        elif isinstance(VolF_add, str) and 'hold' in VolF_add:
            x = int(VolF_add.split('_')[-1])
            tradeVol = get_AddTradeVol_holdX(baseVol, hold_vol, x)
        else:
            tradeVol = VolF_add(baseVol, hold_vol)
        return tradeVol

    def get_SubTradeVol(Price, VolF_sub, hold_vol):
        '''平/减仓量计算'''
        baseVol = get_baseVol(Price)
        if isinstance(VolF_sub, str) and\
                                    'base' in VolF_sub and 'hold' in VolF_sub:
            x = int(VolF_sub.split('_')[-1])
            tradeVol = get_SubTradeVol_holdbaseX(baseVol, hold_vol, x)
        elif isinstance(VolF_sub, str) and 'base' in VolF_sub:
            x = int(VolF_sub.split('_')[-1])
            tradeVol = get_SubTradeVol_baseX(baseVol, hold_vol, x)
        elif isinstance(VolF_sub, str) and 'hold' in VolF_sub:
            x = int(VolF_sub.split('_')[-1])
            tradeVol = get_SubTradeVol_holdX(baseVol, hold_vol, x)
        else:
            tradeVol = VolF_sub(baseVol, hold_vol)
        return tradeVol

    def get_stopLossTradeVol(Price, VolF_stopLoss, hold_vol):
        '''止损后反向开仓量计算'''
        baseVol = get_baseVol(Price)
        if VolF_stopLoss == 0 or isnull(VolF_stopLoss):
            tradeVol = 0
        elif isinstance(VolF_stopLoss, str) and 'base' in VolF_stopLoss:
            x = int(VolF_stopLoss.split('_')[-1])
            tradeVol = get_stopLossTradeVol_baseX(baseVol, hold_vol, x)
        elif isinstance(VolF_stopLoss, str) and 'hold' in VolF_stopLoss:
            x = int(VolF_stopLoss.split('_')[-1])
            tradeVol = get_stopLossTradeVol_holdX(baseVol, hold_vol, x)
        else:
            tradeVol = VolF_stopLoss(baseVol, hold_vol)
        return tradeVol

    def get_tradeVol(sig, act_stop, holdVol_pre, buyPrice, selPrice):
        '''
        根据操作信号、止盈止损信号、前持仓量和交易价格计算交易方向和计划交易量
        '''
        if sig == 0:
            if holdVol_pre == 0 or act_stop == 0:
                return 0, 0
            else:
                if holdVol_pre > 0:  # 做多止损或止盈
                    if act_stop == 0.5:  # 做多止损
                        stopLossTradeVol = get_stopLossTradeVol(
                            selPrice, VolF_stopLoss, holdVol_pre)
                        return 1, holdVol_pre + stopLossTradeVol
                    else:  # 做多止盈
                        return 1, holdVol_pre
                elif holdVol_pre < 0:  # 做空止损或止盈
                    if act_stop == -0.5:  # 做空止损
                        stopLossTradeVol = get_stopLossTradeVol(
                            buyPrice, VolF_stopLoss, holdVol_pre)
                        return -1, abs(holdVol_pre) + stopLossTradeVol
                    else:  # 做空止盈
                        return -1, abs(holdVol_pre)
        elif holdVol_pre == 0:
            tradePrice = buyPrice if sig == -1 else selPrice
            tradeVol = get_AddTradeVol(tradePrice, VolF_add, holdVol_pre)
            return sig, tradeVol
        elif holdVol_pre > 0:  # 持有做多仓位
            if sig == 1:
                if act_stop == 0:
                    if not IgnrSigNoStop:  # 正常减/平做多仓位
                        selVol = get_SubTradeVol(selPrice, VolF_sub,
                                                 holdVol_pre)
                        return sig, selVol
                    else:  # 不触及止盈止损时忽略信号(不操作)
                        return 0, 0
                else:  # 需要先止损或止盈后再开做空仓位
                    selVol = get_AddTradeVol(selPrice, VolF_add, 0)
                    if act_stop == 0.5:  # 先止损后再开做空仓位
                        stopRevSelVol = get_stopLossTradeVol(
                            selPrice, VolF_stopLoss, holdVol_pre)
                        return sig, max(selVol, stopRevSelVol) + holdVol_pre
                    else:  # 先止盈后再开做空仓位
                        return sig, selVol + holdVol_pre
            elif sig == -1:
                if act_stop == 0:
                    if not IgnrSigNoStop:  # 正常加做多仓位
                        buyVol = get_AddTradeVol(buyPrice, VolF_add,
                                                 holdVol_pre)
                        return sig, buyVol
                    else:  # 不触及止盈止损时忽略信号(不操作)
                        return 0, 0
                else:  # 需要先止损或止盈后再开做多仓位
                    buyVol = get_AddTradeVol(buyPrice, VolF_add, 0)
                    if act_stop == 0.5:  # 先止损后再开做多仓位
                        stopRevSelVol = get_stopLossTradeVol(
                            selPrice, VolF_stopLoss, holdVol_pre)
                        selVolAll = stopRevSelVol + holdVol_pre
                        if buyVol == selVolAll:
                            return 0, 0
                        elif buyVol > selVolAll:
                            return -1, buyVol - selVolAll
                        else:
                            return 1, selVolAll - buyVol
                    else:  # 先止盈后再开做多仓位
                        if buyVol == holdVol_pre:
                            return 0, 0
                        elif buyVol > holdVol_pre:
                            return -1, buyVol - holdVol_pre
                        else:
                            return 1, holdVol_pre - buyVol
        elif holdVol_pre < 0:  # 持有做空仓位
            if sig == 1:
                if act_stop == 0:
                    if not IgnrSigNoStop:  # 正常加做空仓位
                        selVol = get_AddTradeVol(selPrice, VolF_add,
                                                 holdVol_pre)
                        return sig, selVol
                    else:  # 不触及止盈止损时忽略信号(不操作)
                        return 0, 0
                else:  # 需要先止盈或止损后再开做空仓位
                    selVol = get_AddTradeVol(selPrice, VolF_add, 0)
                    if act_stop == -0.5:  # 先止损再开做空仓位
                        stopRevBuyVol = get_stopLossTradeVol(
                            buyPrice, VolF_stopLoss, holdVol_pre)
                        buyVolAll = stopRevBuyVol + abs(holdVol_pre)
                        if selVol == buyVolAll:
                            return 0, 0
                        elif selVol > buyVolAll:
                            return 1, selVol - buyVolAll
                        else:
                            return -1, buyVolAll - selVol
                    else:  # 先止盈再开做空仓位
                        if selVol == abs(holdVol_pre):
                            return 0, 0
                        elif selVol > abs(holdVol_pre):
                            return 1, selVol - abs(holdVol_pre)
                        else:
                            return -1, abs(holdVol_pre) - selVol
            elif sig == -1:
                if act_stop == 0:
                    if not IgnrSigNoStop:  # 正常减/平做空仓位
                        buyVol = get_SubTradeVol(buyPrice, VolF_sub,
                                                 holdVol_pre)
                        return sig, buyVol
                    else:  # 不触及止盈止损时忽略信号(不操作)
                        return 0, 0
                else:  # 需要先止盈或止损后再开做多仓位
                    buyVol = get_AddTradeVol(buyPrice, VolF_add, 0)
                    if act_stop == -0.5:  # 先止损再开做多仓位
                        stopRevBuyVol = get_stopLossTradeVol(
                            buyPrice, VolF_stopLoss, holdVol_pre)
                        return sig, max(buyVol, stopRevBuyVol) + \
                                    abs(holdVol_pre)
                    else:  # 先止盈再开做多仓位
                        return sig, buyVol + abs(holdVol_pre)

    def buy_act(df, k, buy_price, buy_vol, hold_vol_pre, hold_cost_pre):
        '''买入操作记录'''
        df.loc[df.index[k], 'buyVol'] = buy_vol
        df.loc[df.index[k], 'holdVol'] = buy_vol + hold_vol_pre
        cashPut = buy_vol * buy_price * (1 + fee)
        df.loc[df.index[k], 'cashPut'] = cashPut
        if hold_vol_pre >= 0:  # 做多加仓或开仓
            df.loc[df.index[k], 'holdCost'] = hold_cost_pre + cashPut
        else:
            if buy_vol < abs(hold_vol_pre):  # 减做空仓位
                df.loc[df.index[k], 'holdCost'] = hold_cost_pre + cashPut
            elif buy_vol > abs(hold_vol_pre):  # 平做空仓位后反向开做多仓位
                df.loc[df.index[k], 'holdCost'] = \
                               (buy_vol + hold_vol_pre) * buy_price * (1+fee)
        return df

    def sel_act(df, k, sel_price, sel_vol, hold_vol_pre, hold_cost_pre):
        '''卖出操作记录'''
        df.loc[df.index[k], 'selVol'] = sel_vol
        df.loc[df.index[k], 'holdVol'] = hold_vol_pre - sel_vol
        cashGet = sel_vol * sel_price * (1 - fee)
        df.loc[df.index[k], 'cashGet'] = cashGet
        if hold_vol_pre <= 0:  # 做空加仓或开仓
            df.loc[df.index[k], 'holdCost'] = hold_cost_pre - cashGet
        else:
            if sel_vol < hold_vol_pre:  # 减做多仓位
                df.loc[df.index[k], 'holdCost'] = hold_cost_pre - cashGet
            elif sel_vol > hold_vol_pre:  # 平做多仓位后反向开做空仓位
                df.loc[df.index[k], 'holdCost'] = \
                                (hold_vol_pre-sel_vol) * sel_price * (1-fee)
        return df

    act_types = list(data[sig_col].unique())
    if not check_l_in_l0(act_types, [0, 1, -1]):
        raise ValueError(f'data.{sig_col}列的值只能是0或1或-1!')

    cols = list(set([sig_col, col_price, col_price_buy, col_price_sel]))
    df = data.reindex(columns=cols)

    df['buyVol'] = 0  # 做多(买入)量
    df['selVol'] = 0  # 做空(卖出)量
    df['holdVol'] = 0  # 持仓量(交易完成后)
    df['holdVal'] = 0  # 持仓价值(交易完成后)
    df['cashPut'] = 0  # 现金流出
    df['cashGet'] = 0  # 现金流入

    df['holdCost'] = 0  # 现有持仓总成本(交易完成后)
    df['holdPreGainPct'] = 0  # 持仓盈亏(交易完成前)
    df['holdPreGainPctMax'] = 0  # 持仓达到过的最高收益(交易完成前)
    df['holdPreMaxDown'] = 0  # 持仓最大回撤(交易完成前)
    df['act_stop'] = 0  # 止盈止损标注(0.5多止损,1.5多止盈,-0.5空止损,-1.5空止盈)
    df['act'] = df[sig_col]  # 实际操作(1做空,-1做多)(用于信号被过滤时进行更正)
    df['holdGainPct'] = 0  # 现有持仓盈亏(交易完成后)

    last_act = 0  # 上一个操作类型
    for k in range(0, df.shape[0]):
        # 交易前持仓量
        if k == 0:
            holdVol_pre = 0
            holdCost_pre = 0
            act_stop = 0
            holdPreGainPct = 0
            holdPreGainPctMax = 0
            holdPreMaxDown = 0
        else:
            holdVol_pre = df.loc[df.index[k - 1], 'holdVol']
            holdCost_pre = df.loc[df.index[k - 1], 'holdCost']
            if holdVol_pre == 0:
                act_stop = 0
                holdPreGainPct = 0
                holdPreGainPctMax = 0
                holdPreMaxDown = 0
            else:
                # 检查止盈止损是否触及
                Price = df.loc[df.index[k], col_price]
                if holdVol_pre > 0:
                    holdVal_pre = holdVol_pre * Price * (1 - fee)
                elif holdVol_pre < 0:
                    holdVal_pre = holdVol_pre * Price * (1 + fee)
                holdPreGainPct = cal_gain_pct(holdCost_pre, holdVal_pre, vP0=0)
                # 若前一次有操作,则计算持仓盈利和回撤(交易前)须重新计算
                if last_act == 0:
                    holdPreGainPctMax = max(
                        holdPreGainPct, df.loc[df.index[k - 1],
                                               'holdPreGainPctMax'])
                else:
                    holdPreGainPctMax = max(holdPreGainPct, 0)
                holdPreMaxDown = holdPreGainPctMax - holdPreGainPct
                # 没有止盈止损
                if isnull(max_loss) and isnull(max_gain) and isnull(max_down):
                    act_stop = 0
                # 固定比率止盈止损
                elif not isnull(max_loss) and not isnull(max_gain):
                    if holdPreGainPct <= -max_loss:  # 止损
                        if holdCost_pre > 0:
                            act_stop = 0.5  # 做多止损
                        elif holdCost_pre < 0:
                            act_stop = -0.5  # 做空止损
                        else:
                            act_stop = 0
                    elif holdPreGainPct >= max_gain:  # 止盈
                        if holdCost_pre > 0:
                            act_stop = 1.5  # 做多止盈
                        elif holdCost_pre < 0:
                            act_stop = -1.5  # 做空止盈
                        else:
                            act_stop = 0
                    else:
                        act_stop = 0
                # 最大回撤平仓
                elif not isnull(max_down):
                    if holdPreMaxDown < max_down:
                        act_stop = 0
                    else:
                        if holdCost_pre > 0:
                            # act_stop = 0.5 # 做多平仓
                            if holdPreGainPct < 0:
                                act_stop = 0.5  # 做多止损
                            elif holdPreGainPct > 0:
                                act_stop = 1.5  # 做多止盈
                            else:
                                act_stop = 0
                        elif holdCost_pre < 0:
                            # act_stop = -0.5 # 做空平仓
                            if holdPreGainPct < 0:
                                act_stop = -0.5  # 做空止损
                            elif holdPreGainPct > 0:
                                act_stop = -1.5  # 做空止盈
                            else:
                                act_stop = 0
                        else:
                            act_stop = 0

        df.loc[df.index[k], 'act_stop'] = act_stop
        df.loc[df.index[k], 'holdPreGainPct'] = holdPreGainPct
        df.loc[df.index[k], 'holdPreGainPctMax'] = holdPreGainPctMax
        df.loc[df.index[k], 'holdPreMaxDown'] = holdPreMaxDown

        buyPrice = df.loc[df.index[k], col_price_buy]
        selPrice = df.loc[df.index[k], col_price_sel]
        sig = df.loc[df.index[k], sig_col]  # 操作信号

        # 确定交易计划
        if sig == 1:
            act, tradeVol = get_tradeVol(sig, act_stop, holdVol_pre, buyPrice,
                                         selPrice)
        elif sig == -1:
            act, tradeVol = get_tradeVol(sig, act_stop, holdVol_pre, buyPrice,
                                         selPrice)
        else:
            act, tradeVol = get_tradeVol(sig, act_stop, holdVol_pre, buyPrice,
                                         selPrice)

        # 更新被过滤信号实际操作
        if IgnrSigNoStop and sig != 0 and act == 0:
            df.loc[df.index[k], 'act'] = act

        # 交易执行
        if act == 0:
            df.loc[df.index[k], 'holdVol'] = holdVol_pre
            df.loc[df.index[k], 'holdCost'] = holdCost_pre
        elif act == -1:
            df = buy_act(df, k, buyPrice, tradeVol, holdVol_pre, holdCost_pre)
        elif act == 1:
            df = sel_act(df, k, selPrice, tradeVol, holdVol_pre, holdCost_pre)

        # 持仓信息更新
        holdVol = df.loc[df.index[k], 'holdVol']
        Price = df.loc[df.index[k], col_price]
        if holdVol > 0:
            df.loc[df.index[k], 'holdVal'] = holdVol * Price * (1 - fee)
        elif holdVol < 0:
            df.loc[df.index[k], 'holdVal'] = holdVol * Price * (1 + fee)

        df.loc[df.index[k],
               'holdGainPct'] = cal_gain_pct(df.loc[df.index[k], 'holdCost'],
                                             df.loc[df.index[k], 'holdVal'], 0)

        last_act = act

    df['cashGet_cum'] = df['cashGet'].cumsum()  # 收入累计
    df['cashPut_cum'] = df['cashPut'].cumsum()  # 支出累计
    df['gain_cum'] = df['cashGet_cum'] + df['holdVal'] - df[
        'cashPut_cum']  # 累计盈利
    df['cashUsed'] = abs(df['cashPut_cum'] - df['cashGet_cum'])
    df['cashUsedMax'] = df['cashUsed'].cummax()  # 最大资金占用
    df['pctGain_maxUsed'] = df[['gain_cum', 'cashUsedMax']].apply(
        lambda x: x_div_y(x['gain_cum'], x['cashUsedMax'], v_xy0=0),
        axis=1)  # 收益/最大占用

    totalGet = df['cashGet_cum'].iloc[-1] + df['holdVal'].iloc[-1]  # 总收入
    totalPut = df['cashPut_cum'].iloc[-1]  # 总支出

    cashUsedMax = df['cashUsedMax'].iloc[-1]
    totalGain = df['gain_cum'].iloc[-1]  # 总收益额
    pctGain_maxUsed = df['pctGain_maxUsed'].iloc[-1]

    gain_stats = [pctGain_maxUsed, totalGain, totalGet, totalPut, cashUsedMax]
    gain_stats = pd.DataFrame(gain_stats).transpose()
    gain_stats.columns = ['收益/最大占用比', '总收益', '总回收', '总投入', '最大占用']

    return gain_stats, df
Beispiel #15
0
def CS(objf, func_opter_parms):
    '''
    todo: 目前仅考虑自变量连续实数情况,后面可增加自变量为离散的情况
    
    布谷鸟搜索算法(Cuckoo Search) CS algorithm
    
    Parameters
    ----------
    objf: 目标函数,须事先转化为求极小值问题
    func_opter_parms: FuncOpterInfo类,须设置parms_func、parms_opter、parms_log
    parms_func: 目标函数参数信息dict,key须包含
        x_lb: 自变量每个维度取值下界,list或数值,为list时长度应等于dim
        x_ub: 自变量每个维度取值上界,list或数值,为list时长度应等于dim
        dim: 自变量维度数
        
        kwargs: 目标函数接收的其它参数
    parms_opter: 优化函数参数信息dict,key须包含
        PopSize: 群体数量(每轮迭代的样本数量)
        Niter: 最大迭代寻优次数
        
        pa: 鸟巢被发现概率
        alpha, beta: Levy飞行参数
    parms_log: 日志参数信息dict,key须包含
        logger: 日志记录器
        nshow: 若为整数,则每隔nshow轮日志输出当前最优目标函数值
    
    Returns
    -------
    更新优化过程之后的func_opter_parms
    
    参考:
    https://blog.csdn.net/u013631121/article/details/76944879
    https://www.jianshu.com/p/4f6e02fc8396
    https://github.com/7ossam81/EvoloPy
    '''

    # 参数提取
    opter_name = func_opter_parms.parms_opter['opter_name']
    if opter_name == '' or isnull(opter_name):
        opter_name = 'CS'
    func_opter_parms.parms_opter['opter_name'] = opter_name
    # 目标函数参数
    x_lb = func_opter_parms.parms_func['x_lb']
    x_ub = func_opter_parms.parms_func['x_ub']
    dim = func_opter_parms.parms_func['dim']
    kwargs = func_opter_parms.parms_func['kwargs']
    # 优化器参数
    PopSize = func_opter_parms.parms_opter['PopSize']
    Niter = func_opter_parms.parms_opter['Niter']
    pa = func_opter_parms.parms_opter['pa']
    beta = func_opter_parms.parms_opter['beta']
    alpha = func_opter_parms.parms_opter['alpha']
    # 日志参数
    logger = func_opter_parms.parms_log['logger']
    nshow = func_opter_parms.parms_log['nshow']

    # 边界统一为列表
    if not isinstance(x_lb, list):
        x_lb = [x_lb] * dim
    if not isinstance(x_ub, list):
        x_ub = [x_ub] * dim

    # 初始化
    nests = rand_init(PopSize, dim, x_lb, x_ub)  # 鸟巢(个体or样本)随机初始化
    nests_new = nests.copy()

    gBest = np.zeros(dim)  # 全局最优解
    gBestVal = np.inf  # 全局最优值

    fvals = np.zeros(PopSize)  # 存放每个个体的目标函数值
    fvals.fill(float('inf'))  # 最小值问题初始化为正无穷大

    # 保存收敛过程
    convergence_curve = np.zeros(Niter)  # 全局最优值
    convergence_curve_mean = np.zeros(Niter)  # 平均值

    # 时间记录
    strt_tm = time.time()
    func_opter_parms.set_startTime(time.strftime('%Y-%m-%d %H:%M:%S'))

    # 初始最优解
    gBestVal, gBest, nests, fvals = update_best(nests, nests_new, fvals,
                                                PopSize, dim, objf, **kwargs)

    # 迭代寻优
    for l in range(0, Niter):
        # Levy flights
        nests_new = update_levy(nests,
                                gBest,
                                x_lb,
                                x_ub,
                                PopSize,
                                dim,
                                beta=beta,
                                alpha=alpha)

        # 个体|样本更新
        _, _, nests, fvals = update_best(nests, nests_new, fvals, PopSize, dim,
                                         objf, **kwargs)

        # 每个个体|样本以pa概率进行位置变化
        nests_new = replace_nests(nests_new, pa, PopSize, dim, x_lb, x_ub)

        # 个体|样本更新并获取最优个体|样本
        best_val, nest_best, nests, fvals = update_best(
            nests, nests_new, fvals, PopSize, dim, objf, **kwargs)

        if best_val < gBestVal:
            gBestVal = best_val
            gBest = nest_best

        # 每轮迭代都保存最优目标值
        convergence_curve[l] = gBestVal
        convergence_curve_mean[l] = np.mean(fvals)

        if nshow:
            if (l + 1) % nshow == 0:
                opter_name = func_opter_parms.parms_opter['opter_name']
                func_name = func_opter_parms.parms_func['func_name']
                logger.info(f'{opter_name} for {func_name}, iter: {l+1}, ' + \
                            f'best fval: {gBestVal}')

    # 更新func_opter_parms
    end_tm = time.time()
    func_opter_parms.set_endTime(time.strftime('%Y-%m-%d %H:%M:%S'))
    func_opter_parms.set_exeTime(end_tm - strt_tm)
    func_opter_parms.set_convergence_curve(convergence_curve)
    func_opter_parms.set_convergence_curve_mean(convergence_curve_mean)
    func_opter_parms.set_best_val(gBestVal)
    func_opter_parms.set_best_x(gBest)

    return func_opter_parms