見出し画像

無料のTradingViewで3つのインジケータを表示する方法


はじめに

TradingViewにお金を払っていない場合、同時に使えるインジケータは2つまでです。今回はEBBXを3つのpaneに表示する方法を紹介します。

TradingViewにお金を払っている場合も、この方法でEBBXを1つ多く表示することができます。ソース付きですので、EBBX以外にも応用してみてください。

表示されるチャート例

今回のインジケータを2つ使うと、次のようにEBBXを3つ表示することができます。

このチャートではローソク足が3つあります。この3つそれぞれのローソク足に対応した表示領域をTradingViewの用語でpaneと言います。

使っているインジケータの名前をpane左上に出すようにしてあります。上のpaneではインジケータが使われておらず、中央と下のpaneではebbx 2024 doubleという名前のインジケータが使われていることが分かります。

どのように作られているか

今回のインジケータはリンク先のインジケータをベースに作られています。以下、差分について見ていきます。

sub pane用のインジケータとして宣言する

まずインジケータの宣言部分に違いがあります。
前回のものは、次のようにoverlay=trueを指定し、main paneにオーバーレイしてインジケータを描くものでした。

indicator("ebbx 202409", overlay=true)

今回のものは、overlayについての指定がないので、デフォルトに従ってsub paneに描くことになります。

indicator("ebbx 202409 double")

main paneにはforce_overlay=trueを使って描く

インジケータの宣言部分でsub paneに描くということにしておいても、force_overlay=true と指定したところはmain paneに描かれるという機能があります。これを次のように使い、EBBXをmain paneに表示しています。 

// 描画0
plot(e0p0 + e0d0*2, color=col_line, title="+2σ", force_overlay=true, display=display-display.price_scale)
plot(e0p0 + e0d0*1, color=col_line, title="+1σ", force_overlay=true, display=display-display.price_scale)
plot(e0p0 - e0d0*1, color=col_line, title="-1σ", force_overlay=true, display=display-display.price_scale)
plot(e0p0 - e0d0*2, color=col_line, title="-2σ", force_overlay=true, display=display-display.price_scale)
var margin0 = dd11b.get_margin(g0*timeframe.in_seconds()/60)
pos0 = dd11b.get_ebbx_pos(e1p0, e0p0, e0d0, margin0)
col0 = dd11b.pos2col4(pos0, not_enough=bar_index<g0*exclude) // 4色版
pe0p0 = plot(e0p0, editable=false, display=display.none, title="e0p", force_overlay=true)
pe1p0 = plot(e1p0, editable=false, display=display.none, title="e1p", force_overlay=true)
fill(pe0p0, pe1p0, color=dd11b.tune_color(col0, tune_s=30, transp=35), display=display)

sub paneではローソク足なども自分で書く

ローソク足が書かれていないのがsub paneです。必要なローソク足をplotcandle()を使って描き、現在値のラインをline.new()などを使って描いています。

// 描画1
plot(e0p1 + e0d1*2, color=col_line, title="+2σ", display=display.all-display.price_scale)
plot(e0p1 + e0d1*1, color=col_line, title="+1σ", display=display.all-display.price_scale)
plot(e0p1 - e0d1*1, color=col_line, title="-1σ", display=display.all-display.price_scale)
plot(e0p1 - e0d1*2, color=col_line, title="-2σ", display=display.all-display.price_scale)
var margin1 = dd11b.get_margin(g1*timeframe.in_seconds()/60)
pos1 = dd11b.get_ebbx_pos(e1p1, e0p1, e0d1, margin1)
col1 = dd11b.pos2col4(pos1, not_enough=bar_index<g1*exclude) // 4色版
pe0p1 = plot(e0p1, editable=false, display=display.none, title="e0p")
pe1p1 = plot(e1p1, editable=false, display=display.none, title="e1p")
fill(pe0p1, pe1p1, color=col1)
var black = dd11b.black()
plotcandle(o1, h1, l1, c1, color=o1<c1 ? na : black, wickcolor=black, bordercolor=black)
var ln = line.new(0, c1, 0, c1, color=col_line, extend=extend.left)
if barstate.islast
    ln.set_xy1(bar_index-1, c1)
    ln.set_xy2(bar_index,  c1)

ローソク足の現在値は、「インジケータと財務指標値のラベル」の機能によって出力しています。今回追加された -display.price_scale の記述は±1σ、±2σなどの現在値を表示しないようにするものです。

