エンジニアリング

2つのPineエンジンが食い違うとき——PineForgeとPyneCoreのクロス検証

各リリースはTradingViewとPyneCore両方へのパリティ・スイープを通します。最新スイープの数字と、なぜ「友好的な第二ソース」が最高のデバッグ道具なのか。

読了 約9分#pinecore#pineforge#parity#engineering

私たちが知る限り、TradingView の外で「実用品質」の Pine エンジンは二つだけです。うちのものと、PyneCore です。PyneSys の PyneComp が Pine を Python にトランスパイルし、PyneCore が OSS の Python ランタイムとして実行します。言語もランタイムも違うが、原材料は同じ Pine、守るべき API 定義も同じです。

PyneCore は 第二ソースのオラクルとして使っています。PineForge の各リリースは、TradingView の「取引リスト」CSV エクスポート PyneCore の実行結果の 両方 に対してパリティ・スイープを回します。三者が揃えば結果を信じる。二対一なら外れた側にバグがありがちで、たいていはこちらです。

この記事は、最新スイープの数字がどう見えるか、という話です。

コーパス

公開スイープに載せている参照戦略は 50 本です(より広い 162 本規模のコーパス本体は非公開。このサブセットがトレード比較レポートに載ります)。各戦略について:

  • PyneComp で Python にコンパイルし、カノニカル OHLCV 上で PyneCore が実行
  • PineForge codegen で C++ にコンパイルし、同じ OHLCV 上で pineforge-engine が実行
  • 両方を TradingView の CSV エクスポートと diff。ウィンドウは
    [OHLCV のスパン] ∩ [TV のエントリーが始まるスパン] ∩ [エンジンのエントリーが始まるスパン]
    にクリップ
  • 一致度は 5 段階(excellent / strong / moderate / weak / minimal)で付与

見出しになりやすい話

50 本のうち 47 本は PineForge と PyneCore で同じティアに収まります。両エンジンとも TV の CSV に対して ≥95% のトレード一致で excellent を取ったのが 47 本。そのうち 2 本だけ PineForge が strong —— PineForge 側の コード差分の数え方がいくつかの境界ケースでティアに効くアーティファクトです。

ティアが食い違う 3 本は、どれも PineForge の方が上。つまり PyneCore が TradingView からずれる場面で、こちらはまだ TV に寄せられている、という読みができます。

StrategyPineForgePyneCoreメモ
49-partial-exit-qty-percent🟢 excellent🟠 weakPyneCore が出口 fill を出し過ぎ
06-liquidity-sweep🟢 excellent🟡 moderatePyne 側で出口タイミングが漂う
07-scalping-strategy🟢 excellent🟡 moderatePyne で PnL p90 が高いがエントリーは一致

一番気になるやつ

49-partial-exit-qty-percent が一番の隔たりです。この戦略は strategy.exit(qty_percent=...) で部分利確をはがし、ひと回りしたらまた建て直す——というサイクルを繰り返します。テストウィンドウでは:

TV trades (raw, in-window):  725
PineForge engine trades:     852  →  725 in-window  →  725 matched (100% of TV)
PyneCore  engine trades:    3297  →  2805 in-window →  582 matched (80.3% of TV)

PyneCore のこの戦略に対するカウント差分は +74% です。PineForge は 0%

デシル別メトリクスはこうです:

PineForge: count_delta 0.0000% · entry p90 0.0000% · exit p90 0.0004% · PnL p90 0.1321%
PyneCore : count_delta 74.1533% · entry p90 0.0000% · exit p90 1.0376% · PnL p90 (high)

言い換えると、両エンジンとも エントリーは同じバーで撃っている(両方 entry p90 が 0% —— 入口はピタリ)。争点は 出口です。PyneCore は TradingView と同じ戦略に対しておおよそ 4 倍の出口 fill を出しています。おそらく、同じ qty_percent 節が TV のオーダ処理が「完了」と見なす前に 再武装してしまう、という類の隅です。

これは PyneCore の品質を値踏みしている話ではありません。Pine の strategy.exit() まわりの 隅のセマンティクスで、パリティ・スイープがこちらの実装を殴ってから TV に寄せました。バグ探しは双方向に流れます——PyneCore と TV が一致しているのに、こちらだけ外していた時期も何度もあります。

もう二本

06-liquidity-sweep07-scalping-strategy は、形は同じで規模だけ小さいです。どちらもエントリーは 100% 揃い、出口は PyneCore 側で 1〜2 ポイント台漂うのに対し、PineForge は 0.05% 未満に収まっています。トレール型の出口や部分約定の意味論は、Pine の参照実装ほど文書化されていません。どのエンジンも 観測できる約定挙動から逆算するしかありません。

PyneSys のコンパイル API

PyneSys はコンパイルを HTTP で公開しています。curl でそのまま叩けます:

curl -X POST https://api.pynesys.io/compiler/compile \
  -H "Authorization: Bearer pyne_..." \
  --data-urlencode 'script=//@version=6
strategy("ma cross", overlay=true)
if ta.crossover(close, ta.sma(close, 20))
    strategy.entry("L", strategy.long)'

応答は OSS の pynecore ランタイム向けの Python ファイルです:

"""
@pyne
 
This code was compiled by PyneComp v6.0.31 — the Pine Script to Python compiler.
Run with open-source PyneCore: https://pynecore.org
Compile Pine Scripts online at PyneSys: https://pynesys.io
"""
from pynecore.lib import close, script, strategy, ta
 
 
@script.strategy("ma cross", overlay=True)
def main():
    if ta.crossover(close, ta.sma(close, 20)):
        strategy.entry('L', strategy.long)
 
 
if __name__ == "__main__":
    from pynecore.standalone import run
    run(__file__)

それを .py に落として pip install pynecore、OHLCV を指させれば 第二エンジンの出力が手に入り、PineForge と diff できます。

なぜこれが効くか

一台のバックテストエンジンが「このテスト窓で 12.4% でした」と言うとき、それが意味するのは そのエンジンがそう主張しているということだけです。比較対象がなければ、エンジンの言葉を信じるしかありません。

独立した二台が同じ脚本・同じデータで同じ結果を返すなら、はるかに強い証拠です。食い違えば、その食い違い自体が仮説になります——どちらかにバグがあるか、Pine のセマンティクスがあいまいな角か、テストデータにどちらも踏んでいないエッジがあるか。どれも知っておいて損はありません。

私たちは 毎リリースこう使っています。本物の資金を載せる戦略を出すなら、あなたも同じことをした方がいいです。

この記事に書いていないこと

  • インジケータ単位のドリフト。 PineForge・PyneCore・TradingView の参照値どうしの一致は別レポートで追っています。エンジンリポの benchmarks/results/indicator_comparison.md にあります。
  • 公開スイープに載っていない内部コーパスの ~110 本。 UDT メソッド、マルチタイムフレーム、request.security、OCA 出口グループなど、Pine の隅を狙ったものです。パリティ・スイープ自体は内部では回しています。方法論をきちんと公開できたタイミングで、別記事を書く予定です。

自分でクロス検証の型を試す

二つのエンジン、一つのソース、突き合わせる出力は三つ。 全部一致なら踏み込みやすい。不一致なら、金を動かす前に何かを学べます。