☰
Python股票自动交易系统毕设实战:数据、回测与风险控制
2026/10/3 10:54:58 网站建设 项目流程

简介:基于Python的股票自动交易系统毕业设计源码包,源自个人毕设项目,答辩评审分高达95分。项目覆盖股票自动交易核心流程,面向计算机、通信、人工智能、自动化等相关专业学生及从业者,可作为期末课程设计、课程大作业或毕业设计参考,也适合小白从零学习项目架构与代码实现。压缩包共686个文件、14.77MB,其中包含131个Java源码、86个JS、67个HTML、48个CSS等前后端代码文件,以及大量JPG、PNG截图和数据库文件,便于查看界面效果、理解数据存储并撰写文档。目前已有336人学习下载。代码经过调试测试,确保可直接运行,整体结构完整、目录清晰,便于定位交易逻辑、数据存储与前端展示模块;基础扎实的读者可借此二次开发,扩展策略或优化交互,具备较高的学习与借鉴价值。

1. 毕设做股票自动交易系统,先想清楚这三件事

毕业设计选择了“基于Python的股票自动交易系统的设计与实现源码.zip”,很多同学的第一反应是:是不是要对接实盘、自动买卖、躺着赚钱?实际上,一个能顺利答辩的股票自动交易系统,重点不在“自动下单”本身,而在“把交易逻辑工程化”。你需要用 Python 完成行情获取、策略计算、回测评估、模拟交易和风险控制这一整条链路。这个题目非常适合已经有 Python 基础、但还没接触过量化交易和系统设计的同学,它能把股票数据分析、数据爬虫、文件持久化、面向对象设计、自动化脚本这些技能串成一个大而完整的项目。本文会按数据层、策略层、交易层、避坑点和你需要的落地路径,讲清楚从零搭完一套可演示的毕设系统。

2. 数据层与系统骨架:用 Python 把行情数据管起来

2.1 选型理由:为什么自动交易系统适合用 Python 来做

自动交易系统听起来高大上,但拆开以后就是四个环节:拿数据、算信号、做回测、发订单。这四个环节里,数据获取和策略验证占了 70% 的工作量,而这恰好是 Python 生态最舒服的地方。

用 Java 或 C++ 当然也能做,但你需要自己处理 HTTP 请求、CSV 解析、数据结构定义、图表可视化这些脏活。Python 的 pandas 可以直接做 Dataframe 运算,akshare、tushare 这类库把沪深行情接口封装成了几行代码,matplotlib 可以快速画出资金曲线和净值图。对毕设来说,你更需要的不是极致性能,而是“一天能改三版策略”的开发效率。

要说明的是,Python 并不适合高频交易场景,它的解释器开销和 GIL 锁在毫秒级竞争中很吃亏。但毕设命题通常针对日线或分钟线级别的自动交易,策略计算周期按小时甚至按天来算,Python 完全没有性能压力。如果你准备用 A 股日线数据、模拟盘交易来交差,选 Python 是性价比最高的决定。

2.2 拉取沪深日线行情:akshare 和 tushare 的最小用法

数据层是整个系统最底层的地基。我一般建议用 akshare 起步,因为不需要注册 token,直接 pip 安装就能跑;tushare 需要注册获取 token,但数据稳定性更好。下面的代码用 akshare 拉取平安银行最近一年的日线行情。

# -*- coding: utf-8 -*- # 获取沪深A股日线行情的示例脚本 import akshare as ak import pandas as pd from datetime import datetime, timedelta # 以平安银行(000001)为例,拉取最近一年的日K线 end_date = datetime.now().strftime("%Y%m%d") start_date = (datetime.now() - timedelta(days=365)).strftime("%Y%m%d") df = ak.stock_zh_a_hist( symbol="000001", # 股票代码,注意不带交易所后缀 period="daily", # 周期:daily / weekly / monthly start_date=start_date, # 开始日期,格式YYYYMMDD end_date=end_date, # 结束日期 adjust="qfq", # qfq前复权,hfq后复权,""不复权 ) # akshare返回的是中文列名,改成后续方便处理的英文名 df.rename( columns={"日期": "date", "开盘": "open", "收盘": "close", "最高": "high", "最低": "low", "成交量": "volume"}, inplace=True, ) # 只保留回测需要的字段,顺便把日期转成时间类型 df = df[["date", "open", "high", "low", "close", "volume"]] df["date"] = pd.to_datetime(df["date"]) print(df.tail())