4つのインジケータ?

ソース上では最初のほうに戻りますが、pane_idという入力変数があります。この値が1だとmain paneにEBBXを表示する制御にしてあります。

var pane_id = input.int(1, title="​pane id", minval=1, tooltip="1の場合のみmain paneにebbxを表示")
var display = pane_id == 1 ? display.all : display.none

1つのpaneでのみpane_idを1にして使うことを想定して作ったのですが、2つのインジケータともpane_idを1にしておくと、次のように4つのEBBXが表示できることに気が付きました。(今回は4つのgでEBBXを表示しています。)

1つ増えてよかったと一瞬思いました。ただ、1つのpaneに複数のEBBXを描くことは、コードをコピペして名前にpostfixつければいくらでもできます。
今回は3つの「pane」にEBBXを表示することが主目的です。この方法で4つのEBBXを表示することは追及しません。現状ではmain paneの左下の情報テーブルは上書きされて一方しか見えていませんが、手を加えることはやめておきます。

おわりに

しばらく前に無料のTradingViewで同時に使えるインジケータの数が3から2に減ってだいぶ厳しくなってしまいましたが、このような方法もありますので少しでも便利に使ってください。

pane_id、main paneのシンボル、時間足などを見て、各paneのシンボルやgを自動的に設定するコードを書くのもよいと思います。

上ではソースの注目部分のみを取り上げましたが、今回のEBBXのソース、使っているライブラリ dig_dig_11/lib_beta/3 の全体は次の通りです。

// 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("ebbx 202409 double")

import dig_dig_11/lib202408/1 as dd11
import dig_dig_11/lib_beta/3 as dd11b

var pane_id = input.int(1, title="​pane id", minval=1, tooltip="1の場合のみmain paneにebbxを表示")
var display = pane_id == 1 ? display.all : display.none

var g_value0 = input.float(0, title="​g0 value", minval=0, inline="g0")
var g_unit0 = input.string("b", title="​unit", options=["b", "s", "m", "h", "D", "W", "M", "Y"], inline="g0")
var g_shift0 = input.int(0, title="​shift", inline="g0",
  tooltip="value\n"
  + "  0: テーブルで設定\n"
  + "  他: 次のunitとともに解釈\n"
  + "unit\n"
  + "  b: bars\n  s: seconds\n  m: minutes\n  h: hours\n  D: days\n  W: weeks\n  M: months\n  Y: years\n"
  + "shift\n"
  + "  規定テーブルをずらす量")

var g_value1 = input.float(0, title="​g1 value", minval=0, inline="g1")
var g_unit1 = input.string("b", title="​unit", options=["b", "s", "m", "h", "D", "W", "M", "Y"], inline="g1")
var g_shift1 = input.int(0, title="​shift", inline="g1",
  tooltip="value\n"
  + "  0: テーブルで設定\n"
  + "  他: 次のunitとともに解釈\n"
  + "unit\n"
  + "  b: bars\n  s: seconds\n  m: minutes\n  h: hours\n  D: days\n  W: weeks\n  M: months\n  Y: years\n"
  + "shift\n"
  + "  規定テーブルをずらす量")

var sec1 = input.symbol("AUDJPY", title="​symbol1")
[o1, h1, l1, c1] = request.security(sec1, timeframe.period, [open, high, low, close])

var exclude = input.int(5, title="​exclude", minval=4, display=display.none, // display.noneはalertメッセージを簡潔にするため
  tooltip="最初のexclude*gで、塗りつぶしをしない")

var lic = input.string("", title="​lic", display=display.none,
  tooltip="入力なしで15分足まで使えます\n"
  + "より短い足で使うには https://x.com/dig_dig_11 のプロフィールから")

var vline_width = input.int(1, title="​vline width", display=display.none,
  tooltip="g毎に描かれる縦線の太さ")

var info_position = input.string(position.bottom_left, title="​info table position",
  options=[position.bottom_left, position.bottom_right, position.top_right], inline="info", display=display.none)
var extra_space = input.bool(true, title="​extra space", inline="info",
  tooltip="TradingViewのロゴが邪魔なときにチェックしてください")

// gを計算
var g0 = dd11b.get_g(g_value0, g_unit0, g_shift0)
var g1 = dd11b.get_g(g_value1, g_unit1, g_shift1)

