TradingViewのfloat大小比較の残念な点とその修正方法
はじめに
TradingViewのfloat(浮動小数点数)の大小比較にある残念な点を示すとともに、修正方法を書きます。
残念な動作
TradingViewでプログラムするとき、比較ってしますよね。
例えば、signalが0より大きいかどうかで赤/青に色分けしたいなら、
signal > 0 ? color.red : color.blue
と書くと思いますが、次のようにsignalがある程度大きくないと赤にならないです。siginalがプラスでも売り推奨の判定になります。知ってました?
一見同じ意味な気もしますが、
signal < 0 ? color.blue : color.red
と書くと、次のようにsignalがある程度小さくないと青にならないです。siginalがマイナスでも買い突撃してしまいます。
誰でも結果を確認できるようにソースを公開します。
最初の例のソースは次のものです。(bar_index % 41) - 20 で -20~20の値を生成して使っています。
「signalが0を上回れば強気」「signalが0を下回れば弱気」とある行のコメントアウトを入れ替えると、2つ目の例のソースになります。
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dig_dig_11
//@version=5
indicator("positive test", precision=11)
signal = ((bar_index % 41) - 20) * 1e-11
col = signal > 0 ? color.red : color.blue // signalが0を上回れば強気
// col = signal < 0 ? color.blue : color.red // signalが0を下回れば弱気
plot(signal, style=plot.style_circles, linewidth=5, color=col)
// 目盛のための横線
plot(1e-10, color=color.rgb(200, 200, 200))
plot(0, color=color.black)
plot(-1e-10, color=color.rgb(200, 200, 200))
実は上の例のようにグラフで問題点がよく見えるのは、値が小さいときです。1に近い値だと影響は減ります。値が小さいときであっても上のような結果になるのはいやなので、どうにかして直したいです。
修正方法と修正結果
修正といっても一般ユーザーができる範囲なので、次の関数を作ることにします。
positive(f) fが正の数かどうか(f>0かどうか)を返す関数
negative(f) fが負の数かどうか(f<0かどうか)を返す関数
上のグラフから、±0.0000000001(=±1e-10)が鍵に見えます。この値だけ判定がずれているので戻してあげるように関数を作りました。(なんで基本定数を10進数で定義するのか不思議ですが、TradingViewのPINEはそうなっているみたいです。)
その関数を使って0との比較を行い、修正後の最初の例は次のようになりました。
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dig_dig_11
//@version=5
indicator("positive test fixed", precision=11)
signal = ((bar_index % 41) - 20) * 1e-11
var pine_fixed_epsilon = 1e-10 // PINEで使われている固定のイプシロン
positive(float f) => f > -pine_fixed_epsilon // f > 0 かどうか
negative(float f) => f < pine_fixed_epsilon // f < 0 かどうか
col = positive(signal) ? color.red : color.blue // signalが0を上回れば強気
// col = negative(signal) ? color.blue : color.red // signalが0を下回れば弱気
plot(signal, style=plot.style_circles, linewidth=5, color=col)
// 目盛のための横線
plot(1e-10, color=color.rgb(200, 200, 200))
plot(0, color=color.black)
plot(-1e-10, color=color.rgb(200, 200, 200))
このソースを動かした結果は次の通りです。意図通り、0を上回ったときに赤になっています。0は0を上回っていないので、正しく青になっています。
上の修正ソースで「signalが0を上回れば強気」「signalが0を下回れば弱気」とある行のコメントアウトを入れ替えると、残念な動作の2つ目の例を修正したソースになります。その結果は次の通りです。意図通り、0を下回ったときに青になっています。0は0を下回っていないので、正しく赤になっています。
もともと期待した動作はこうですよね。
わんわんとしてはこれで出来たつもりです。ただ、公式または非公式な情報がどこかにあったわけではなく、わんわんが実験して内部を推測して作っただけなので、この修正に間違いがある可能性もあります。
また、もともとの挙動をTradingView側が修正したら、この関数の挙動も変わってしまうはずです。
けど修正してくれる可能性は低そうです。というのも、TradingViewに去年(2023年)末にこのあたりがおかしいことを汎用的な解決方法のソースとともに伝えたのですが、
ここから先は
この記事が気に入ったらサポートをしてみませんか?