这段代码的逻辑是:先通过 akshare 拿到原始行情,再做列名清洗和字段筛选。period="daily"的意思是拉日线,如果你后面要扩展分钟级别,可以改成1、5、15、30这种分钟周期值。adjust="qfq"非常关键,它拉回来的是前复权数据,除权除息日前后价格是连续的,否则你会在分红日看到一个莫名其妙的向下跳空缺口,直接影响均线计算和回测盈亏。

初期踩坑点在于:akshare 的列名是中文,而且版本更新偶尔会改列名。建议你把数据清洗单独封装成一个函数,后面换 tushare 时只需要改这一个函数,不用在策略代码里到处改。

2.3 数据存储与复权字段设计:少走弯路的本地库

毕设项目不需要上数据库,用 CSV 或者 SQLite 就够。但存储结构要提前想清楚,否则策略每次运行都要重新拉数据。

# 保存为CSV,同时写一个meta文件记录数据范围 import os os.makedirs("data/daily", exist_ok=True) df.to_csv("data/daily/000001_daily_qfq.csv", index=False) with open("data/daily/000001_daily_qfq_meta.txt", "w", encoding="utf-8") as f: f.write(f"symbol=000001\n") f.write(f"start={df['date'].min().date()}\n") f.write(f"end={df['date'].max().date()}\n") f.write(f"adjust=qfq\n")

这里用文件名把股票代码、周期、复权方式都记录下来,meta 文件记录数据范围。这样做的好处是,当你同时测试多只股票时,文件不会互相覆盖。

字段设计上,date、open、high、low、close、volume 是底线。但你要特别注意复权方式的一致性:同一个数据目录下不要一部分是前复权、一部分是不复权。前复权数据受最新除权影响,每次拉取都可能改变历史价格,如果策略代码里混合使用,回测结果会变得不可复现。你可以把复权方式写死在文件名和 meta 文件里,甚至可以在 README 里说明“当前系统统一使用前复权日线数据”,这样答辩时老师问起来也能说得清楚。

3. 策略编写与回测:把交易想法变成可验证的代码

3.1 策略信号生成:从指标到买卖点的抽象过程

数据到位后,接下来就是把交易思想变成代码。这里以最常见、最容易讲的“双均线策略”为例,短周期均线上穿长周期均线时买入,下穿时卖出。它虽然简单,但足够展示完整的信号生成和回测逻辑。

# strategy/double_ma.py def generate_signal(df, short=5, long=20): """ 输入含有 date 和 close 列的数据,输出带 ma_short / ma_long / target_position 的副本。 target_position: 1 表示目标持仓,0 表示目标空仓。 """ df = df.sort_values("date").reset_index(drop=True) df["ma_short"] = df["close"].rolling(short).mean() df["ma_long"] = df["close"].rolling(long).mean() # 短均线大于长均线时持有,否则空仓 df["target_position"] = (df["ma_short"] > df["ma_long"]).astype(int) return df

这里我把信号表达成“target_position”,而不是直接写买入卖出的动作。这个抽象很重要:回测引擎只需要关注“当前应该持有还是空仓”,不需要在每个 bar 上判断是否发生了金叉死叉。这样做能避免重复信号,比如已经持有时再出现金叉,不会被重复买入。

参数 short 和 long 是策略最敏感的部分,它们的值直接影响持仓周期和交易频率。在代码里用参数传入方式,而不是写死rolling(5)和rolling(20),后面才能做参数寻优。

3.2 最小回测引擎:逐根K线模拟交易和资金曲线

信号生成以后,就要写回测引擎。回测引擎的本质是模拟交易规则:按收盘价买入、卖出,记录每天的现金和持仓市值。下面这段代码是逐行遍历 DataFrame,逻辑直观,适合毕设第一版。

# engine/backtest_engine.py def backtest(df, init_cash=100000, fee_rate=0.0003): """ 简化版回测:按收盘价成交,买入按整手。 返回包含日期、总资产、现金、持仓股数的DataFrame。 """ df = df.reset_index(drop=True) cash = init_cash position = 0 equity_list = [] for i, row in df.iterrows(): price = row["close"] target = row["target_position"] # 目标持仓为1且当前空仓时买入 if target == 1 and position == 0: position = int(cash // (price * 100)) * 100 # 按整手买入 cash -= position * price * (1 + fee_rate) # 扣除手续费 # 目标持仓为0且当前有持仓时卖出 elif target == 0 and position > 0: cash += position * price * (1 - fee_rate) # 卖出扣手续费 position = 0 total_assets = cash + position * price equity_list.append({ "date": row["date"], "total_assets": total_assets, "cash": cash, "position": position, }) return pd.DataFrame(equity_list)

