OptiNod 学院

TradingView 回测方法 — 从初始设置到 CSV 分析

从应用策略开始,设置资金、手续费、滑点和日期,排查零交易,解读结果并分析交易 CSV。记录相同条件,让下一次验证可以比较。

第一次回测是同时保存设置和交易记录的一次运行。保留这些条件,才能与下一次结果比较。


把策略添加到图表后,可能没有交易,也可能一加入手续费,利润就消失了。这时先查看:哪条规则生成了订单,订单使用了多大的数量。


TradingView 回测把交易规则应用于历史数据,生成模拟交易结果。图表上的买卖标记、真实订单的成交,以及策略报告中的模拟交易,是不同的记录。


本文按以下顺序操作:应用策略 → 设置成本和日期 → 检查第一笔交易 → 解读结果 → 保存交易列表。最后把 CSV 放入 OptiNod 分析,找到造成损失的交易,并据此安排下一次验证。


应用策略后,要同时查看订单和结果


先使用标准蜡烛图,选择带交易所名称的交易品种和 K 线周期。添加你有权使用的策略,并记录策略名称、源代码版本和输入值。仅添加均线等指标不会生成回测交易。策略需要 strategy() 声明,以及生成模拟订单的指令。


当前官方文档把图表下方的界面称为策略报告(Strategy report),结果标签为 Metrics 和 Trades。根据账户语言和界面版本,你也可能看到策略测试器(Strategy Tester)、概览(Overview)、交易列表(List of Trades)等旧名称。在界面中分别找到交易列表和绩效指标。策略官方文档


从标准蜡烛图开始,可以减少使用合成价格的图表所带来的成交假设。添加策略后,先确认确实生成了入场和退出记录。


本例为 OptiNod Learn - SMA 10/30 Backtest Guide v1.0.0。验证时选择 NASDAQ:AAPL,使用标准蜡烛图和 1D 周期,界面中的数据源显示为 NASDAQ by Cboe One,检查日期为 2026-10-01。这是自行编写的教学示例:快速 SMA 10 向上穿过慢速 SMA 30 时做多,向下穿过时退出。示例没有单独的止损、止盈或实盘交易提醒,也不是基于绩效提出的策略推荐。


  1. 在 TradingView 的 Pine Editor 中打开新脚本,粘贴以下代码。
  2. 将代码应用到图表,确认品种为 NASDAQ:AAPL、周期为 1D,并使用标准蜡烛图。
  3. 在策略设置的输入(Inputs)中核对日期和基础入场金额,在属性(Properties)中核对资金、成本和成交设置。
  4. 打开报告中的交易列表和指标,在相同条件下与下文的实测结果比较。

//@version=6
// OptiNod Learn 教学示例 v1.0.0。AAPL 标准蜡烛图,1D。
// 仅生成模拟订单。没有定义提醒或 webhook 消息。
strategy("OptiNod Learn - SMA 10/30 回测指南", overlay=true, pyramiding=0, initial_capital=10000, currency=currency.USD, default_qty_type=strategy.fixed, default_qty_value=1, commission_type=strategy.commission.percent, commission_value=0.05, slippage=1, margin_long=100, margin_short=100, process_orders_on_close=false, calc_on_every_tick=false, calc_on_order_fills=false, use_bar_magnifier=false)

// 0 - 日期 / 资金:第一个输入分组,位于信号和显示设置之前。
string G_CAP = "0 · 日期 · 资金"
int startTime = input.time(1704067200000, "开始时间", group=G_CAP, inline="win") // 2024-01-01 00:00 UTC
int endTime = input.time(1767225600000, "结束时间", group=G_CAP, inline="win", tooltip="入场使用 [开始, 结束) 区间内的 K 线开盘时间。未平仓头寸在结束时间及之后的第一根计算 K 线上生成平仓订单;市价订单通常在下一个可用价格更新时成交。") // 2026-01-01 00:00 UTC
float leverage = input.float(1.0, "杠杆", minval=1.0, maxval=1.0, step=1.0, group=G_CAP, tooltip="这个股票教学示例不使用杠杆:固定为 1 倍,保证金要求为 100%。")
float baseAmount = input.float(1000.0, "基础入场金额", minval=0.0, group=G_CAP, inline="amt")
string amountUnit = input.string("$", "", options=["%", "$"], group=G_CAP, inline="amt", tooltip="每次入场的美元保证金预算。% 使用当前策略权益;$ 使用固定金额。按整股向下取整,使按信号收盘价计算的实际敞口不超过预算。")
bool useVarSizing = input.bool(true, "可变仓位规模", group=G_CAP, tooltip="标准设置区保留此选项。本例始终使用乘数 1,因此切换此选项不会改变订单数量。")