// ebbx計算
[e0p0, e0d0, e1p0] = dd11.ebbx(open, high, low, close, g0, lic)
[e0p1, e0d1, e1p1] = dd11.ebbx(o1, h1, l1, c1, g1, lic)

var col_line = dd11b.gray(75)

// 描画0
plot(e0p0 + e0d0*2, color=col_line, title="+2σ", force_overlay=true, display=display-display.price_scale)
plot(e0p0 + e0d0*1, color=col_line, title="+1σ", force_overlay=true, display=display-display.price_scale)
plot(e0p0 - e0d0*1, color=col_line, title="-1σ", force_overlay=true, display=display-display.price_scale)
plot(e0p0 - e0d0*2, color=col_line, title="-2σ", force_overlay=true, display=display-display.price_scale)
var margin0 = dd11b.get_margin(g0*timeframe.in_seconds()/60)
pos0 = dd11b.get_ebbx_pos(e1p0, e0p0, e0d0, margin0)
col0 = dd11b.pos2col4(pos0, not_enough=bar_index<g0*exclude) // 4色版
pe0p0 = plot(e0p0, editable=false, display=display.none, title="e0p", force_overlay=true)
pe1p0 = plot(e1p0, editable=false, display=display.none, title="e1p", force_overlay=true)
fill(pe0p0, pe1p0, color=dd11b.tune_color(col0, tune_s=30, transp=35), display=display)

// 描画1
plot(e0p1 + e0d1*2, color=col_line, title="+2σ", display=display.all-display.price_scale)
plot(e0p1 + e0d1*1, color=col_line, title="+1σ", display=display.all-display.price_scale)
plot(e0p1 - e0d1*1, color=col_line, title="-1σ", display=display.all-display.price_scale)
plot(e0p1 - e0d1*2, color=col_line, title="-2σ", display=display.all-display.price_scale)
var margin1 = dd11b.get_margin(g1*timeframe.in_seconds()/60)
pos1 = dd11b.get_ebbx_pos(e1p1, e0p1, e0d1, margin1)
col1 = dd11b.pos2col4(pos1, not_enough=bar_index<g1*exclude) // 4色版
pe0p1 = plot(e0p1, editable=false, display=display.none, title="e0p")
pe1p1 = plot(e1p1, editable=false, display=display.none, title="e1p")
fill(pe0p1, pe1p1, color=col1)
var black = dd11b.black()
plotcandle(o1, h1, l1, c1, color=o1<c1 ? na : black, wickcolor=black, bordercolor=black)
var ln = line.new(0, c1, 0, c1, color=col_line, extend=extend.left)
if barstate.islast
    ln.set_xy1(bar_index-1, c1)
    ln.set_xy2(bar_index,  c1)

// 情報テーブル出力0
if display != display.none
    var a_str0 = array.from(syminfo.ticker, dd11b.second2readable(g0*timeframe.in_seconds()))
    var a_str_tt0 = array.from(str.tostring(g0, "g=#.#bars ") + str.tostring(margin0, "margin=#.0%"))
    var tbl0 = dd11b.get_table(a_str0, a_str_tt0, columns=3, extra_space=extra_space, force_overlay=true)
    if barstate.islast
        tbl0.cell_set_text(3, 0, text=str.tostring(e0d0/syminfo.mintick, "#"))
        for x = 1 to 3 // 0はextra spaceに使われている
            tbl0.cell_set_bgcolor(x, 0, dd11b.tune_color(col0, transp=20))

// 情報テーブル出力1
var ticker = str.split(ticker.standard(sec1), ":").get(1)
var a_str1 = array.from(ticker, dd11b.second2readable(g1*timeframe.in_seconds()))
var a_str_tt1 = array.from(str.tostring(g1, "g=#.#bars ") + str.tostring(margin1, "margin=#.0%"))
var tbl1 = dd11b.get_table(a_str1, a_str_tt1, columns=3, extra_space=extra_space)
if barstate.islast
    tbl1.cell_set_text(3, 0, text=str.tostring(e0d1/syminfo.mintick, "#"))
    for x = 1 to 3 // 0はextra spaceに使われている
        tbl1.cell_set_bgcolor(x, 0, dd11b.tune_color(col1, transp=20))

// 背景色表示
bgcolor(dd11b.get_bg_color(g0, vline_width=vline_width), title="colored session", force_overlay=true, display=display)
bgcolor(dd11b.get_bg_color(g1, vline_width=vline_width), title="colored session")
// 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