代码里的核心逻辑是:每当 target_position 从 0 变成 1 时,就用剩余现金尽量买入 100 的整数倍股票;从 1 变成 0 时,就把持仓全部卖出。为什么用整手?因为 A 股买入数量必须是 100 股或其整数倍。这里没有处理涨跌停,真实回测中涨停时你可能买不进,跌停时卖不出,这个后面在避坑章节再展开。

手续费 scale 费率是双边收取,也就是买入卖出各扣一次。实际 A 股还有最低 5 元佣金、印花税和过户费,但对毕设来说,按照 0.0003 的单边费率先行实现即可,如果答辩需要进一步细化,再去补最低佣金逻辑。

3.3 评估指标怎么算:年化收益率、最大回撤、夏普比例

回测跑完以后,不能只看最后的总收益率。很多新手第一次跑出几倍收益,结果发现最大回撤超过一半,这种策略根本没法用。你需要至少计算年化收益率、最大回撤、夏普比率三个指标。

# engine/evaluate.py def evaluate(equity_df): """根据回测结果计算评估指标""" equity_df["prev_high"] = equity_df["total_assets"].cummax() equity_df["drawdown"] = equity_df["total_assets"] / equity_df["prev_high"] - 1 max_drawdown = equity_df["drawdown"].min() equity_df["daily_ret"] = equity_df["total_assets"].pct_change().fillna(0) total_ret = equity_df["total_assets"].iloc[-1] / equity_df["total_assets"].iloc[0] - 1 years = len(equity_df) / 250 # 一年约250个交易日 annual_ret = (1 + total_ret) ** (1 / years) - 1 daily_std = equity_df["daily_ret"].std() sharpe = 0 if daily_std > 0: sharpe = equity_df["daily_ret"].mean() / daily_std * (250 ** 0.5) return { "total_ret": total_ret, "annual_ret": annual_ret, "max_drawdown": max_drawdown, "sharpe": sharpe, "trade_days": len(equity_df), }

最大回撤用cummax()算出历史最高净值,再用当前净值除以最高净值减 1,得到的就是从最高点往下的回撤幅度。夏普比率做了一个年化处理,乘以250 ** 0.5是因为我们用的是日收益率。这里没有使用无风险利率,对毕设来说已经够用。

你要记住一个黄金认知:回测指标只能在“样本内”给出参考,不能证明策略未来会赚钱。所以后面必须做样本外验证。

4. 从回测到模拟交易:订单、持仓与风控落地

4.1 交易通道选择:模拟盘接口与前后端设计

回测通过以后,要让系统真正跑起来,需要接入交易通道。毕设阶段不建议直接对接真实账户。更推荐的做法是接券商的模拟盘环境,或者完全用内存模拟一个交易账户。写一个交易接口抽象类,把“虚拟账户”和“真实接入”统一成相同的接口,这样后续替换很方便。

# trade/trade_api.py class TradeAPI: """交易接口抽象类,定义买卖和查询持仓的统一方法""" def buy(self, symbol, price, quantity): raise NotImplementedError def sell(self, symbol, price, quantity): raise NotImplementedError def query_position(self): raise NotImplementedError class VirtualTradeAPI(TradeAPI): """虚拟账户:只在内存中模拟交易,避免真实资金风险""" def __init__(self, init_cash=100000): self.cash = init_cash self.position = {} self.order_id = 0 def buy(self, symbol, price, quantity): # 先校验资金是否充足,这里不做任何风控,后面接RiskManager cost = price * quantity if cost > self.cash: raise ValueError("资金不足") self.cash -= cost self.position[symbol] = self.position.get(symbol, 0) + quantity self.order_id += 1 return { "order_id": self.order_id, "symbol": symbol, "side": "buy", "quantity": quantity, "price": price, } def sell(self, symbol, price, quantity): if self.position.get(symbol, 0) < quantity: raise ValueError("持仓不足") self.cash += price * quantity self.position[symbol] -= quantity self.order_id += 1 return { "order_id": self.order_id, "symbol": symbol, "side": "sell", "quantity": quantity, "price": price, }

