PR

Pine Scriptのリペイント問題を完全理解する【request.security()の罠と回避コード】

未分類

この記事でわかること

  • リペイントとは何か、なぜバックテスト結果が信用できなくなるのか
  • リペイントが起きる3つの原因と、それぞれの見分け方
  • request.security()でリペイントを防ぐ正しいコードの書き方

「バックテストでは勝率80%だったのに、実際に動かしたら全然シグナルが違う」。マルチタイムフレームのインジケーターを自作した人が必ず一度はぶつかるのが、このリペイントという問題です。

原因の多くはrequest.security()の使い方にあります。この記事では、リペイントが起きる仕組みと、そのまま貼り付けて使える回避コードを解説します。Pine Script v5・v6の両方で共通する内容です。

📊 この記事はTradingViewユーザー向けです

TradingViewをまだ使っていない方は、まず無料アカウントを作成してみましょう。登録は30秒、クレジットカード不要です。

無料でTradingViewを始める →

リペイントとは何か

リペイントとは、過去のバーに表示されるシグナルや値が、後から書き換わってしまう現象のことです。

チャートを開いた瞬間は「3本前のローソク足で買いシグナルが出ていた」ように見えるのに、時間が経ってチャートを開き直すと、そのシグナルが消えていたり別の位置に移動していたりします。これでは、バックテスト(過去検証)で見えていた好成績が、リアルタイムでは再現できません。

やっかいなのは、リペイントするインジケーターほど過去チャート上では「よく当たっているように見える」点です。未来の情報を使って過去を描いているので、当たって見えるのは当然なのです。

リペイントが起きる3つの原因

原因 内容
未確定バーの値を使う 形成途中のローソク足の終値などを条件に使うと、確定までに値が変わる
上位足の未来参照 request.security()で上位足の未確定・未来の値を持ってきてしまう
未来関数の使用 ZigZagやfractalなど、確定に数本先の情報が必要な描画

この中で最も多く、かつ気づきにくいのが2番目のrequest.security()によるものです。順番に見ていきます。

request.security()でリペイントする典型例

下位足のチャートに日足の200EMAを重ねたい、というよくあるケースで考えます。まずはリペイントしてしまう書き方です。

//@version=5
indicator("MTF EMA(リペイントする悪い例)", overlay=true)

// lookahead_on を単体で使うと未来を参照してしまう
htfEma = request.security(syminfo.tickerid, "D",
     ta.ema(close, 200),
     lookahead=barmerge.lookahead_on)

plot(htfEma, color=color.red, linewidth=2)

barmerge.lookahead_onを単体で指定すると、TradingViewは「その日足が最終的に確定したときの値」を、日足がまだ始まったばかりの過去バーにまで先取りして表示します。つまり未来の値を過去に持ち込んでいる状態です。過去チャートでは完璧なラインに見えますが、リアルタイムでは同じ値になりません。

リペイントを防ぐ正しい書き方

Pineの公式コミュニティ(PineCoders)で確立されている定番パターンが、lookahead_onと1本前オフセット[1]の組み合わせです。

//@version=5
indicator("MTF EMA(リペイントしない正しい例)", overlay=true)

htf    = input.timeframe("D", "上位足")
emaLen = input.int(200, "EMA期間", minval=1)

// [1] で「1本前に確定した上位足の値」を取得する
htfEma = request.security(syminfo.tickerid, htf,
     ta.ema(close, emaLen)[1],
     lookahead=barmerge.lookahead_on)

plot(htfEma, color=color.orange, linewidth=2)

ポイントはta.ema(close, emaLen)[1]の部分です。「1本前に確定した上位足の値」だけを参照するため、履歴(過去バー)でもリアルタイムでも常に同じ確定値を使うことになり、リペイントしなくなります。

lookahead_on[1]は必ずセットで使うのがコツです。lookahead_off単体だと、今度は上位足の途中経過の値が下位足に少しずつ漏れてくるケースがあり、これも見た目のズレの原因になります。

TradingViewで実際に試してみよう

この記事の内容はTradingViewで今すぐ実践できます。無料プランでも十分対応できます。

▶ TradingViewを無料で開く

クレジットカード不要・いつでも解約OK

安全なラッパー関数にしておく

毎回この書き方を思い出すのは大変なので、リペイントしないrequest.security()を関数にまとめておくと安全です。

//@version=5
indicator("安全なMTF参照", overlay=true)

// リペイントしない上位足参照ラッパー
// _off に 1 を渡すと確定値だけを参照する
f_secure(_tf, _expr) =>
    request.security(syminfo.tickerid, _tf, _expr[1],
         lookahead=barmerge.lookahead_on)

htf     = input.timeframe("60", "上位足")
htfHigh = f_secure(htf, high)
htfLow  = f_secure(htf, low)

plot(htfHigh, "上位足の高値", color=color.teal)
plot(htfLow,  "上位足の安値", color=color.red)

こうしておけば、複数の上位足の値を参照するときも1行で安全に呼び出せます。マルチタイムフレーム分析の実装全般はマルチタイムフレーム分析の完全ガイドで詳しく解説しています。

リペイントしているか確認する方法

自分のインジケーターがリペイントするかどうかは、以下の方法で確認できます。

  • チャートを再読み込みする:ブラウザを更新して、過去のシグナル位置が動かないか目視する
  • バーリプレイで比べる:バーリプレイ機能で「そのバーがリアルタイムだったとき」の表示と、確定後の表示を見比べる
  • barstate.isconfirmedを条件に入れる:シグナルを確定足だけに限定すると、未確定バーでのちらつきを防げる

ストラテジーの信頼性を検証する手順はバックテストの実行方法strategy()での本格的な設計ガイドもあわせて確認してください。

こんな場合はリペイントを気にしなくてよい

  • 現在の時間足だけで完結するインジケーターの場合request.security()を使わず、確定足の値だけを見るなら基本的にリペイントは起きません
  • 描画・視覚確認だけが目的で、売買判断に使わない場合:厳密な再現性が不要なら、多少のズレは実用上問題になりません
  • あえてリアルタイムの途中経過を見たい場合:現在進行中の上位足の動きを監視したいなら、確定値ではなくリアルタイム値を使う方が目的に合います

まとめ

  • リペイントは過去のシグナルが後から書き換わる現象で、バックテスト結果を信用できなくする
  • 最大の原因はrequest.security()の未来参照。lookahead_on[1]をセットで使うと防げる
  • 安全なラッパー関数を用意し、確定足を参照する習慣をつけるとハマりにくい

リペイントを避けた正しいコードをAIに書かせたい場合は、Pine Scriptを正確に書かせるプロンプトの書き方で「リペイントしない実装で」と指定するコツを解説しています。上位足を扱う本格的なインジケーター開発では、有料プランの上位足データや複数チャート表示が役立ちます。

TradingViewを始めるなら、まずは無料プランで試してみましょう。有料プランへのアップグレードで、さらに高度な機能が使えます。

TradingViewを無料で始める

タイトルとURLをコピーしました