見出し画像

モンテカルロ法の計算方法MQL4、PineScript

モンテカルロ法っていうのがあって計算は簡単だけど、紙に都度メモる必要があるのでとても面倒くさい方法です。

ベラジョンから引用します。

まずはモンテカルロ法のルールをご紹介。3つの数字からスタート
数列の数字は1ユニットを表す
数列の数字が1つか0になれば1サイクル終了


モンテカルロ法を配当2倍のゲームでシミュレーション

モンテカルロ法を配当2倍のゲームに応用する場合のステップです。

ステップ1 ★3つの数字を紙に書く

ステップ2 ★数列にある3つの数字の両端を足した合計数 (ベット額) が最初の賭け額になる

負けた場合

ステップ3★ベット額の数字を数列の右端に書く

勝った場合

ステップ3★数列の両端の数字を1つずつ消す

この後は、ステップ2に戻って、数列にある数字の両端を足した合計数 (ベット額) を計算し、1サイクルが終わるまで繰り返すだけ!

シミュレーションにて流れをチェックしていきましょう。

※1ユニット=$1とする数字を3つ紙に書く
⇒「1・2・3」
数列の両端を足した数字を賭ける
⇒「1 + 3 = 4」なので、$4を賭ける
負けたので、数列の右端にベット額の数字を書く
⇒「1・2・3・4」
数列の両端を足した数字を賭ける
⇒「1 + 4 = 5」なので、$5を賭ける
勝ったので、数列の両端の数字を1つずつ消す
⇒「1・2・3・4」が「2・3」になる
数列の両端を足した数字を賭ける
⇒「2 + 3 = 5」なので、$5を賭ける
勝ったので、数列の両端の数字を1つずつ消すと、もともとの2つの数字がなくなったので、ここで1サイクル終了、となります


配当2倍のゲームでは、勝率も約50%と勝つ可能性も理論的に高めなので、1サイクルが早く終わることが多めです。

しかし、負けが何回か続くと連勝しないと利益が出ない場合もあります。

いちいち紙にメモは面倒くさいのでギャンブラーみたいな単細胞には向いてないです。

そこでプログラミングで自動計算するので冷静にモンテカルロ法が使えます。

半裁量EA ELDRAでバックテスト


モンテカルロ法はRR比率が固定されている場合に有効なので、それ以外はなんかがおかしいかも。



Pine Script

//@version=5
strategy('[ホソノP]ASCTrendでエントリー(モンテカルロ法or固定ロット数)', overlay=true, default_qty_type=strategy.cash, default_qty_value=1000)

// Inputs for ASC Trend
eternalfg = input(false, title='eternal 確定')
eternal = eternalfg ? 1 : 0
ASClength = input.int(title='ASC Length', minval=4, defval=10)
RISK = input.int(title='RISK', minval=0, defval=3)

// Inputs for Blackflag FTS
trailType = input.string('modified', 'Trailtype', options=['modified', 'unmodified'])
ATRPeriod = input(28, 'ATR Period')
ATRFactor = input(5, 'ATR Factor')

// ロットサイズ設定のための新しい入力
lotSizeMethod = input.string("Fixed", title="ロットサイズ方式", options=["Fixed", "MonteCarlo"])
fixedLotSize = input.float(0.01, "固定ロットサイズ", minval=0.01, step=0.01)
initialLotSize = input.float(0.01, "モンテカルロ初期ロットサイズ", minval=0.01, step=0.01)
maxSequenceSize = input.int(100, "最大数列サイズ", minval=3)

// ASC Trend Calculations
x1 = 67 + RISK
x2 = 33 - RISK
Range = ta.highest(ASClength) - ta.lowest(ASClength)
AvgRange = ta.sma(Range, ASClength)
CountFg = math.abs(open - close) >= AvgRange * 2.0 ? 1 : 0
TrueCount = math.sum(CountFg, ASClength)
CountFg2 = math.abs(close[3] - close) >= AvgRange * 4.6 ? 1 : 0
TrueCount2 = math.sum(CountFg2, ASClength - 3)
wpr3RR = ta.wpr(3 + RISK + RISK)
wpr3 = ta.wpr(3)
wpr4 = ta.wpr(4)
WprAbs = 100 + (TrueCount2 > 0 ? wpr4 : TrueCount > 0 ? wpr3 : wpr3RR)
ASC_Trend = 0
ASC_Trend := WprAbs[eternal] < x2[eternal] ? -1 : WprAbs[eternal] > x1[eternal] ? 1 : ASC_Trend[1]