// @description dig_dig_11 beta library
library("lib_beta", overlay=true)

import dig_dig_11/lib202408/1 as dd11

//////
////// number
//////

positive(float f) =>
    dd11.positive(f)
negative(float f) =>
    dd11.negative(f)

// @function より大きいか判定する
// @param f 判定される値
// @param g 基準の値
// @returns f > g の結果
export more_than(float f, float g) =>
    positive(f - g)

// @function より小さいか判定する
// @param f 判定される値
// @param g 基準の値
// @returns f < g の結果
export less_than(float f, float g) =>
    negative(f - g)

// @function 範囲内にクリップする
// @param i クリップされるint
// @param min クリップの下限
// @param max クリップの上限
// @returns クリップの結果
export clip(int i, int min, int max) =>
    i < min ? min : max < i ? max : i

// @function 範囲内にクリップする
// @param f クリップされるfloat
// @param min クリップの下限
// @param max クリップの上限
// @returns クリップの結果
export clip(float f, float min, float max) =>
    less_than(f, min) ? min : less_than(max, f) ? max : f

//////
////// color
//////

color_at_phase(float phase, float min, float max) =>
    p = phase % 360 
    val = less_than(p, 180) ?
      min - (max-min)/60 * (p-120) : // p=120でminを通り、傾き-(max-min)/60
      min + (max-min)/60 * (p-240) // p=240でminを通り、傾き(max-min)/60
    clip(val, min, max)

// @function HSV色空間で指定された色を返す
// @param h 色相(hue) -60 <= h
// @param s 彩度(saturation) 0 <= s <= 100
// @param v 明度(value) 0 <= v <= 100
// @param t 透過度(transparency) 0 <= t <= 100
// @returns 指定された色
export hsv2color(float h, float s, float v, float t=0) =>
    clipped_s = clip(s, 0, 100)
    clipped_v = clip(v, 0, 100)
    max = clipped_v/100 * 255
    min = max * (1 - clipped_s/100)
    color.rgb(color_at_phase(h, min, max), color_at_phase(h+240, min, max), color_at_phase(h+120, min, max), t)

// @function HSV色空間での成分を返す
// @param c 色
// @returns 入力された色のHSV色空間での成分
export color2hsv(color c) =>
    rgb = array.from(color.r(c), color.g(c), color.b(c))
    max_i = // 最大値のindex
      more_than(rgb.get(0), rgb.get(1)) ? // 0、1どちらかを脱落させる
      more_than(rgb.get(0), rgb.get(2)) ? 0 : 2 : // 1が脱落した後の処理
      more_than(rgb.get(1), rgb.get(2)) ? 1 : 2  // 0が脱落した後の処理
    fw_i = (max_i + 1) % 3 // forward index(max_iより位相が進んだindex)
    bw_i = (max_i + 2) % 3 // backward index(max_iより位相が遅れたindex)
    min_i =  more_than(rgb.get(fw_i), rgb.get(bw_i)) ? bw_i : fw_i // 最小値のindex

    h = rgb.get(max_i) == rgb.get(min_i) ? 0 : // 0除算防止
      max_i * 120 // 0、120、240度の大枠決定
      + (rgb.get(fw_i) - rgb.get(bw_i)) / (rgb.get(max_i) - rgb.get(min_i)) * 60 // ±60度調整

    s = rgb.get(max_i) == 0 ? 0 : // 0除算防止
      (rgb.get(max_i) - rgb.get(min_i)) / rgb.get(max_i) * 100
    
    [(h+360)%360, s, rgb.get(max_i)/255*100]

// @function 入力された色をHSV色空間で微調整する
// @param c 色
// @param tune_h hを調整する量 -360~360
// @param tune_s sを調整する量 -100~100
// @param tune_v vを調整する量 -100~100
// @param transp 透過度(調整量ではない) 0~100
// @returns 微調整された色
export tune_color(color c, float tune_h=0, float tune_s=0, float tune_v=0, float transp=na) =>
    [h, s, v] = color2hsv(c)
    h := (h + tune_h + 360) % 360
    s += tune_s/100 * (negative(tune_s) ? s : 100-s)
    v += tune_v/100 * (negative(tune_v) ? v : 100-v)
    t = nz(transp, color.t(c)) // naの場合には元のtransp
    hsv2color(h, s, v, t)

