yuya_takahashi_

Pine講座㊾ バックテスト|Moving Average Cross and/or Bbands bot の解説

教育
FX:USDJPY   米ドル/円
今回はCryptoRoxさんの
Moving Average Cross and/or Bbands bot を題材に解説しています。

このストラテジーはアイデアが満載で、
(儲かるかは別として)非常に良いコードだと思います。

利確損切り幅をチャート上に表示する方法など、
個人的にも勉強になる点がいくつかありました。

このストラテジーには以下のような機能があります。

・MAロジックのON/OFF
・BBロジックのON/OFF
(組み合わせることもできる)
・平均足のON/OFF
・検証期間の調整
・ピラミッティングの回数の調整
・取引対象によって取引量を変更
・利益確定幅の指定
・ロスカット幅の指定
・トレーリングストップの指定
(利確、損切り、トレーリングストップがない場合は途転売買)

ただし、注文は成行しか使っていないですね。
Pineスクリプトのストラテジーでは指値、逆指値を使うこともできます。

・どういう動きになるか
・どういう設定をしたら良いのか

あたりを、次回以降、
何回かに分けて解説してみようと思います。

※ 解説はコードの中で

※ コピペする場合は以下の変更を行ってください
[](全角の角括弧)→(半角の角括弧)
(全角スペース)→(半角スペース)

=====
//@version=3
strategy("Moving Average Cross and/or Bbands bot by CryptoRox の解説", overlay=true, pyramiding=1000)

//
// 取引量の設定
////

qty = 1

isALT = input(false, "Altcoin")
if isALT
 qty:= 100000000

isForex = input(false, "Forex")
if isForex
 qty:= 10000


//
// 検証期間の設定
////

testStartYear = input(1, "Backtest Start Year")
testStartMonth = input(8, "Backtest Start Month")
testStartDay = input(25, "Backtest Start Day")
testPeriodStart = timestamp(testStartYear,testStartMonth,testStartDay,0,0)

testStopYear = input(999999, "Backtest Stop Year")
testStopMonth = input(9, "Backtest Stop Month")
testStopDay = input(26, "Backtest Stop Day")
testPeriodStop = timestamp(testStopYear,testStopMonth,testStopDay,0,0)

testPeriod() =>
 time >= testPeriodStart and time <= testPeriodStop ? true : false


//
// ローソク足と平均足を切り替える
////

isHA = false

data = isHA ? heikinashi(tickerid) : tickerid

o = security(data, period, open)
h = security(data, period, high)
l = security(data, period, low)
c = security(data, period, close)

// ローソク足を描画
col = c > o ? green : red
plotcandle(o, h, l, c, "Heiken Ashi", col, black)


//
// エントリーの判断
////

// 買いシグナルと売りシグナルを入れる変数
long = na
short = na

// MAだけのロジック(設定ONのとき)
////

// ON/OFF と 計算用の数値の設定
useMA = input(true, "Use Moving Average Cross")
ma1Input = input(50, "Moving Average 1")
ma2Input = input(200, "Moving Average 2")

// MAの算出
ma1 = sma (c, ma1Input)
ma2 = sma (c, ma2Input)

// 描画用の計算値の入れ物
ma1Plot = na
ma2Plot = na

// MAロジックの根拠(買いシグナル、売りシグナル)
maLong = c > ma1 and ma1 > ma2
maShort = c < ma1 and ma1 < ma2

// MAロジックON → データの格納とシグナルの判断
if useMA
 ma1Plot := ma1
 ma2Plot := ma2
 long := maLong
 short := maShort

// 描画(MAロジックOFFのときは描画されない)
plot(ma1Plot, "ma1", blue)
plot(ma2Plot, "ma2", orange)

// ボリンジャーバンドロジック
////

// ON/OFF と 計算用の数値の設定
useBbands = input(false, "Use Bollinger Bands")
bblength = input(20, minval=1)
mult = input(2.0, minval=0.001, maxval=50)

// テクニカルの算出
basis = sma (c, bblength)
dev = mult * stdev(c, bblength)
upper = basis + dev
lower = basis - dev

// 描画用の計算値の入れ物
basisPlot = na
p1Plot = na
p2Plot = na

// BBロジックON → データの格納とシグナルの判断
if useBbands
 long := c < lower
 short := c > upper
 basisPlot := basis
 p1Plot := upper
 p2Plot := lower

// BBロジックとMAロジックがON → シグナルの判断(上書く)
if useBbands and useMA
 long := c < lower and maLong
 short := c > upper and maShort

// 描画(BBロジックがOFFのときは描画されない)
plot(basisPlot, color=red)
p1 = plot(p1Plot, color=blue)
p2 = plot(p2Plot, color=blue)
fill(p1, p2)


//
// 売買のロジック
////

// エントリーシグナルの数をカウントする
sectionLongs = 0
sectionLongs := nz (sectionLongs[1])
sectionShorts = 0
sectionShorts := nz (sectionShorts[1])

