原创内容第1003篇,专注AGI+,AI量化投资、个人成长与财富自由。今天发布backtrader引擎的代码,带三个策略:新的backtrader引擎,支持按第二天开盘价交易,支持止盈止损,支持多策略组合,支持多参数优化。
import pandas as pd
class SelectWhere: def __init__(self, signal): self.signal = signal
def __call__(self, target): signal = self.signal current_date = target.datetime.date(0)
current_date_pd = pd.Timestamp(current_date)
if current_date_pd in signal.index: selected_columns = signal.loc[current_date_pd][signal.loc[current_date_pd]==1].index.to_list() target.temp["selected"] = selected_columns
return True else: target.temp["selected"] = [] return True
class SelectAll: def __call__(self, target):
symbols = [] for data in target.datas: if len(data) > 0: symbols.append(data._name) target.temp["selected"] = symbols return True
class SelectTopK: def __init__(self, signal, K=1, drop_top_n=0, b_ascending=False): self.K = K self.drop_top_n = drop_top_n self.b_ascending = b_ascending self.signal = signal
def __call__(self, target): """ 根据当天信号值排序,丢弃N个信号后选取前K个信号
参数: signal: pd.DataFrame - 信号数据框,索引为日期 N: int - 要丢弃的信号数量 K: int - 要选取的信号数量 """ current_date = target.datetime.date() current_date_pd = pd.Timestamp(current_date) signal = self.signal
if current_date_pd not in signal.index: target.temp["selected"] = [] return True
daily_signals = signal.loc[current_date_pd]
valid_signals = daily_signals.dropna() if 'selected' in target.temp.keys():
selected = target.temp['selected'] if selected: valid_signals = valid_signals[selected] else: return True else: return False
sorted_signals = valid_signals.sort_values(ascending=self.b_ascending)
N = self.drop_top_n if N > 0: N = min(N, len(sorted_signals)) sorted_signals = sorted_signals.iloc[N:]
K = self.K if len(sorted_signals) > 0: K = min(K, len(sorted_signals)) topK_signals = sorted_signals.head(K) target.temp["selected"] = topK_signals.index.tolist()
return True else: target.temp["selected"] = [] return True
class WeightEqually: def __init__(self): pass
def __call__(self, target): selected = target.temp["selected"] n = len(selected)
if n == 0: target.temp["weights"] = {} else: w = 1.0 / n target.temp["weights"] = {x: w for x in selected} return True
class ReBalance: def __init__(self): self.pre_symbols = None
def __call__(self, target):
if "weights" not in target.temp: return True
target_weights = target.temp["weights"] if type(target_weights) is pd.Series: target_weights = target_weights.to_dict()
if self.pre_symbols == set(target_weights.keys()): return
datas = target.get_current_holding_datas() for data in datas: if data._name not in target_weights.keys(): target.close(data)
total_value = target.broker.getvalue()
to_buy = [] for symbol, w in target_weights.items(): pos = target.getposition(target.getdatabyname(symbol)) close = target.getdatabyname(symbol).close[0] data_value = pos.size * close percent = data_value / total_value if percent > w: target.order_target_percent(symbol, w) else: to_buy.append(symbol)
for s in to_buy: target.order_target_percent(s, w * 0.99) self.pre_symbols = set(target_weights.keys()) target.temp = {} return True
对于做量化的思路,随着自己的成长,也在一步步清晰。之前花过不少时间写回测引擎,对于回测引擎的工作原理有了比较深入的了解。不过,一个成熟尤其是实盘导向的框架,还是有很多细节要考虑。在熟悉一个引擎之后,使用成熟的框架是有好处的,比如backtrader。后来花了不少时间搞低代码和gui,在进展,有沉淀。把重要的事情,做精,做扎实,自然往外延伸,而不是求多,求快。写到3000篇看看什么效果?还有2000篇,6年多的样子,就算七年吧。如今,随着健康水平和生活质量的提高,50岁早已不再是“老人”的代名词,而被赋予了新的意义:
人生的新起点:很多人在这个年龄,孩子已经长大成人(生娃晚的话,可能孩子还在长大中),事业趋于稳定,反而有了更多的时间和精力去追求自己年轻时未完成的梦想,发展新的爱好,开启人生的“第二春”。
智慧与成熟的巅峰:积累了丰富的人生阅历、工作经验和处世智慧,看问题更加通透,决策更加沉稳。
承上启下的阶段:通常是家庭中的支柱,上有年迈的父母需要赡养,下有可能刚刚步入社会的子女需要指导,是家庭的核心力量。
代码和数据下载:AI量化实验室——2025量化投资的星辰大海AI量化实验室 星球,已经运行三年多,1800+会员。
aitrader代码,因子表达式引擎、遗传算法(Deap)因子挖掘引擎等,支持vnpy,qlib,backtrader和bt引擎,内置多个年化30%+的策略,每周五迭代一次,代码和数据在星球全部开源。
点击 “查看原文”,直接访问策略集合。