// よく使う色の定義
// tune_color()によるh、s、vの微調整、transpの指定も可能
export black(float transp=na) => tune_color(hsv2color(0, 0, 0), transp=transp)
export white(float transp=na) => tune_color(hsv2color(0, 0, 100), transp=transp)
export gray(float v=50, float transp=na) => tune_color(hsv2color(0, 0, v), transp=transp)
export red(float tune_h=0, float tune_s=0, float tune_v=0, float transp=na) => tune_color(hsv2color(-2, 100, 92), tune_h, tune_s, tune_v, transp)
export green(float tune_h=0, float tune_s=0, float tune_v=0, float transp=na) => tune_color(hsv2color(122, 100, 50), tune_h, tune_s, tune_v, transp)
export blue(float tune_h=0, float tune_s=0, float tune_v=0, float transp=na) => tune_color(hsv2color(212, 100, 90), tune_h, tune_s, tune_v, transp)

//////
////// ebbx
//////

// @function e1pの方向の計算で使うmarginを計算する
// @param g_in_minutes 分単位で表したg
// @returns e0dに対する割合を表すmargin
export get_margin(float g_in_minutes) =>
    // g_in_minutes=1のとき0.1(つまり10%)を返す
    // g_in_minutes=256のとき0.05、256^2のとき0.025と、256倍になるたび0.5倍になる
    0.1 * math.pow(0.5, math.log(g_in_minutes)/math.log(256))

// @function e1pの向きとe1pとe0pの上下関係でポジションを計算する
// @param e1p ebbxのe1p
// @param e0p ebbxのe0p
// @param e0d ebbxのe0d
// @param margin e1pの方向判定で、逆行を e0d*margin まで許す
// @returns ポジション(+2, +1, -1, -2)
export get_ebbx_pos(float e1p, float e0p, float e0d, float margin) =>
    var dir = +1 // e1pの向き(+1 上向き、-1 下向き)
    var h = e1p // e1pの直近高値
    var l = e1p // e1pの直近安値
    
    dir :=
      less_than(e1p, h-e0d*margin) ? -1 : // 直近高値-e0d*marginをe1pが下回れば下向き
      more_than(e1p, l+e0d*margin) ? +1 : // 直近安値+e0d*marginをe1pが上回れば上向き
      dir
    h := dir > 0 ? math.max(nz(h, e1p), e1p) : e1p // 上向きのとき直近高値をmath.max(h, e1p)で更新
    l := dir < 0 ? math.min(nz(l, e1p), e1p) : e1p // 下向きのとき直近安値をmath.min(l, e1p)で更新
    dir > 0 ? // dirが正なら強気
      more_than(e1p, e0p) ? +2 : +1 : // e1p > e0pだとより強気
      less_than(e1p, e0p) ? -2 : -1 // e1p < e0pだとより弱気

// @function e1pの傾きとe1pとe0pの上下関係でポジションを計算する
// @param e1p ebbxのe1p
// @param e0p ebbxのe0p
// @returns ポジション(+2, +1, -1, -2)
export get_ebbx_pos_simple(float e1p, float e0p) =>
    less_than(e1p[1], e1p) ? // e1pが右上がりなら強気
      more_than(e1p, e0p) ? +2 : +1 : // e1p > e0pだとより強気
      less_than(e1p, e0p) ? -2 : -1 // e1p < e0pだとより弱気

//////
////// pos2col
//////

// @function ポジションで4色に塗り分ける
// @param pos ポジション
// @param not_enough 経過時間が短いので色分けしない
// @param color_bull0 弱買の色
// @param color_bull1 買の色
// @param color_bear0 弱売の色
// @param color_bear1 売の色
// @returns 選択された色
export pos2col4(int pos, bool not_enough=false, color color_bull0=na, color color_bull1=na, color color_bear0=na, color color_bear1=na) =>
    var col_bull0 = nz(color_bull0, red(tune_s=-75, tune_v=+90)) // 弱買
    var col_bull1 = nz(color_bull1, red(tune_s=-50, tune_v=+70)) // 買  
    var col_bear0 = nz(color_bear0, blue(tune_s=-75, tune_v=+90)) // 弱売
    var col_bear1 = nz(color_bear1, blue(tune_s=-50, tune_v=+70)) // 売
    not_enough ? na :
      pos > 0 ? pos > 1 ? col_bull1 : col_bull0 :
      pos < 0 ? pos < -1 ? col_bear1 : col_bear0 :
      na // pos == 0 のとき

