OptiNod アカデミー
TradingViewバックテスト方法 — 初期設定からCSV分析まで
戦略の適用、資金・手数料・スリッページと期間の設定、取引ゼロの対処、結果の読み方とCSV分析を進めます。条件を記録し、次の検証と比較します。
最初のバックテストでは、設定と取引記録を一緒に残します。条件が残っていれば、次の結果と比較できます。
戦略を追加しても取引が出ない、手数料を入れると利益が消えることがあります。まず、どのルールがどの数量で注文を作ったかを見ます。
TradingViewのバックテストは、売買ルールを過去のデータに適用して模擬取引を確認する作業です。売買マーク、実際の約定、戦略レポートの模擬取引はそれぞれ別の記録です。
戦略を適用 → コストと期間を設定 → 最初の取引を確認 → 結果を読む → 取引一覧を保存、の順に進めます。最後にCSVをOptiNodで分析し、損失に寄与した取引を次の検証につなげます。
戦略を適用すると注文と結果を一緒に見られます
通常のローソク足で、取引所を含むシンボルと時間足を選びます。利用権限のある戦略を追加し、名前、ソースのバージョン、入力値を記録します。移動平均などのインジケーターだけではバックテストの取引は生まれません。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を上抜くとロング、下抜くと決済する独自作成の教育用コードです。別の損切り・利確や実取引アラートはなく、成績に基づく推奨ではありません。
- TradingViewのPine Editorで新しいスクリプトを開き、下のコードを貼り付けます。
- チャートへ適用し、NASDAQ:AAPL、1D、通常のローソク足に合わせます。
- Inputsの期間とBase Entry Amount、Propertiesの資金・コスト・約定設定を照合します。
- 取引一覧と指標を開き、同じ条件で下の実測値と比較します。
//@version=6
// OptiNod Learn educational example v1.0.0. AAPL standard candles, 1D.
// Simulated orders only. No alerts or webhook payloads are defined.
strategy("OptiNod Learn - SMA 10/30 Backtest Guide", 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 - Period / Capital: first input group, before signal and visual inputs.
string G_CAP = "0 · Period · Capital"
int startTime = input.time(1704067200000, "Start Time", group=G_CAP, inline="win") // 2024-01-01 00:00 UTC
int endTime = input.time(1767225600000, "End Time", group=G_CAP, inline="win", tooltip="Entries use bar opening times in [start, end). An open position is closed at the first calculated bar at or after end; market fills normally occur on the next available tick.") // 2026-01-01 00:00 UTC
float leverage = input.float(1.0, "Leverage", minval=1.0, maxval=1.0, step=1.0, group=G_CAP, tooltip="This educational stock example is unleveraged: 1x only. Margin requirement is 100%.")
float baseAmount = input.float(1000.0, "Base Entry Amount", minval=0.0, group=G_CAP, inline="amt")
string amountUnit = input.string("$", "", options=["%", "$"], group=G_CAP, inline="amt", tooltip="Margin budget per entry in USD. % uses current strategy equity; $ uses a fixed amount. Whole-share rounding makes actual exposure no greater than the budget at the signal close.")
bool useVarSizing = input.bool(true, "Variable Position Sizing", group=G_CAP, tooltip="The standard header keeps this control. This simple example always uses multiplier 1, so toggling it does not change sizing.")
string G_SIGNAL = "1 · Moving Averages"
int fastLength = input.int(10, "Fast SMA", minval=1, group=G_SIGNAL)
int slowLength = input.int(30, "Slow SMA", minval=1, group=G_SIGNAL)
string G_VIEW = "2 · Visuals"
bool showAverages = input.bool(true, "Show averages", group=G_VIEW)
color fastColor = input.color(#10b981, "Fast", group=G_VIEW, inline="palette")
color slowColor = input.color(#9aa0b5, "Slow", group=G_VIEW, inline="palette")
// AAPL whole shares. Quantity uses the signal close, not an unknowable future fill.
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="Long")
if strategy.position_size > 0 and time >= endTime
strategy.close("Long", comment="Time exit")
else if strategy.position_size > 0 and exitSignal
strategy.close("Long", comment="Exit")
// Layout: Minimal Overlay. Two averages explain the educational crossover.
plot(showAverages ? fastSma : na, "Fast SMA", color=fastColor, linewidth=2)
plot(showAverages ? slowSma : na, "Slow SMA", color=slowColor, linewidth=1)数量は1,000 USDの予算をシグナル終値で割り、整数の株数に切り捨てます。実際の約定金額が必ず1,000 USDになる注文ではありません。次の足のギャップやスリッページで約定金額は変わります。レバレッジは1倍です。Variable Position Sizingはオンですが、倍率が常に1なので切り替えても数量は変わりません。

コストと数量を先に合わせると比較条件が残ります
戦略設定のPropertiesで資金、注文数量、手数料、スリッページを設定します。次の表は実測した実行の設定と単位です。
| 項目 | 実際に使った値 | 単位 | 結果に影響する理由 |
|---|---|---|---|
| 初期資金・通貨 | 10,000 USD | USD | 開始資産と収益率の基準です |
| Base Entry Amount | 1,000、単位$ | USD/エントリー予算 | シグナル終値から整数株数を計算します |
| レバレッジ・証拠金 | 1倍、ロング・ショート100% | 倍、% | 資金内でレバレッジなしの模擬注文です |
| 手数料 | 0.05 | %/注文 | エントリー・決済ごとに売買額の0.05%です |
| スリッページ | 1 | tick | 成行・ストップの約定価格に適用します |
| 足の詳細 | Default (4 ticks per bar) | 4価格地点/足 | 過去足の約定に通常のOHLC仮定を使います |
| スクリプト実行 | On bar close | 足の確定 | 足が確定したときに交差を計算します |
| 注文実行の遅延 | One tick | 1 tick | 成行注文は次の利用可能なtickで約定します |
価格差はtick数 × シンボルの最小tick幅です。資産比率によるサイズはエントリー時の資産によって金額が変わります。コードが注文ごとに数量を指定している場合、デフォルトの数量を変えてもその注文は変わらないことがあります。プロパティの公式定義
証拠金、再計算、約定オプションも記録します。コストや注文サイズの変更を、売買ルールの改善と混同しないようにします。
Propertiesのデフォルト注文サイズは1でしたが、コードがstrategy.entry()にqtyを指定するので実数量はInputsの予算から計算されます。レポートのDefault detalizationとScript execution、戦略設定のPropertiesを照合します。

期間はチャートデータと戦略の日付条件を合わせて見ます
通常のバックテストはチャートに読み込まれたデータで実行されます。戦略の日付入力は、そのデータ内で注文を制限する条件であり、古いデータを追加する機能ではありません。期間入力があれば開始日と終了日を設定し、実際の取引時刻を意図した期間と照合します。
Testing periodの選択やDeep Backtestingは別の機能です。アカウントで利用できる範囲と画面の結果期間を記録します。期間選択がすべてのアカウントで使えるとは限りません。期間とチャートデータの説明
表示タイムゾーン、取引所のセッション、最初のデータ足、計算の準備期間も残します。日付入力が同じでもデータ範囲まで同じとは限りません。
実測Inputsは2024-01-01 00:00 UTCから2026-01-01 00:00 UTCです。韓国時間の画面では09:00でした。シグナル足の開始時刻が開始以上・終了未満の場合だけ新規注文を作ります。
レポートの計算範囲は1980-12-12~2026-09-30ですが、コードで制限したエントリー期間とは違います。実際の最初のエントリーは2024-01-30、最後の決済は2025-12-23です。準備計算には前の読み込み済み足も使うので、レポート期間をエントリー期間として読みません。
終了後もポジションがあれば、終了時刻以降の最初の計算足で決済注文を作り、次の利用可能なtickで約定します。終了時刻ぴったりに決済するコードではありません。期間内で作ったエントリー注文も次の足で期間外に約定する場合があります。
取引ゼロなら注文が作られる経路から絞り込みます
まず戦略のスクリプトであることと注文命令を確認します。実行エラーの表示があれば開いて内容を読みます。次に日付条件とデータが重なるか、エントリー条件が成立したかを見ます。
注文数量が0、または資金と証拠金が注文サイズを賄えない場合も取引が出ないことがあります。先物の契約金額はポイント価値と数量を反映するため、チャート価格だけで資金が足りるとは判断できません。
取引ゼロの確認順: スクリプトの種類と実行エラー → データと日付 → エントリー条件 → 数量と資金。一度に複数を変えず、一項目ずつ変更して取引が出るかを見ます。最初の取引が出たら、エントリー・決済時刻、価格、数量、シグナルをチャートと照合します。
注文が作られない理由から原因を絞った後に成績指標へ進みます。取引がない実行と損失が出た実行では、次の行動が異なります。
Fast SMAとSlow SMAを両方10にすると、実際に“This report requires trade data”と表示されました。同じ平均線は互いに交差せず、注文条件が成立しません。Slow SMAを30に戻すと元の10/30交差に戻ります。この原因は条件未成立なので、資金を増やしても解消しません。

純損益を読んだ後は損失取引に戻ります
Net PnLには設定した手数料がすでに反映されています。Commission paidをもう一度差し引くと二重計上になります。Open PnLは決済済みの損益と分けて見ます。手数料の扱い
| 指標 | 読み方 | この値だけでは分からないこと |
|---|---|---|
| 決済済み取引数 | エントリー後に決済された取引を数えます | 今後も同じ頻度で取引するか |
| PF | 利益取引の損益合計 ÷ 損失取引の損益合計の絶対値 | 一部の取引や期間に利益が集中しているか |
| 平均取引結果 | 純損益 ÷ 決済済み取引数 | 損益分布や大きな損失の規模 |
| 最大ドローダウン | intrabar/close-to-closeと%の分母を記録 | 今後の下落が同じ範囲に収まるか |
取引数、PF、Expected payoffには未決済ポジションを含めません。損失合計が0なら通常の比較に使える有限のPFにはなりません。共通の合格PFや最低取引数を設けず、取引時刻と損益分布を見ます。
足内(intrabar)の最大ドローダウンにはポジション保有中の値動きが含まれます。決済損益の累積だけで計算した下落とは異なることがあります。初期資金に対する%と別の分母の%も分けます。足内ドローダウンと初期資金比のドローダウンを照合し、大きな損失の前後のチャートを開きます。
実行したTradingView画面と英語の取引一覧CSVを照合しました。CSVはエントリー・決済の18行で、決済済み取引は9件です。両方の行に同じ損益が繰り返されるため、検算には決済行だけを使いました。
| 項目 | 実測結果 | 意味 | この値だけでは分からないこと |
|---|---|---|---|
| 決済済み取引 | 9件、利益3件・損失6件 | 完了した取引の標本です | 今後の頻度と再現性 |
| Total PnL | 169.84 USD、+1.70% | 決済行の純損益合計と一致 | 別の期間でも同じ結果になるか |
| Profit factor | 画面1.81、CSV約1.81015 | 379.48 ÷ 209.64で検算 | 少数の利益取引への依存 |
| Expectancy | 18.87 USD | 169.84 ÷ 9 ≈ 18.87111 | 個別の損失規模と分布 |
| Max drawdown | 画面239.05 USD、2.35% | TradingViewの該当計算での最大下落 | 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%の丸め値と一致します。

取引一覧CSVを入れると損失期間を見直せます
TradesまたはList of TradesのDownloadからCSVを保存します。成績指標と取引一覧のエクスポートでは内容が違います。全体のXLSXレポートがあっても、このガイドでOptiNodに入れるのは取引一覧CSVです。公式エクスポート説明
ファイルを開き、取引番号、エントリー・決済時刻、純損益を見ます。ファイル名と戦略、シンボル、時間足、設定を一緒に保存します。エントリー行と決済行をすべて数えるだけでは決済済み取引数と一致しないことがあります。
OptiNod分析にCSVを入れ、最初に決済済み取引数と純損益を元のレポートと比較します。韓国語・英語のヘッダーに対応しています。別の言語で認識されない場合はTradingViewの表示言語を韓国語または英語にして再エクスポートします。未決済取引しかないファイルは決済済み取引の分析に使えません。
分析はログインせずに開始でき、アカウントへの保存にはログインまたは登録が必要です。損失に寄与した取引と期間を探し、元のチャートと条件に戻ります。CSVからのドローダウンは元の足内最大ドローダウンをそのまま再現した値ではないので、計算基準も読みます。
英語CSVの18行をそのまま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という公式足内MDDをそのまま再現した意味ではありません。この最初の損失取引を開き、エントリー・決済条件とコストを元のチャートに照合します。

次の実行では変える条件と残す条件を分けます
コストを比較するときはソース、入力、シンボル、時間足、期間、注文サイズを固定します。別の期間を見るときはルールとコストを固定して日付を変えます。一つのファイルを時系列で分割する分析と、新しいデータ期間で戦略を再実行する検証は別です。
コストと約定はスリッページ・手数料・流動性、シグナル時点はルックアヘッドとリペイント、設定周辺の安定性は過剰最適化に進みます。最適化に使わなかった期間で手順を繰り返す方法はウォークフォワード分析、実取引との差はバックテストと実運用で扱います。
次の実行を保存するときは、変えた点を一行で残します。同じ条件と取引記録があれば、結果の差を生んだ取引に戻れます。