if long
 sectionLongs := sectionLongs + 1
 sectionShorts := 0

if short
 sectionLongs := 0
 sectionShorts := sectionShorts + 1

// ピラミッティングの設定値
pyrl = input(1, "Pyramiding less than") // If your count is less than this number
pyre = input(0, "Pyramiding equal to") // If your count is equal to this number
pyrg = input(1000000, "Pyramiding greater than") // If your count is greater than this number

// シグナルとピラミッティングの制限を確認
longCondition = long and sectionLongs <= pyrl or long and sectionLongs >= pyrg or long and sectionLongs == pyre
shortCondition = short and sectionShorts <= pyrl or short and sectionShorts >= pyrg or short and sectionShorts == pyre

// エントリーの価格を記録する
last_open_longCondition = na
last_open_shortCondition = na
last_open_longCondition := longCondition ? close : nz (last_open_longCondition[1])
last_open_shortCondition := shortCondition ? close : nz (last_open_shortCondition[1])

// ピラミッティングの制限を含めたエントリーのシグナルを数える
sectionLongConditions = 0
sectionLongConditions := nz (sectionLongConditions[1])
sectionShortConditions = 0
sectionShortConditions := nz (sectionShortConditions[1])

if longCondition
 sectionLongConditions := sectionLongConditions + 1
 sectionShortConditions := 0

if shortCondition
 sectionLongConditions := 0
 sectionShortConditions := sectionShortConditions + 1

// 最後のエントリーの時間を記録
last_longCondition = na
last_shortCondition = na
last_longCondition := longCondition ? time : nz (last_longCondition[1])
last_shortCondition := shortCondition ? time : nz (last_shortCondition[1])

in_longCondition = last_longCondition > last_shortCondition
in_shortCondition = last_shortCondition > last_longCondition

// エントリー後の最高値、最安値などの記録
last_high = na
last_low = na
last_high_short = na
last_low_short = na
last_high := not in_longCondition ? na : in_longCondition and (na(last_high[1]) or high > nz (last_high[1])) ? high : nz (last_high[1])
last_high_short := not in_shortCondition ? na : in_shortCondition and (na(last_high[1]) or high > nz (last_high[1])) ? high : nz (last_high[1])
last_low := not in_shortCondition ? na : in_shortCondition and (na(last_low[1]) or low < nz (last_low[1])) ? low : nz (last_low[1])
last_low_short := not in_longCondition ? na : in_longCondition and (na(last_low[1]) or low < nz (last_low[1])) ? low : nz (last_low[1])

// トレーリングストップの設定
////

// 設定
isTS = input(false, "Trailing Stop")
tsi = input(0, "Activate Trailing Stop Price") / qty
ts = input(0, "Trailing Stop") / qty
// 判断
long_ts = isTS and not na(last_high) and crossunder(low, last_high - ts ) and longCondition == 0 and high >= (last_open_longCondition + tsi)
short_ts = isTS and not na(last_low) and crossover(high, last_low + ts ) and shortCondition == 0 and low <= (last_open_shortCondition - tsi)
// 描画
tsColor = isTS and in_longCondition and last_high >= (last_open_longCondition + tsi) ? blue : isTS and in_shortCondition and last_low <= (last_open_shortCondition - tsi) ? blue : white
tsiColor = isTS and in_longCondition and last_high >= (last_open_longCondition + tsi) ? white : isTS and in_shortCondition and last_low <= (last_open_shortCondition - tsi) ? white : blue
plot(isTS and in_longCondition ? last_open_longCondition + tsi : na, "Long Trailing", tsiColor, style=3, linewidth=2)
plot(isTS and in_shortCondition ? last_open_shortCondition - tsi : na, "Short Trailing", tsiColor, style=3, linewidth=2)
plot(isTS and in_longCondition and last_high >= (last_open_longCondition + tsi) ? last_high - ts : na, "Long Trailing", tsColor, style=2, linewidth=2)
plot(isTS and in_shortCondition and last_low <= (last_open_shortCondition - tsi) ? last_low + ts : na, "Short Trailing", tsColor, style=2, linewidth=2)

// 利益確定の設定
////

// 設定
isTP = input(false, "Take Profit")
tp = input(0, "Take Profit") / qty
// シグナル
long_tp = isTP and crossover(high, last_open_longCondition + tp) and longCondition == 0
short_tp = isTP and crossunder(low, last_open_shortCondition - tp) and shortCondition == 0
// 描画
tpColor = isTP and in_longCondition ? purple : isTP and in_shortCondition ? purple : white
plot(isTP and in_longCondition and last_high < last_open_longCondition + tp ? last_open_longCondition + tp : na, "Long TP", tpColor, style=3, linewidth=2)
plot(isTP and in_shortCondition and last_low > last_open_shortCondition - tp ? last_open_shortCondition - tp : na, "Short TP", tpColor, style=3, linewidth=2)

