【Pineスクリプト】ごく単純なルールで取引するストラテジーを作ってみる

当ページのリンクには広告が含まれています。
目次

作るもの

Pineスクリプトで、ごく単純なルールで取引するストラテジーを作ってみます。(稼げるルールではない)
エントリーとエグジットのルール、および、ストラテジー実行時に指定できるパラメータは以下のとおり。

ロング条件・内容

  • 足確定時に、ローソク足が単純移動平均線を上抜けていたらエントリー (ショートは逆)
  • 足確定時に、ローソク足が単純移動平均線を下抜けていたらエグジット (ショートは逆)
  • ロット数は固定
  • エントリー時に固定幅で指値・逆指値決済注文を入れる
  • ポジションは1つしか持たない

パラメータ

  • 移動平均線の期間
  • ロット数
  • 決済指値・逆指値幅

参考サイト

実装

MQL5と違ってめっちゃ短いので、最初にスクリプト全体を示します。

strategy("Sample1")

// パラメータ
int   maPeriod = input.int(20, "MA Period")
int   lots     = input.int(1, "Lots")
float limitPts = input.float(0.1, "Limit Points")
float stopPts  = input.float(0.03, "Stop Points")

// 定数
const string long_id = "long"
const string short_id = "short"

// MA値を取得・描画
float ma = ta.sma(close, maPeriod)
plot(ma, color=color.orange, force_overlay=true)

// 期間
int start_tm = timestamp("GMT+9", 2024, 8, 1, 0, 0, 0)
int end_tm = timestamp("GMT+9", 2024, 8, 31, 0, 0, 0)

if (time >= start_dt) and (time <= end_dt)
    // ポジションなし
    if strategy.opentrades == 0
        // 上抜けた
        if ta.crossover(close, ma)
            // 買いエントリー
            strategy.entry(long_id, strategy.long, lots * 10000, close + limitPts, close - stopPts)

        // 下抜けた
        else if ta.crossunder(close, ma)
            // 売りエントリー
            strategy.entry(short_id, strategy.short, lots * 10000, close - limitPts, close + stopPts)

    // ポジションあり
    else
        // エントリーIDを取得
        string id = strategy.opentrades.entry_id(0)

        // ロング保有中で下抜けた、または、ショート保有中で上抜けた
        if ((id == long_id) and (close < ma)) or ((id == short_id) and (close > ma))
            // 決済
            strategy.close(id)

最低限、これだけ。

みじかっ‼

では、詳細を説明します。

スクリプトの宣言

最初の strategy( ...) は、このスクリプトがストラテジーであることの宣言です。
インジケータの場合は、indicator( ...) です。

それぞれの定義は以下のとおり。

strategy(title, shorttitle, overlay, format, precision, scale, pyramiding, calc_on_order_fills, calc_on_every_tick, max_bars_back, backtest_fill_limits_assumption, default_qty_type, default_qty_value, initial_capital, currency, slippage, commission_type, commission_value, process_orders_on_close, close_entries_rule, margin_long, margin_short, explicit_plot_zorder, max_lines_count, max_labels_count, max_boxes_count, calc_bars_count, risk_free_rate, use_bar_magnifier, fill_orders_on_standard_ohlc, max_polylines_count, dynamic_requests) → void
indicator(title, shorttitle, overlay, format, precision, scale, max_bars_back, timeframe, timeframe_gaps, explicit_plot_zorder, max_lines_count, max_labels_count, max_boxes_count, calc_bars_count, max_polylines_count, dynamic_requests) → void

うん。いまの段階で全部の引数の意味を調べる気はおきませんね。
とりあえず、最初の title だけ指定しておけば大丈夫です。
他は、使いたくなったときに調べましょう。

スクリプトの実行タイミング

Pineスクリプトは、デフォルトでは、ローソク足が確定する度に 実行されます。

じゃあ、変数の値を持ち越したい場合はどうするの?

と思いますよね。
その場合は、var を頭につけて宣言します。

< 記述例 >

strategy("...")

var int n = 0

n := n + 1
log.info("n={0,number,#}", n)

こう書くと、strategy が呼ばれるたびに、n が +1 されます。
var を書かないと、ログには常に “n=1” が出力されます。

今回は使いませんでしたが、ポジションの保有情報などを変数で保持しておきたいなどのケースで使用できそうです。

パラメータ

int   maPeriod = input.int(20, "MA Period")
int   lots     = input.int(1, "Lots")
float limitPts = input.float(0.1, "Limit Points")
float stopPts  = input.float(0.03, "Stop Points")

input.〇〇〇関数は、 スクリプト実行時のパラメータになります。
個人的には

スクリプトを直接書き換えればよくない?

という気がしますが、せっかくなので使ってみました。
きっと、オリジナルインジケータなどを公開する人が使うんでしょう。

移動平均線

// MA値を取得・描画
float ma = ta.sma(close, maPeriod)
plot(ma, color=color.orange, force_overlay=true)

単純移動平均値は、ta.sma関数で取得できます。
指数平滑移動平均値は、ta.ema関数を使用します。

ta.sma関数と ta.ema関数の定義を以下に示します。

ta.sma(source, length) → series float
ta.ema(source, length) → series float

source には close変数を指定します。
close変数には、終値が入っています。
高値なども指定できそうですが、オリジナルインジケータを作るときでなければ使わないでしょうから、ここでは触れません。

length には期間を指定します。

また、動作確認しやすいように、移動平均線をチャートに重ねて描画しています。
インジケータの値の描画には、plot関数を使用します。

plot(series, title, color, linewidth, style, trackprice, histbase, offset, join, editable, show_last, display, format, precision, force_overlay) → plot