这段代码把“下单”抽象成了 buy 和 sell 两个方法。为什么值得这么做?因为策略层不需要关心底层是模拟还是真实接入,它只需要调用buy("000001", 10.5, 100)。后面如果你想从虚拟账户切换到某券商提供的开放接口,只需要新写一个RealTradeAPI类,把买和卖换成调用对方 SDK,策略代码完全不用改。

4.2 订单状态管理与持仓更新

真实交易系统里,订单从提交到成交有多个状态:已提交、已成交、已撤销、被拒绝。模拟盘里你也可以设计这个状态机,方便演示“下单以后发生了什么”。

# trade/order_status.py ORDER_PENDING = "PENDING" # 订单已提交,等待成交 ORDER_FILLED = "FILLED" # 订单已成交,持仓已更新 ORDER_CANCELLED = "CANCELLED" # 订单已撤销 ORDER_REJECTED = "REJECTED" # 订单被拒绝,例如资金不足

订单管理的核心不是把状态记下来,而是在每个状态变化时同步更新现金和持仓。我之前见过不少同学把订单状态和持仓分开维护,结果跑到一半现金和持仓对不上账。建议以订单为唯一事实来源:只有当订单状态变为 FILLED 时,才去修改 cash 和 position,其他状态一律不动。这样即使订单被拒绝,账本也不会乱。

另一个容易忽略的点是所有下单操作都要做幂等处理。比如程序定时器触发了两遍买入信号,不能对同一个信号下两张单。常见做法是给信号生成一个唯一标识,比如按日期加股票代码做 key,订单表里检查这个 key 是否已经存在,存在就直接跳过。

4.3 风控模块:仓位控制、止损与防止情绪化交易

风控是整个自动交易系统的安全气囊。没有风控的自动交易,本质是给亏钱装上了自动扣扳机。毕设风控不需要做得很复杂,但至少要有三个规则:单笔止损、总仓位限制、最大回撤预警。

# trade/risk_manager.py class RiskManager: """下单前的风控检查,所有检查通过才能执行交易""" def __init__(self, max_position_ratio=0.7, stop_loss_threshold=0.05): self.max_position_ratio = max_position_ratio # 总仓位不能超过70% self.stop_loss_threshold = stop_loss_threshold # 单只股票亏损超过5%则触发止损 def check_before_buy(self, total_assets, current_position_value, order_value): # 买入后总市值不能超过总资产的70% if current_position_value + order_value > total_assets * self.max_position_ratio: return False, "总仓位超过上限" return True, "ok" def check_stop_loss(self, cost_price, current_price): # 如果当前价格已经跌到成本价以下5%,不开新仓或直接执行止损 loss_ratio = (current_price - cost_price) / cost_price if loss_ratio < -self.stop_loss_threshold: return False, "触发止损" return True, "ok"

max_position_ratio=0.7是总仓位上限,防止策略在极端行情下满仓梭哈。stop_loss_threshold=0.05是单笔止损阈值,亏损超过 5% 就停止加仓或强制离场。这些参数都是经验值,答辩时可以摆出你的调整过程。

这里要提醒一句:风控代码必须放在订单发送之前执行,并且要写在策略主循环里,不能只挂在回测里。回测中的风控和模拟交易中的风控要保持一致,否则回测和实盘的表现会完全不同。

5. 股票自动交易系统常见问题与避坑

5.1 回测很美、实盘翻车:未来函数和成交价格假设

现象:回测年化收益 30%,最大回撤只有 8%,一上模拟盘连续亏损,资金曲线明显分叉。

原因:最常见的是未来函数,也就是策略用了当天收盘后才能知道的信号,却在同一根 K 线的收盘价成交。比如你在df["close"].rolling(5).mean()的同一个 bar 里比较大小生成信号,又在同一行代码里用 close 成交,这就等于你提前知道今天会涨,然后用今天的收盘价买入,现实中根本不可能。

解决:把信号生成和成交价做一个时间错位。信号当天收盘后计算,按下一个交易日开盘价成交。最简单的改法是在回测循环里,price用下一行的open,或者把target_position用shift(1)平移。这里推荐平移方式,它同时适用于回测和模拟盘。

# 避免未来函数:信号向后平移一天,用次日价格 df["target_position"] = df["target_position"].shift(1) df.iloc[0, df.columns.get_loc("target_position")] = 0

这个细节是答辩时的高频提问点,提前处理好能让你的系统显得专业。

5.2 数据缺口和复权错误导致信号错乱

现象:策略对某只股票回测时,资金曲线突然出现一根巨大跳线,有时候一天之内收益率从 5% 变成 20%。