// ロスカットの設定
////

// 設定
isSL = input(false, "Stop Loss")
sl = input(0, "Stop Loss") / qty
// 判断
long_sl = isSL and crossunder(low, last_open_longCondition - sl) and longCondition == 0
short_sl = isSL and crossover(high, last_open_shortCondition + sl) and shortCondition == 0
// 描画
slColor = isSL and in_longCondition and last_low_short > last_open_longCondition - sl ? red : isSL and in_shortCondition and last_high_short < last_open_shortCondition + sl ? red : white
plot(isSL and in_longCondition ? last_open_longCondition - sl : na, "Long SL", slColor, style=3, linewidth=2)
plot(isSL and in_shortCondition ? last_open_shortCondition + sl : na, "Short SL", slColor, style=3, linewidth=2)

// 仮想マージンコール
////

isMargin = input(false, "Margin Call")
leverage = input(1, "Leverage")
long_call = last_open_longCondition - (0.8 + 0.2 * (1/leverage)) / leverage * last_open_longCondition
short_call = last_open_shortCondition + (0.78 + 0.2 * (1/leverage)) / leverage * last_open_shortCondition
long_call_signal = isMargin and crossunder(low, long_call)
short_call_signal = isMargin and crossunder(high, short_call)
marginColor = isMargin and in_longCondition and last_low_short > long_call ? black : isMargin and in_shortCondition and last_high_short < short_call ? black : white
plot(isMargin and in_longCondition ? long_call : na, "Long Margin", marginColor, style=3, linewidth=2)
plot(isMargin and in_shortCondition ? short_call : na, "Short Margin", marginColor, style=3, linewidth=2)

// ポジションの平均価格の算出
////

totalLongs = 0.0
totalLongs := nz (totalLongs[1])
totalShorts = 0.0
totalShorts := nz (totalShorts[1])
averageLongs = 0.0
averageLongs := nz (averageLongs[1])
averageShorts = 0.0
averageShorts := nz (averageShorts[1])

if longCondition
 totalLongs := totalLongs + last_open_longCondition
 totalShorts := 0.0

if shortCondition
 totalLongs := 0.0
 totalShorts := totalShorts + last_open_shortCondition

averageLongs := totalLongs / sectionLongConditions
averageShorts := totalShorts / sectionShortConditions

// 利益・損失幅の描画
longProfit = averageLongs > 0 and close >= averageLongs ? green : red
shortProfit = averageShorts > 0 and close <= averageShorts ? green : red
plot1 = plot(averageLongs > 0 ? averageLongs : na, color=white)
plot2 = plot(close, color=white)
plot3 = plot(averageShorts > 0 ? averageShorts : na, color=white)
fill(plot1, plot2, color=longProfit, transp=50)
fill(plot2, plot3, color=shortProfit, transp=50)




//Enable this to double your order size every time your pyramid on top of an existing position. (Martingale strategy)
// useMartin = input(true, "Martingale")

// longMartin = 0
// longMartin := nz (longMartin[1])
// shortMartin = 0
// shortMartin := nz (shortMartin[1])

// // Check to see if this is our first order, set the order qty to 1
// if longCondition and sectionLongConditions == 1
//  longMartin := longMartin + 1
//  shortMartin := 0
// if shortCondition and sectionShortConditions == 1
//  longMartin := 0
//  shortMartin := shortMartin + 1

// confirm that this order is being added to an existing order
// if longCondition and sectionLongConditions > 1
//  longMartin := longMartin * 2
// if shortCondition and sectionShortConditions > 1
//  shortMartin := shortMartin * 2

// 決済シグナルの判断(利確 or 損切り or トレーリングストップ or 途転)
////

long_close = long_tp or long_sl or long_ts or long_call_signal ? 1 : 0
short_close = short_tp or short_sl or short_ts or short_call_signal ? 1 : 0

// 決済時間の記録
last_long_close = na
last_short_close = na
last_long_close := long_close ? time : nz (last_long_close[1])
last_short_close := short_close ? time : nz (last_short_close[1])

// エントリーと決済の時間を確認
if long_close and last_long_close[1] > last_longCondition
 long_close := 0
if short_close and last_short_close[1] > last_shortCondition
 short_close := 0

// 検証期間内ならトレード
if testPeriod()
 strategy.entry("Long", strategy.long, qty=qty, when=longCondition)
 strategy.entry("Short", strategy.short, qty=qty, when=shortCondition)

 strategy.close("Long", when=long_close)
 strategy.close("Short", when=short_close)
=====
コメント: 次の講座

小次郎講師公式インジケーターのお申込
http://bit.ly/2vdSV4Q

小次郎講師のLINE@
http://bit.ly/2VZQFu3

小次郎講師のチャート情報局
http://bit.ly/2GvLAEp