string G_SIGNAL = "1 · 移动平均线"
int fastLength = input.int(10, "快速 SMA", minval=1, group=G_SIGNAL)
int slowLength = input.int(30, "慢速 SMA", minval=1, group=G_SIGNAL)

string G_VIEW = "2 · 显示"
bool showAverages = input.bool(true, "显示均线", group=G_VIEW)
color fastColor = input.color(#10b981, "快速", group=G_VIEW, inline="palette")
color slowColor = input.color(#9aa0b5, "慢速", group=G_VIEW, inline="palette")

// AAPL 按整股交易。数量使用信号收盘价计算,而非无法预知的未来成交价。
qtyFor(float stateMult) =>
    float margin = (amountUnit == "%" ? strategy.equity * baseAmount / 100.0 : baseAmount) * (useVarSizing ? stateMult : 1.0)
    math.floor(math.max(margin, 0.0) * leverage / (close * syminfo.pointvalue))

bool inWindow = time >= startTime and time < endTime
float fastSma = ta.sma(close, fastLength)
float slowSma = ta.sma(close, slowLength)
bool longSignal = ta.crossover(fastSma, slowSma)
bool exitSignal = ta.crossunder(fastSma, slowSma)
float entryQty = qtyFor(1.0)

if inWindow and longSignal and strategy.position_size == 0 and entryQty > 0
    strategy.entry("Long", strategy.long, qty=entryQty, comment="做多")

if strategy.position_size > 0 and time >= endTime
    strategy.close("Long", comment="到期退出")
else if strategy.position_size > 0 and exitSignal
    strategy.close("Long", comment="退出")

// 布局:最简叠加。两条均线用于说明教学示例中的交叉。
plot(showAverages ? fastSma : na, "快速 SMA", color=fastColor, linewidth=2)
plot(showAverages ? slowSma : na, "慢速 SMA", color=slowColor, linewidth=1)

数量以信号收盘价为基础,把 1,000 USD 的预算换算成股数并向下取整。这不是直接以 1,000 USD 作为交易金额下单。下一根 K 线的跳空和滑点,可能使实际成交金额与预算不同。杠杆固定为 1 倍;虽然可变仓位规模已开启,但乘数始终为 1,所以开关这个选项不会改变数量。


实际使用的日期与资金输入
实际使用的日期与资金输入UTC 00:00 在韩国时间的界面中显示为 09:00。(2026-10-01)

先设定成本和订单规模,才能保留可比较的条件


在策略设置的属性(Properties)中设定资金、订单规模、手续费和滑点。下表为实际运行使用的设置和单位。


项目实际使用值单位影响结果的原因
初始资金与币种10,000 USDUSD起始资产和收益率的计算基准
基础入场金额1,000,单位 $USD / 每次入场预算代码按信号收盘价计算整股数量
杠杆与保证金1 倍,多空保证金均为 100%倍,%不使用杠杆,在资金范围内生成模拟订单
手续费0.05% / 每笔订单入场和退出各收取交易金额的 0.05%
滑点1tick应用于市价和止损订单的成交价格
K 线细节精度默认(Default,4 ticks per bar)每根 K 线 4 个价格点历史 K 线成交使用默认的 OHLC 假设
脚本执行K 线收盘时(On bar close)K 线收盘K 线收盘时计算交叉
订单执行延迟一个价格更新(One tick)1 tick已生成的市价订单在下一个可用价格更新时成交

滑点的价格差为 tick 数 × 品种的最小 tick 大小。如果订单规模按权益百分比设置,金额会随入场时的权益变化。如果代码直接指定每笔订单的数量,改变默认订单规模可能不会改变这些订单。属性的官方定义


第一次比较时,把保证金、重新计算和成交选项也一并记录。不要把成本或订单规模变化的效果,与策略规则改善的效果混在一起。


Properties 中的默认订单规模显示为 1,但本代码直接向 strategy.entry() 传入 qty,所以实际数量由 Inputs 中的基础入场金额计算。把报告中的 Default detalization、Script execution 与策略设置的 Properties 一起核对。


实际使用的资金、成本和成交设置
实际使用的资金、成本和成交设置核对初始资金 10,000 USD、手续费 0.05%、On bar close 和默认 K 线细节精度。(2026-10-01)

日期范围要同时核对图表数据和策略的日期条件


普通回测运行于图表已加载的数据。策略中的日期输入是在这些数据内限制订单的条件,不会额外加载更早的数据。如果策略提供日期输入,设定开始和结束日期后,检查实际交易时间是否符合预期。


Testing period 等日期选择和 Deep Backtesting 是独立功能。以账户可用的范围,以及界面显示的结果日期为准进行记录。若看不到相应套餐或菜单,不要假定日期选择一定可用。日期范围与图表数据说明


同时记录图表显示时区、交易所交易时段、数据的第一根 K 线和计算准备区间。相同的日期输入,并不保证两次运行使用相同的数据范围。


实测 Inputs 的开始时间为 2024-01-01 00:00 UTC,结束时间为 2026-01-01 00:00 UTC。韩国时间的界面中,两者均显示为 09:00。只有计算入场信号的 K 线开盘时间大于等于开始时间、且小于结束时间,才会生成新订单。


报告顶部显示的计算范围为 1980-12-12~2026-09-30,但这与日期过滤器限制的入场区间不同。实际首次入场是 2024-01-30,最后一次退出是 2025-12-23。准备计算也会使用此前已加载的 K 线,所以不能把报告日期范围当作入场日期范围。


若结束后仍有持仓,代码会在结束时间及之后的第一根计算 K 线上生成平仓订单,并在下一个可用价格更新时成交。代码并不保证恰好在结束时间平仓;在区间内生成的入场订单,也可能在下一根 K 线成交时落到区间之外。


交易为 0 笔时,先逐步检查订单的生成路径


没有交易时,先确认脚本属于策略,且包含生成订单的指令。若图表显示运行错误,打开并阅读错误内容。接着检查日期条件与图表数据是否重叠,以及入场条件是否成立。


订单数量为 0,或资金和保证金无法承担订单规模,也可能导致没有交易。期货合约金额由图表价格、点值和数量共同决定,不能只看价格就判断资金足够。


交易为 0 笔的检查顺序: 策略类型与运行错误 → 数据与日期范围 → 入场条件 → 订单数量与资金。每次只调整一项,再观察是否出现交易。第一笔交易生成后,把入场和退出时间、价格、数量及信号与原图表核对。


按照策略不生成订单的原因找到问题后,再查看绩效指标。没有交易的运行和产生亏损的运行,需要不同的下一步行动。


实测中,把快速 SMA 和慢速 SMA 都设为 10 后,报告显示 “This report requires trade data”(此报告需要交易数据)。两条相同的均线不会出现向上或向下交叉,因此订单条件没有满足。将慢速 SMA 恢复为 30,即可恢复原来的 10/30 交叉条件。这里的原因是条件未成立,增加资金无法解决。


SMA 10/10 时没有交易的报告
SMA 10/10 时没有交易的报告相同的均线不会交叉。将慢速 SMA 恢复为 30。(2026-10-01)

看完净损益,要回到产生亏损的交易


净损益(Net PnL)已包含设置的手续费。如果再次扣除已付手续费(Commission paid),就会重复扣减成本。未平仓损益(Open PnL)要与已结束交易的损益分开查看。手续费处理


指标解读基准仅凭此值无法知道的事
已结束交易数统计入场后已退出的交易未来是否仍以相同频率交易
PF盈利交易损益之和 ÷ 亏损交易损益之和的绝对值利润是否集中于少数交易或时段
平均每笔交易结果净损益 ÷ 已结束交易数每笔交易的损益分布和大额亏损规模
最大回撤同时查看 K 线内或收盘间的计算方式,以及百分比的分母未来回撤是否仍保持在此范围内

已结束交易数、PF 和平均每笔交易结果不包含未平仓头寸。如果亏损之和为 0,就难以用一个有限的 PF 比较。不要为所有策略设定统一的合格 PF 或最低交易数,要结合交易时间与损益分布判断。


K 线内(intrabar)最大回撤包含持仓期间 K 线内部的价格变化,可能不同于仅按已结束交易累计损益计算的回撤。还要区分以初始资金为分母的百分比和使用其他分母的百分比。对照K 线内回撤与相对于初始资金的回撤后,再打开大额亏损交易前后的图表。


使用相同源代码运行的 TradingView 界面,与英文交易列表 CSV 已进行核对。CSV 共 18 行入场和退出记录,对应 9 笔已结束交易。入场行和退出行会重复显示同一笔交易的损益,所以复核计算只使用退出行。


项目示例实测结果含义仅凭此值无法知道的事
已结束交易9 笔,盈利 3 笔、亏损 6 笔已结束交易的样本后续交易频率和可重复性
Total PnL169.84 USD,+1.70%与 CSV 退出行净损益之和一致其他日期范围能否产生相同损益
Profit factor界面 1.81,CSV 约 1.81015用 379.48 ÷ 209.64 复核对少数盈利交易的依赖程度
Expectancy18.87 USD169.84 ÷ 9 ≈ 18.87111单笔交易的亏损规模和分布
Max drawdown界面 239.05 USD,2.35%TradingView 对应计算显示的最大回撤能否仅凭 CSV 复原相同的 K 线内路径

CSV 的损益合计为 169.84 USD。盈利之和 379.48 USD 与亏损绝对值之和 209.64 USD,来自对每笔交易已舍入的 CSV 字段求和。TradingView 的总亏损界面显示为 209.63 USD,存在 0.01 USD 差异;这说明舍入后的行值之和与内部汇总显示可能略有不同。


不能把界面回撤 2.35% 解释成 239.05 ÷ 10,000 得出的百分比。该计算约为 2.3905%,因此要区分所显示回撤指标的计算基准。收益率 +1.70% 则与 169.84 ÷ 10,000 × 100 = 1.6984% 舍入后的值一致。


TradingView 实际运行结果
TradingView 实际运行结果记录了 9 笔已结束交易、净损益 169.84 USD 和 PF 1.81。(2026-10-01)

导入交易列表 CSV,可以重新查看亏损区间


在交易列表(Trades 或 List of Trades)的导出(Download)功能中保存 CSV。绩效指标导出和交易列表导出包含的信息不同。即使界面提供 XLSX 完整报告,本指南导入 OptiNod 的输入仍是交易列表 CSV。官方导出说明


打开文件,确认其中包含交易编号、入场和退出时间,以及净损益。把输入和输出文件名,与此前记录的策略、品种、K 线周期及设置一起保存。简单统计 CSV 中全部入场和退出行,得到的数字可能不同于已结束交易数。


将交易列表 CSV 放入 OptiNod 分析界面,先把已结束交易数和净损益与原报告核对。系统支持韩文和英文表头的交易列表。如果其他语言的文件无法识别,可将 TradingView 显示语言改为韩文或英文后重新导出。只有未结束交易的文件不能用于已结束交易分析。


无需登录即可开始分析;将结果保存到账户时,需要登录或注册。在结果中找到造成损失的交易和时段,再回到这些交易的图表和条件。基于 CSV 的回撤并非原始 K 线内最大回撤的完整复原,阅读时要同时查看计算基准。


本次运行把英文交易列表 CSV 的 18 行原样导入 OptiNod,确认分析可以打开。OptiNod 显示已完成头寸 9 个、已实现损益 170 USD、PF 1.81。170 USD 是 169.84 USD 的界面舍入值;第一笔交易显示为 2024-01-30 入场、2024-02-12 退出,损益 -13.65 USD。


OptiNod 的 239 USD 在界面中明确标注为基于交易记录的估算回撤。即使它与 TradingView 的 239.05 USD 舍入后接近,也不意味着完整复原了官方 K 线内 MDD。下一步,打开交易列表中的这笔首次亏损交易,把入场和退出条件及成本与原图表核对。


同一 CSV 的 OptiNod 分析结果
同一 CSV 的 OptiNod 分析结果显示 9 个已完成头寸、PF 1.81,以及基于交易记录的估算回撤。(2026-10-01)

下一次运行,要区分改变的条件和保留的条件


比较成本时,固定源代码、输入值、品种、K 线周期、日期范围和订单规模。比较其他日期范围时,固定规则和成本,只改变日期。将同一个文件按时间拆分分析,与在新数据区间重新运行策略验证,是不同的操作。


成本与成交可继续阅读滑点、手续费与流动性,信号时点可阅读前视偏差与重绘,设置附近的稳定性可阅读过拟合。滚动前推分析说明如何在未用于优化的区间重复验证流程,回测与实盘讨论与真实交易产生差异的环节。


保存下一次运行时,用一句话写下改变了什么。保留相同条件和交易记录,才能回到造成结果差异的交易。

检查你自己的回测结果

上传优化结果 CSV 或 TradingView 策略的交易列表,即可同时查看绩效指标和稳健性检查结果。无需登录即可分析。

分析我的结果文件 查看分析示例