いろいろ引数がありますが、とりあえず series, color, force_overlay だけ覚えておけば、最低限使えます。

series には MA値を指定します。

color には、色を指定します。
色は、Pineエディタ上で「color.」と入力すると候補が表示されます。
また、#rrggbb という形式でRGB値を指定できます。
この引数を省略した場合は、color.blue になります。

force_overlay には、チャートに重ねるかどうかを指定します。
true を指定すると、チャート上に描画します。
false を指定すると、オシレータ系インジケータのようにチャートの下に領域が用意されて、描画されます。
この引数を省略した場合は、false になります。

移動平均線を描画しなくていい場合は、後述するテスト期間の節の if分の中で MA値を取得しても構いません。
ただし、plot関数はトップレベルのスコープにしか記述できないので、移動平均線を描画したい場合は if分の外で MA値を取得してください。

テスト期間

int start_tm = timestamp("GMT+9", 2024, 8, 1, 0, 0, 0)
int end_tm = timestamp("GMT+9", 2024, 8, 31, 0, 0, 0)

if (time >= start_dt) and (time <= end_dt)
...

TradingViewでは、テスト期間をスクリプトで指定します。
timestamp関数で開始日時と終了日時を作成し、開始日時 ≦ time変数 ≦ 終了日時 となっているときに取引するようにします。

timestamp関数の定義は以下のとおりです。

timestamp(timezone, year, month, day, hour, minute, second) → simple int

timezone は、日本なら “GMT+9” を指定します。

year, month, day, hour, minute, second は、日時の数値を指定します。

time変数には、現在の(確定した最後の) ローソク足の開始時刻が設定されています。
終了時刻は time_close変数に入っています。

TradingView のBasicプランを利用している場合、過去5000本しかローソク足を遡れません。
そのため、5分足だと 1か月ほどしか遡れません。(金曜日のNYクローズ~月曜日のオセアニアオープンはローソク足が無いので、ギリギリ 1か月分遡れるかどうかというところ)

エントリー

// ポジションなし
if strategy.opentrades == 0
    // 上抜けた
    if ta.crossover(close, ma)
        // 買いエントリー
        strategy.entry(long_id, strategy.long, lots * 10000, close + limitPts, close - stopPts)

    // 下抜けた
    else if ta.crossunder(close, ma)
        // 売りエントリー
        strategy.entry(short_id, strategy.short, lots * 10000, close - limitPts, close + stopPts)

保有ポジションの有無を確認

strategy.opentrades変数には保有ポジション数が設定されているので、この値により、ポジションを保有しているかどうかを判断できます。

注文条件の判定

ローソク足が移動平均線を上抜けたかどうかは ta.crossover関数で判断できます。

ta.crossover関数の定義は以下のとおり。

ta.crossover(source1, source2) → series bool

ta.crossover関数は、以下の条件を満たす場合に true を返します。

  • 現在の (確定した最後の) source1 が source2 より上
  • 1本前の source1 が source2 以下

同様に、下抜けたかどうかは ta.crossunder関数で判断できます。

ta.crossunder関数の定義は以下のとおり。

ta.crossunder(source1, source2) → series bool

ta.crossunder関数は、以下の条件を満たす場合に true を返します。

  • 現在の (確定した最後の) source1 が source2 より下
  • 1本前の source1 が source2 以上

どちらも、source1close変数、source2 に上で取得したMA値を指定します。

成行の新規注文

エントリーには strategy.entry関数を使用します。

strategy.entry関数の定義は以下のとおり。

strategy.entry(id, direction, qty, limit, stop, oca_name, oca_type, comment, alert_message, disable_alert) → void

これも、最低限の引数だけ指定します。

id は注文のIDです。文字列で指定します。
この例では、ロングは冒頭で定義した定数の “long”、ショートは “short” を指定しています。

direction は、買い注文なら strategy.long、売り注文なら strategy.short を指定します。

qty は取引通貨量です。
この例では、パラメータの lots * 10000 を指定しています。

limitstop は、Take profit と Stop loss です。
この例では、現在の終値とパラメータの limitPts(指値幅)、stopPts(逆指値幅) から算出したものを指定しています。

エグジット

// エントリーIDを取得
string id = strategy.opentrades.entry_id(0)

// ロング保有中で下抜けた、または、ショート保有中で上抜けた
if ((id == long_id) and (close < ma)) or ((id == short_id) and (close > ma))
    // 決済
    strategy.close(id)

決済注文の前に、現在保有しているポジションの注文IDを取得します。
注文IDは strategy.opentrades.entry_id関数で取得できます。

strategy.opentrades.entry_id関数の定義は以下のとおり。

strategy.opentrades.entry_id(trade_num) → series string

trade_num は、0起算の注文インデックスです。
この例ではポジションを1つしか持たないので、0(ゼロ)を指定しています。

決済注文は strategy.close関数で行います。

strategy.close関数の定義は以下のとおり。

strategy.close(id, comment, qty, qty_percent, alert_message, immediately, disable_alert) → void

id には、上で取得した注文IDを指定します。

実行してみる

TradingView のPineエディタでスクリプトを保存すると、自動で strategy (や indicator) のスクリプトを実行してくれます。

<実行例> ※ 画像をクリックすると、大きく表示されます。

ご覧のとおり、買い注文の箇所を青矢印、売り注文の箇所を赤矢印、決済注文の箇所を紫矢印で示してくれます。

下のストラテジーテスタータブには、テスト結果をいろいろ表示してくれます。

なんだろう、すごくらく。
自動売買しないのなら、MT5よりTradingView のほうがいいかもね。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA



reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次