// @function ポジションで3色に塗り分ける
// @param pos ポジション
// @param not_enough 経過時間が短いので色分けしない
// @param color_bull 買の色
// @param color_bear 売の色
// @param color_neutral 中立の色
// @returns 選択された色
export pos2col3(int pos, bool not_enough=false, color color_bull=na, color color_bear=na, color color_neutral=na) =>
    var col_bull = nz(color_bull, red(tune_s=-60, tune_v=+80)) // 買
    var col_bear = nz(color_bear, blue(tune_s=-60, tune_v=+80)) // 売
    var col_neutral = nz(color_neutral, gray(85)) // 中立
    not_enough ? na :
      pos > 1 ? col_bull :
      pos < -1 ? col_bear : 
      col_neutral // -1 <= pos <= 1 のとき

//////
////// tool
//////

// @function 指定されたテーブルを作る
// @param a_str テーブルに表示する文字列の配列。横優先で入れる。データがなくても""などを入れる
// @param a_str_tt ツールチップで表示する文字列の配列。横優先で入れる
// @param columns テーブルの幅(extra_spaceは含まない)
// @param rows テーブルの高さ
// @param position テーブルの表示位置 position.top_left, position.top_center, position.top_right, position.middle_left, position.middle_center, position.middle_right, position.bottom_left, position.bottom_center, position.bottom_right
// @param bgcolor 背景色
// @param text_color 文字列の色
// @param text_size 文字列の大きさ size.auto, size.tiny, size.small, size.normal, size.large, size.huge 
// @param text_halign 横方向の配置方法 text.align_left, text.align_center, text.align_right
// @param extra_space 左に場所を空けるかどうか
// @returns 生成されたテーブル
export get_table(array<string> a_str, array<string> a_str_tt=na, int columns=1, int rows=1,
  string position=position.bottom_left,
  color bgcolor=na,
  color text_color=na,
  string text_size=size.normal,
  string text_halign=text.align_right, 
  bool extra_space=false,	
  bool force_overlay=false) =>
    var col = nz(text_color, black())
    var col_bg = nz(bgcolor, gray(95))
    var count = array.size(a_str)
    var count_tt = na(a_str_tt) ? 0 : array.size(a_str_tt)
    var tbl = force_overlay ? // ライブラリでconst引数が使えないことを回避するため
      table.new(position, 1+columns, rows, force_overlay=true) : // カラム0はextra_space用に追加	
      table.new(position, 1+columns, rows, force_overlay=false)
    if extra_space
        tbl.cell(0, 0, text="          ", text_size=size.small) // 場所を空けるため
    for y = 0 to rows-1
        for x = 0 to columns-1 // 横優先で入っているので、内側ループでは横を連続して処理
            index = y*columns + x
            txt = index < count ? array.get(a_str, index) : "" // 要素が足りなければ""で補う
            tbl.cell(1+x, y, text=txt, text_size=text_size, text_halign=text_halign, text_color=col, bgcolor=col_bg)
            if index < count_tt
                tbl.cell_set_tooltip(1+x, y, array.get(a_str_tt, index))
    tbl

//////
////// time
//////

// @function 1週間に何日あるか計算する
// @returns 1週間に何日あるか
export get_days_in_week() =>
    var p = syminfo.prefix
    var t = syminfo.ticker
    var pt = p + ":" + t  
    p == "CRYPTO" or p == "COINBASE" // prefixだけで判定したい場合の書き方
      // or pt == "COINBASE:BTCUSD" // prefixとticker合わせて判定したい場合の書き方
      // or t == "BTCUSD" // これだとOANDA:BTCUSDなどが7日になるので間違い
      ? 7 : // 1週間は7日
      5 // 1週間は5日

// @function 1年に何日あるか計算する
// @returns 1年に何日あるか
export get_days_in_year() =>
    get_days_in_week() == 7 ? 365.24219 : // 1年は365日強(太陽年)
      259.0 // 1年は259日

// @function 1ヶ月に何日あるか計算する
// @returns 1ヶ月に何日あるか
export get_days_in_month() =>
  get_days_in_year() / 12.0

// @function 1日に何時間あるか計算する
// @returns 1日に何時間あるか
export get_hours_in_day() =>
    24