原因:股票停牌导致数据缺行,或者除权除息后没有使用复权数据。停牌时当天根本没有交易,akshare 不会产生那根 K 线,你的 DataFrame 中间就会空一行。均线计算是用 rolling 窗口,它不会因为你缺行就跳过,而是直接把前一行和后一行拉在一起,算出一个假交叉。

解决:下载数据后做日期连续性校验。拿交易日历和生产数据做对比,发现缺失就直接放弃这段数据或者用最近交易日填充。另一个办法是统一字段标记,从文件名里区分前复权和不复权,不要混用。

# 校验数据日期连续性:打印缺失日期 import pandas as pd df["date"] = pd.to_datetime(df["date"]) date_set = set(df["date"].dt.date) missing = [] for d in pd.date_range(df["date"].min(), df["date"].max(), freq="D"): if d.date() not in date_set: missing.append(d.date()) # 输出后要人工判断:周末和节假日是正常缺失,工作日缺失就需要处理 print("疑似缺失日期:", missing)

注意,A 股节假日和周末本来就缺数据,你跟日历对不上不代表出错,要过滤掉非交易日再做判断。

5.3 程序挂起或阻塞,日志看不出原因

现象:定时任务今天没跑,打开日志发现昨天下午 3 点之后没有任何输出,进程也没有退出。

原因:外部接口超时卡死、akshare 请求被限频、网络断开后程序没有重试。有些命令直接阻塞在requests.get上,超时时间没设置,卡住几小时都不奇怪。

解决:所有网络请求都设置超时和重试。另外,在关键步骤打点日志,比如“开始拉取数据 / 数据拉取完成 / 开始计算信号 / 计算完成”。

# 给akshare请求加一个超时兜底 import akshare as ak from tenacity import retry, stop_after_attempt, wait_exponential @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10)) def fetch_daily(symbol): print(f"拉取 {symbol} 行情") return ak.stock_zh_a_hist(symbol=symbol, period="daily", adjust="qfq")

即使你不引入 tenacity,手工写 try-except 也需要把异常和重试次数记录下来。有一个教训:日志不能只打印“开始某步”,还要打印“这一步耗时多少”,否则你不知道是卡在数据源还是卡在本地计算上。

5.4 策略过拟合:历史数据上完美,参数一改就崩

现象:一个策略设了 8 个参数,通过反复调参得到一条几乎 45 度上扬的资金曲线,但对 2022 年到 2023 年的分段回测表现很差,参数稍微改一点就变成亏损。

原因:用全部历史数据反复调参,策略已经把噪声“背”下来了。参数越多,过拟合越容易发生,这在机器学习里是常识,在股票量化里同样成立。

解决:把数据集切成样本内和样本外,样本内调参、样本外验证。同时限制参数数量,一个策略有 3 到 4 个可调参数已经不少了。如果最优参数旁边稍微一调就大幅变差,说明这个策略不稳定,不要选它。

# 参数敏感性检查:在最优参数附近做小范围扰动 test_params = [ {"short": 4, "long": 19}, {"short": 5, "long": 20}, {"short": 6, "long": 21}, ] for params in test_params: result = backtest(generate_signal(df, **params)) print(params, "总收益率:", result["total_assets"].iloc[-1])

如果相邻参数结果差异巨大,说明策略不稳定。这一条被答辩老师问到概率很高,提前做一组敏感性分析放在论文里,能挽回不少印象分。

5.5 密钥、权限和账户安全边界

现象:同学把交易接口的密钥硬编码在源码里,然后整个项目打包发到群里,结果密钥被他人拿走使用,账户资金出了风险。

原因:只追求“能跑”,没有考虑代码会被复制、提交到代码仓库,或者分享给别人。

解决:密钥统一从环境变量或者.env文件读取,真实配置文件要加入.gitignore。同时毕设项目里尽量只使用模拟账号,不要放真实资金。自动交易涉及合规问题,不同地区监管要求不同,答辩时也建议明确写“系统面向模拟交易与策略研究”,不要承诺实盘自动交易功能。以下是.env.example的写法,只给格式,不给真实值:

# .env.example 提交到仓库时只保留这个示例文件,不提交真实文件 TRADE_API_BASE_URL=https://your-broker-api.example.com TRADE_API_KEY=your_key_here TRADE_API_SECRET=your_secret_here

风险控制永远是第一位,别有“真实账户跑一下就删掉”的想法,自动交易出 Bug 时几秒钟就能把资金亏掉不少。