// Blackflag FTS Calculations
norm_o = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, open)
norm_h = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, high)
norm_l = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, low)
norm_c = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, close)

Wild_ma(_src, _malength) =>
    _wild = 0.0
    _wild := nz(_wild[1]) + (_src - nz(_wild[1])) / _malength
    _wild

HiLo = math.min(norm_h - norm_l, 1.5 * nz(ta.sma(norm_h - norm_l, ATRPeriod)))
HRef = norm_l <= norm_h[1] ? norm_h - norm_c[1] : norm_h - norm_c[1] - 0.5 * (norm_l - norm_h[1])
LRef = norm_h >= norm_l[1] ? norm_c[1] - norm_l : norm_c[1] - norm_l - 0.5 * (norm_l[1] - norm_h)
trueRange = trailType == 'modified' ? math.max(HiLo, HRef, LRef) : math.max(norm_h - norm_l, math.abs(norm_h - norm_c[1]), math.abs(norm_l - norm_c[1]))
loss = ATRFactor * Wild_ma(trueRange, ATRPeriod)
Up = norm_c - loss
Dn = norm_c + loss
TrendUp = Up
TrendDown = Dn
Trend = 1
TrendUp := norm_c[1] > TrendUp[1] ? math.max(Up, TrendUp[1]) : Up
TrendDown := norm_c[1] < TrendDown[1] ? math.min(Dn, TrendDown[1]) : Dn
Trend := norm_c > TrendDown[1] ? 1 : norm_c < TrendUp[1] ? -1 : nz(Trend[1], 1)
trail = Trend == 1 ? TrendUp : TrendDown

macdLine = ta.ema(close, 12) - ta.ema(close, 26)
signalLine = ta.ema(macdLine, 9)
histogram = macdLine - signalLine
sb = histogram // This is your Impulse MACD histogram value

// Define the threshold for the Impulse MACD signal (sikiti)
sikiti = input(0.02, title='Impulse MACD Threshold')

// Combine all conditions and plot the buy/sell signals
ConditionForSignal = sb <= sikiti and sb >= -sikiti
// Signal conditions
longCondition = ta.crossover(ASC_Trend, 0) and Trend == 1 and not ConditionForSignal
shortCondition = ta.crossunder(ASC_Trend, 0) and Trend == -1 and not ConditionForSignal

// Calculate stop loss and take profit levels
stopLossLong = low[1]
takeProfitLong = close + (close - stopLossLong) * 1

stopLossShort = high[1]
takeProfitShort = close - (stopLossShort - close) * 1


// モンテカルロ法のためのグローバル変数
var float[] sequence = array.new_float(3, 1.0)  // 初期数列 [1, 2, 3]
var int sequenceSize = 3
var int lastOrderId = 0
var float currentLotSize = initialLotSize * 10000  // 初期ロットサイズに10000を掛ける

// 現在の取引ID(バーのインデックス)を取得
currentOrderId = bar_index

if (strategy.closedtrades > 0)
    currentOrderId := strategy.closedtrades.exit_bar_index(strategy.closedtrades - 1)

// モンテカルロ法でロットサイズを計算
if (lotSizeMethod == "MonteCarlo" and currentOrderId > lastOrderId)
    lastOrderId := currentOrderId
    isWin = strategy.closedtrades.profit(strategy.closedtrades - 1) > 0
    
    if isWin
        // 勝った場合、数列の両端を削除
        if sequenceSize > 2
            array.shift(sequence)
            array.pop(sequence)
            sequenceSize := sequenceSize - 2
        else
            // 数列が空になったら初期化
            array.clear(sequence)
            array.push(sequence, 1.0)
            array.push(sequence, 2.0)
            array.push(sequence, 3.0)
            sequenceSize := 3
    else
        // 負けた場合、ベット額を数列の最後に追加
        if sequenceSize < maxSequenceSize
            array.push(sequence, currentLotSize / (initialLotSize * 10000))
            sequenceSize := sequenceSize + 1

    // 新しいロットサイズを計算
    currentLotSize := (array.get(sequence, 0) + array.get(sequence, sequenceSize - 1)) * initialLotSize * 10000

// 固定ロットサイズの場合
if (lotSizeMethod == "Fixed")
    currentLotSize := fixedLotSize * 10000

// デバッグ情報の出力
if (lotSizeMethod == "MonteCarlo")
    sequenceStr = array.join(sequence, ",")
    label.new(bar_index, high, text="Lot Size: " + str.tostring(currentLotSize, "#.##") + " Sequence: " + sequenceStr)