export readable2seconds(float f, string unit) =>
    var hid = get_hours_in_day()
    math.round(
      unit == "b" ? f :
      unit == "s" ? f :
      unit == "m" ? f*60 :
      unit == "h" ? f*60*60 :
      unit == "D" ? f*60*60*hid :
      unit == "W" ? f*60*60*hid*get_days_in_week() :
      unit == "M" ? f*60*60*hid*get_days_in_month() :
      unit == "Y" ? f*60*60*hid*get_days_in_year() :
      na)

// @function 値と単位からbarの数に換算する
// @param f 値
// @param unit 単位
// @returns 換算されたbarの数
export readable2bars(float f, string unit) =>
    unit == "b" ? f : readable2seconds(f, unit) / timeframe.in_seconds()

// @function 秒を読みやすい単位に換算にする
// @param s 秒で表された時間
// @returns 読みやすい単位に換算した結果
export second2readable(float s) =>
    var hid = get_hours_in_day()
    s < 60 ? str.tostring(s, "#s") :
      s < 60*60 ? str.tostring(s/60, "#m") :
      s < 60*60*hid ? str.tostring(s/60/60, "#.#h") :
      s < 60*60*hid*get_days_in_week() ? str.tostring(s/60/60/hid, "#.#D") :
      s < 60*60*hid*get_days_in_month() ? str.tostring(s/60/60/hid/get_days_in_week(), "#.#W") :
      s < 60*60*hid*get_days_in_year() ? str.tostring(s/60/60/hid/get_days_in_month(), "#.#M") :
      str.tostring(s/60/60/hid/get_days_in_year(), "#.#Y")

// @function 分を読みやすい単位に換算にする
// @param s 分で表された時間
// @returns 読みやすい単位に換算した結果
export minute2readable(float m) =>
    second2readable(m*60)

//////
////// indicator
//////

get_g_from_table(string[] a_readable_g=na, int min_g_in_bars=48, int shift=0) =>
    a_g = na(a_readable_g) ? array.from("1m", "10m", "1h", "1D", "1W", "1M", "1Y", "10Y") : a_readable_g
    a_g_in_seconds = array.new_int()
    for i in a_g
        array.push(a_g_in_seconds, readable2seconds(str.tonumber(str.match(i, "[\\d]+")), str.match(i, "[\\D]")))

    min_g_in_seconds = min_g_in_bars * timeframe.in_seconds()
    int index = na
    for i = 0 to array.size(a_g_in_seconds)-1
        if min_g_in_seconds <= array.get(a_g_in_seconds, i)
            index := i
            break
        
    array.get(a_g_in_seconds, math.max(0, index + shift)) / timeframe.in_seconds()

// @function gを計算する(単位はbars)
// @param g_value gの値(0のときはテーブルから選択する)
// @param g_unit gの単位
// @param g_shift テーブルのシフト
// @param a_readable_g gのテーブル(小さい順に並べる)
// @param min_g_in_bars gがこれ以上になるようにテーブルから選択する
// @returns 計算されたg
export get_g(float g_value, string g_unit, int g_shift=0, string[] a_readable_g=na, int min_g_in_bars=48) =>
    g_value != 0 ?
      readable2bars(g_value, g_unit) :
      get_g_from_table(a_readable_g, min_g_in_bars, g_shift)

//////
////// background color
//////

var utco_local = 9 // TradingViewの表示で使っているtimezoneのUTCオフセット
conv_time(t, adj) =>
    str.tostring((t + (adj - utco_local) * 100 + 2400) % 2400, "0000")

in_session(ses) => // そのbarがsessionに入っているか
    not na(time(timeframe.period, ses))

tf_change(string tf, simple int width) =>
    width == 0 ? false : (ta.change(time(tf), width) != 0)

