EBBXライブラリを使った機能強化版インジケータ(202409版)
はじめに
タイトル画像のチャートを表示するインジケータの紹介です。次のリンク先で紹介したebbx 202408に対して更に機能強化したものになります。今回も末尾にソースがあります。TradingViewの仕様を推測して作っている部分や、最近書き換えた部分もあるので、不十分なところもあるかもしれません。何かありましたらお知らせください。
今回の内容の中で、セッションの塗り分けについてはEBBXと関係なく使うこともできます。次の2行をコピペするだけで誰でも使えるのでどうぞ。
import dig_dig_11/lib_beta/2 as dd11b
bgcolor(dd11b.get_bg_color())
セッションの塗り分けを追加
タイトル画像のようにチャートの背景に色を塗り、次の3つのセッションの範囲を示すものです。
session0 東京市場オープン~東京市場クローズ
session1 欧州市場オープン~米国市場オープン(両方オープン)
session2 欧州市場クローズ~米国市場クローズ(両方クローズ)
欧州市場と米国市場が重なっている時間に色を塗らないという少し変わった仕様なのでご注意ください。目に入る色の数を減らすための仕様です。
それぞれの市場のオープン、クローズの時間、塗る色などがオプションで指定できます。デフォルトでは60分単位の時間指定だけが可能です。1分、5分などの細かい単位で指定するには、check_intervalも指定してください。
色分けする市場オープン・クローズの時間が夏時間かどうか、取り扱い市場が夏時間かどうかを計算して、色を塗る時間帯を自動補正しています。
取り扱い市場が未対応のタイムゾーンの場合には補正ができません。例えばシンガポールの日経225の場合は、次のように中央上に赤で Asia/Singapore is unknown と出ます。この場合、時間と色の関係が狂います。時差と夏時間のルールを追加してください。希望があればわんわんのほうでもできるだけ対応します。
gごとに縦の区切り線を入れる機能も含まれています。この機能が不要の場合にはvline_width=0としてください。また、g=16hのような半端な値の動作は適当です。
セッションの色は30分足以下で塗るようになっています。これを変更する場合は、ソースの「30分足より長ければ色を付けない」とコメントがある行の数値を書き換えてください。
ソースは次の通りです。
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
BTCUSDなど週7日銘柄への対応
前回、g=1W(週)などと指定できるようにしましたが、1週間は5日という前提になっていました。今回、1週間は7日という扱いを可能にしました。
1ヶ月、1年についても、1週間に連動して変わるようにしてあります。
次のコードで行っています。syminfo.prefixがCRYPTOかCOINBASEのときに週7日と判定するようにしてあります。わんわんは週7日の銘柄はほとんど馴染みないです。よい指定のしかたがあったら教えてください。
// @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
テーブルから自動でgを選ぶ機能の追加
前回は、値と単位の組み合わせでgを指定できるようにしました。今回は、現在の時間足を使った自動選択を追加しました。
gの値として0を指定したときに自動選択モードになります。自動選択モードではテーブルに登録されたgの中で、現在の時間足でのbarの数が48以上になる最小のものが選ばれます。48という値はmin_g_in_barsを指定することで変更できます。テーブルはa_readable_gを指定することで変更できます。次のコードで実現しています。
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)
おわりに
他に、細かいですが、テーブル作成関数の引数や、色を少し変えたりしています。また、セッションの塗り分けに使ったget_bg_color()は遅めです。高速化していただけるとうれしいです。
上ではソースの注目部分のみを取り上げましたが、今回のEBBXのソース、使っているライブラリ dig_dig_11/lib_beta/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("ebbx 202409", overlay=true)
import dig_dig_11/lib202408/1 as dd11
import dig_dig_11/lib_beta/2 as dd11b
var g_value = input.float(0, title="g value", minval=0, inline="g")
var g_unit = input.string("b", title="unit", options=["b", "s", "m", "h", "D", "W", "M", "Y"], inline="g")
var g_shift = input.int(0, title="shift", inline="g",
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 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 g = dd11b.get_g(g_value, g_unit, g_shift)
// ebbx計算
[e0p, e0d, e1p] = dd11.ebbx(open, high, low, close, g, lic)
// バンド描画
var col_line = dd11b.gray(75)
plot(e0p + e0d*2, color=col_line, title="+2σ")
plot(e0p + e0d*1, color=col_line, title="+1σ")
plot(e0p - e0d*1, color=col_line, title="-1σ")
plot(e0p - e0d*2, color=col_line, title="-2σ")
// 塗りつぶし描画
var margin = dd11b.get_margin(g*timeframe.in_seconds()/60)
pos = dd11b.get_ebbx_pos(e1p, e0p, e0d, margin)
// pos = dd11b.get_ebbx_pos_simple(e1p, e0p) // simple_ebbx互換
col = dd11b.pos2col4(pos, not_enough=bar_index<g*exclude) // 4色版
// col = dd11b.pos2col3(pos, not_enough=bar_index<g*exclude) // 3色版
pe0p = plot(e0p, editable=false, display=display.none+display.price_scale, title="e0p")
pe1p = plot(e1p, editable=false, display=display.none+display.price_scale, title="e1p")
fill(pe0p, pe1p, color=col)
// 情報テーブル出力
var a_str = array.from(dd11b.second2readable(g*timeframe.in_seconds()))
var a_str_tt = array.from(str.tostring(g, "g=#.#bars ") + str.tostring(margin, "margin=#.0%"))
var tbl = dd11b.get_table(a_str, a_str_tt, columns=2, extra_space=extra_space)
if barstate.islast
tbl.cell_set_text(2, 0, text=str.tostring(e0d/syminfo.mintick, "#"))
for x = 1 to 2 // 0はextra spaceに使われている
tbl.cell_set_bgcolor(x, 0, dd11b.tune_color(col, transp=20))
// 背景色表示
bgcolor(dd11b.get_bg_color(g, 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(h, e1p) : e1p // 上向きのとき直近高値をmath.max(h, e1p)で更新
l := dir < 0 ? math.min(l, 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) =>
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 = table.new(position, 1+columns, rows) // カラム0はextra_space用に追加
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
ここから先は
この記事が気に入ったらサポートをしてみませんか?