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
def get_baseVol(Price): '''计算底仓交易量''' if not isnull(baseMny): return 100 * (baseMny // (100 * Price)) elif isnull(baseVol): raise ValueError('baseMny和baseVol必须设置一个!') else: return baseVol
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
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']
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_
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 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]
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
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
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
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
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
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
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
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