// @function 取引セッションで塗り分けた背景色を計算する
// @param g ebbxのgの値(ebbxを使わない場合は指定しない)
// @param open_jp 日本市場開始時間(デフォルト900)
// @param close_jp 日本市場終了時間(デフォルト1500)
// @param open_eu 欧州市場開始時間(デフォルト1700)
// @param open_us 米国市場開始時間(デフォルト2200)
// @param close_eu 欧州市場終了時間(デフォルト100)
// @param close_us 米国市場終了時間(デフォルト600)
// @param color_session0 open_jp-close_jpの色
// @param color_session1 open_eu-open_usの色(両方openなので注意)
// @param color_session2 close_eu-close_usの色(両方closeなので注意)
// @param color_vline 縦区切り線の色
// @param vline_width 縦区切り線の太さ(0で区切り線なし)
// @param check_interval セッション中かどうかの判定を何分ごとに行うか
// @returns 取引セッションで塗り分けるための色
export get_bg_color(float g=0,
  simple int open_jp=900, simple int close_jp=1500, simple int open_eu=1700, simple int open_us=2200, simple int close_eu=100, simple int close_us=600,
  color color_session0=na, color color_session1=na, color color_session2=na, color color_vline=na, simple int vline_width=1, simple int check_interval=60) =>
    var col_session0 = nz(color_session0, hsv2color(60, 10, 100))
    var col_session1 = nz(color_session1, hsv2color(85, 9, 100))
    var col_session2 = nz(color_session2, hsv2color(120, 6, 100))
    var col_vline = nz(color_vline, gray(80))
    var timeframe = timeframe.in_seconds()
    var utco =
      syminfo.timezone == "Asia/Tokyo" ? 9 : // TOPIXなどで使われる
      syminfo.timezone == "Europe/Paris" ? 1 : // PX1などで使われる
      syminfo.timezone == "Etc/UTC" ? 0 : // BITCOINなどで使われる
      syminfo.timezone == "America/New_York" ? -5: // USDJPYなどで使われる
      syminfo.timezone == "America/Chicago" ? -6 : // VIXなどで使われる
      24
    if utco == 24
        var a_str = array.from(syminfo.timezone + " is unknown")
        var tbl = get_table(a_str,position=position.top_center, bgcolor=red(), text_color=white())
    var timezone_is_eu =
      syminfo.timezone == "Europe/Paris" ? 1 : 0
    var timezone_is_us = 
      syminfo.timezone == "America/New_York" or
      syminfo.timezone == "America/Chicago" ? 1 : 0
    var check_tf = timeframe.from_seconds(check_interval*60)
    
    var color col = na
    if timeframe.change(check_tf) // 高速化のために判定を毎回しない
        day_of_sunday = dayofmonth - dayofweek + 1 // 週初の日曜の日付。日本時間で日曜朝9時に7増える
 
        eu_dst // EUがDSTかどうか
          = (month == 3 and 25 <= day_of_sunday // 3月は週初日付が25以上=最終日曜から
          or month == 10 and day_of_sunday < 25 // 10月は週初日付が25未満=最終日曜より前
          or 3 < month and month < 10 // これらの月はぜんぶ
          ) ? 1 : 0
        us_dst // USがDSTかどうか
          = (month == 3 and 8 <= day_of_sunday // 3月は週初日付が8以上=第2日曜から
          or month == 11 and day_of_sunday < 1 // 11月は週初日付が1未満=第1日曜より前
          or 3 < month and month < 11 // これらの月はぜんぶ
          ) ? 1 : 0
        tz_dst = eu_dst*timezone_is_eu + us_dst*timezone_is_us // 市場のtimezoneが夏時間の場合の調整
        adj_jp = utco + tz_dst
        adj_eu = utco + tz_dst - eu_dst
        adj_us = utco + tz_dst - us_dst
        session0 = conv_time(open_jp, adj_jp) + "-" + conv_time(close_jp, adj_jp)
        session1 = conv_time(open_eu, adj_eu) + "-" + conv_time(open_us, adj_us)
        session2 = conv_time(close_eu, adj_eu) + "-" + conv_time(close_us, adj_us)

        col := timeframe > 60*30 ? na : // 30分足より長ければ色を付けない
          in_session(session0) ? col_session0 :
          in_session(session1) ? col_session1 :
          in_session(session2) ? col_session2 : na

    var tf_vl = g != 0 ? timeframe.from_seconds(int(g*timeframe)) :
      timeframe > 60*60*6 ? "12M" : // 年
      timeframe > 60*30 ? "M" : // 月
      "W" // 週
    var add_weekly_border = 60*60*12 < g*timeframe and g*timeframe < 60*60*24*2
    var col_weekly_border = tune_color(col_vline, tune_v=-30) // ダークモードではtune_vの符号が逆か

    col_vl = tf_change("W", vline_width) and add_weekly_border ? col_weekly_border : col_vline

    tf_change(tf_vl, vline_width) ? col_vl : col

ここから先は

0字

メンバー特典記事、メンバー限定掲示板が、他のnoteメーンバーシップと同様にあります。 このメンバ…

スタンダードプラン

¥500 / 月
初月無料

プレミアムプラン

¥1,500 / 月

この記事が気に入ったらサポートをしてみませんか?