else
    label.new(bar_index, high, text="Fixed Lot Size: " + str.tostring(currentLotSize, "#.##"))

// 戦略の実行
if (longCondition)
    strategy.entry("Long", strategy.long, qty=currentLotSize / close)
    strategy.exit("Take Profit Long", "Long", limit=takeProfitLong, stop=stopLossLong)

if (shortCondition)
    strategy.entry("Short", strategy.short, qty=currentLotSize / close)
    strategy.exit("Take Profit Short", "Short", limit=takeProfitShort, stop=stopLossShort)

MQL4

double CalculateMonteCarloLotSize()
{
    static double sequence[100] = {1, 2, 3}; // 初期数列
    static int sequenceSize = 3;          // 初期数列の長さ
    static bool isInitialized = false;    // 初期化フラグ
    static int lastOrderTicket = 0;       // 最後に処理した注文のチケット番号

    // 初期化(EA起動時に一度だけ実行)
    if (!isInitialized)
    {
        InitializeFromHistory(sequence, sequenceSize);
        isInitialized = true;
    }

    // ロットサイズの計算
    double lotSize = (sequence[0] + sequence[sequenceSize - 1]) * InitialLotSize;

    // 直前の取引結果の処理
    if (OrdersHistoryTotal() > 0)
    {
        for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
        {
            if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) &&
                OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber &&
                OrderTicket() > lastOrderTicket)
            {
                lastOrderTicket = OrderTicket();
                bool isWin = (OrderProfit() > 0);
                if (isWin)
                {
                    // 勝った場合、数列の両端を削除
                    if (sequenceSize > 2)
                    {
                        for (int j = 0; j < sequenceSize - 2; j++)
                        {
                            sequence[j] = sequence[j + 1];
                        }
                        sequenceSize -= 2;
                    }
                    else
                    {
                        // 数列が空になったら終了
                        sequenceSize = 0;
                    }
                }
                else
                {
                    // 負けた場合、ベット額を数列の最後に追加
                    if (sequenceSize < ArraySize(sequence))
                    {
                        sequence[sequenceSize] = lotSize / InitialLotSize; // ベット額を数列に追加
                        sequenceSize++;
                    }
                }
                break; // 最新の取引のみを処理
            }
        }
    }

    // デバッグ情報の出力
    string sequenceStr = "";
    for (int i = 0; i < sequenceSize; i++)
    {
        sequenceStr += DoubleToString(sequence[i], 2);
        if (i < sequenceSize - 1) sequenceStr += ",";
    }
    Print("Lot Size: ", DoubleToString(lotSize, 2), " Sequence: ", sequenceStr);

    if (sequenceSize == 0)
    {
        // 数列が空になったら初期化
        sequence[0] = 1;
        sequence[1] = 2;
        sequence[2] = 3;
        sequenceSize = 3;
    }

    return NormalizeDouble(lotSize, 2);
}


// TradeHistoryから初期状態を設定
void InitializeFromHistory(double &sequence[], int &sequenceSize)
{
    int historyCount = 0;
    sequenceSize = 3;
    sequence[0] = 1;
    sequence[1] = 2;
    sequence[2] = 3;
    
    for (int i = OrdersHistoryTotal() - 1; i >= 0; i--)
    {
        if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) &&
            OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
        {
            historyCount++;
            bool isWin = (OrderProfit() > 0);
            double usedLotSize = OrderLots() / InitialLotSize;
            
            if (isWin)
            {
                if (sequenceSize > 2)
                {
                    for (int j = 0; j < sequenceSize - 2; j++)
                    {
                        sequence[j] = sequence[j + 1];
                    }
                    sequenceSize -= 2;
                }
                else
                {
                    sequenceSize = 0;
                }
            }
            else
            {
                if (sequenceSize < ArraySize(sequence))
                {
                    sequence[sequenceSize] = usedLotSize;
                    sequenceSize++;
                }
            }
            
            if (sequenceSize == 0)
            {
                sequence[0] = 1;
                sequence[1] = 2;
                sequence[2] = 3;
                sequenceSize = 3;
            }
            
            // 最新の20取引まで遡る
            if (historyCount >= 20) break;
        }
    }
}





ここから先は

0字
このマガジンで読み放題です。

EA開発者のためのサンプルコード集

よろしければサポートお願いします! いただいたサポートはクリエイターとしての活動費に使わせていただきます!