6. 把毕设做到能答辩:样本外验证与代码组织

6.1 一份能自证的最小闭环项目

答辩时老师最怕看到一堆文件但不知道从哪里开始运行。建议你把项目整理成下面这种结构,保证任何一个人按 README 步骤能跑出回测结果:

stock_trading_system/ ├── data/ │ ├── daily/ # 本地行情CSV,带复权标记 │ └── backtest_result/ # 回测输出结果 ├── strategy/ │ └── double_ma.py # 策略信号生成 ├── engine/ │ ├── backtest_engine.py # 回测引擎 │ └── evaluate.py # 评估指标计算 ├── trade/ │ ├── trade_api.py # 交易接口抽象与虚拟账户 │ ├── order_status.py # 订单状态常量 │ └── risk_manager.py # 风控管理器 ├── config.yaml # 策略参数与账户配置 ├── requirements.txt ├── run_backtest.py # 主入口:拉数据、算策略、跑回测、输出指标 └── README.md

这里的run_backtest.py是唯一入口,负责把数据获取、策略信号、回测、评估串起来。config.yaml负责装载配置,这样做的好处是老师改参数不需要去翻代码,打开配置文件就能做实验。

6.2 样本外验证:用 80/20 的时间切分来评估

设计一套自动交易系统,最容易被追问的问题是:“你如何证明策略在未来也能工作?”最佳回答就是:我做了样本外验证。把时间序列的前 80% 作为训练段,后 20% 作为测试段,在训练段选参数,在测试段验证参数,全程禁止用测试段调参。

# run_backtest.py import yaml import pandas as pd from strategy.double_ma import generate_signal from engine.backtest_engine import backtest from engine.evaluate import evaluate # 读取配置文件里的参数 config = yaml.safe_load(open("config.yaml", encoding="utf-8")) df = pd.read_csv("data/daily/000001_daily_qfq.csv", parse_dates=["date"]) # 按时间顺序切分 split_idx = int(len(df) * 0.8) train_df = df.iloc[:split_idx].copy() test_df = df.iloc[split_idx:].copy() params = { "short": config["strategy"]["short"], "long": config["strategy"]["long"], } # 样本内回测 train_result = backtest(generate_signal(train_df, **params)) print("样本内指标:", evaluate(train_result)) # 样本外回测,使用同样的参数 test_result = backtest(generate_signal(test_df, **params)) print("样本外指标:", evaluate(test_result))

这段代码同时展示了配置加载和时间序列切分。要注意切分前必须先按照 date 排序,否则随机顺序会让样本外失去意义。这里split_idx只做一条分割线,完全避免未来数据泄漏。

对于毕设,你还可以再往前一步:做多组样本外滚动测试。比如每 6 个月作为一个区块,用前 18 个月训练、后 6 个月测试,滚动三轮。这样能证明系统不是只撞上一次好行情。

6.3 代码组织的常用习惯与答辩自检清单

最后分享一个让我自己受益比较多的习惯:把“可以复现”作为写代码的底线。每次回测跑完,自动把策略参数、交易区间、数据文件、评估指标同步写到当天日期的结果文件里。这样你拿着结果去对论文,每一张图都能追溯。

你还可以把config.yaml写得更细一些,让老师看一眼就明白系统设计思路:

# config.yaml:系统配置示例 data: symbol: "000001" start_date: "2018-01-01" end_date: "2023-12-31" adjust: "qfq" strategy: name: "double_ma" short: 5 long: 20 backtest: init_cash: 100000 fee_rate: 0.0003 min_lot: 100 trade: mode: "virtual" # virtual 表示虚拟账户,不接真实盘

答辩前你至少要点检三件事:第一,回测结果是否能在另一台机器上重新跑出来,如果可以就说“纯 Python + 配置文件”,不能的话赶紧补 README;第二,策略代码是否清晰展示了信号的产生、回测、风控三个层次,别把逻辑搅在一个文件里;第三,论文里的每一条资金曲线和指标都要有对应的本地代码文件和参数记录。

以前我有一个项目把所有数据都用来调参,答辩时被问“你对 2022 年下半年的样本外表现怎么看”,当场拿不出结果。后来我养成了固定做 80/20 切分的习惯,把样本外测试作为流程的一部分写进项目里。这样导师看到的不是一个堆满代码的 zip,而是一套能自证、可验证的系统。希望这些思路能帮你把这个毕设题目做成真正拿得出手的作品,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询