グランビルの8法則のうち以下の条件を載せる

❶移動平均線が長期下落の後、株価がこの移動平均線を上抜いたとき

❺移動平均線が長期上昇の後、株価がこの移動平均線を下回ったとき

 

1日1回だけ、日足の25日移動平均線(SMA)が10日間ずっと同じ向きかをチェックして、条件を満たしたら前日足の位置で売買する」ロジック

全体のロジック(何をしたいEAか)

① 1日1回だけ判定する

  • Tick(価格更新)のたびに毎回売買判断すると、同じ日に何度も発注してしまう可能性がある
    → それを防ぐために「今日まだ処理してないなら1回だけ実行」します。

② 25日移動平均線(SMA)の向きを10日分チェック

  • iMA(..., PERIOD_D1, 25, ..., i) を i=0〜9 で取り、過去10日分の25MA を配列に入れる

  • その10日分が

    • ずっと上昇方向(単調増加)

    • もしくは ずっと下降方向(単調減少)
      でないと「トレンドなし」として売買しない

※「途中で1日でも崩れたら、上昇/下降トレンドとみなさない」という厳しめ条件。

③ 前日足がMAの上か下かで売買

  • 上昇トレンド(isRise=true) かつ 前日足がMAより上にある(始値も終値もMAより上)
    buy()(買い)

  • 下降トレンド(isFall=true) かつ 前日足がMAより下にある(始値も終値もMAより下)
    sell()(売り)


各関数が何をしているか

1) グローバル変数・定数

EA_MAGIC_NO

  • このEAが出した注文だけを識別するための番号(マジックナンバー)

  • 他のEA/手動注文と区別するのに使う

VOLUME

  • ロット固定(0.1)

processedDate

  • 「最後に処理した日付」を持っておく変数

  • 初期値は iTime(..., D1, 1) なので「前日の日付」

    • これにより、稼働初日に 今日の処理を1回だけ させやすい


2) OnInit()

  • EA起動時に1回だけ呼ばれる初期化関数

  • このコードでは特に準備はせず、成功として終わるだけ


3) OnDeinit(const int reason)

  • EA停止時に呼ばれる

  • 今回は中身なし(後片付けなし)


4) OnTick()

  • 価格が更新されるたびに呼ばれる(めちゃくちゃ頻繁)

  • ここで「1日1回だけ trade() を呼ぶ」制御をしています

処理:

  1. currentDate = iTime(Symbol(), PERIOD_D1, 0)
    → 「今日の日足バーの時刻(=今日の日付の基準)」を取得

  2. processedDate != currentDate のときだけ trade() 実行

  3. 実行後 processedDate = currentDate で「今日処理済み」に更新


5) trade()

売買判断の本体。やっていることは3段階です。

(A) 10日分の25MAを配列に入れる

  • maArray[0..9]iMA(..., i) を入れる

    • i=0 は「直近(今日側)のMA」

    • i=1 は「1本前(前日側)のMA」

    • …という並び

(B) MAが10日間ずっと上昇/下降か判定

  • isRise=true, isFall=true で開始

  • 9回比較して、矛盾したら false にする

判定ロジック(コードの意味):

  • maArray[i] < maArray[i+1] なら
    「今日側のMAが小さく、過去側が大きい」= 右肩下がり方向
    → 上昇ではないので isRise=false

  • maArray[i] > maArray[i+1] なら
    右肩上がり方向
    → 下降ではないので isFall=false

※ここは「配列の並び(i=0が最新)」の関係で、比較が少しややこしいです。

(C) 前日足の位置で売買

  • openPrice = iOpen(...,1) 前日の始値

  • closePrice = iClose(...,1) 前日の終値

売買条件:

  • isRise(上昇トレンド) かつ
    openPrice > maArray[0] && closePrice > maArray[0](前日足がMAより上)
    buy()

  • isFall(下降トレンド) かつ
    openPrice < maArray[0] && closePrice < maArray[0](前日足がMAより下)
    sell()


6) order(int cmd, double orderPrice)

  • 実際に発注する共通関数

  • OrderSend() を呼んで注文を出す

  • 失敗したら ticketNo == -1 なので Printでエラーログを出す

主な設定:

  • volume:固定ロット

  • slippage:100(ブローカー仕様によって影響)

  • stopLoss/takeProfit:0(設定なし)

  • comment:NULL

  • magic:EA_MAGIC_NO


7) buy()

買い注文を出す前に「ポジション整理」をします。

処理:

  1. すでに買いポジがあれば何もしない(重複エントリー防止)

  2. 売りポジがあれば全部決済(ドテン)

  3. Ask で成行買いとして order(OP_BUY, Ask)


8) sell()

売り版。やることは buy() と同じ。

処理:

  1. すでに売りポジがあれば何もしない

  2. 買いポジがあれば全部決済

  3. Bid で成行売りとして order(OP_SELL, Bid)


9) hasBuyPosition() / hasSellPosition()

  • 自分(このEA)の保有ポジ(注文)があるか確認するだけの関数

  • 内部では getPositionCount(OP_BUY/OP_SELL) を使う


10) getPositionCount(int orderType)

  • 今ある注文(ポジション)一覧 OrdersTotal() を順番にチェックして数える

チェック条件:

  1. OrderSelect(...) できないものはスキップ

  2. OrderMagicNumber() == EA_MAGIC_NO のものだけ対象(このEAの注文だけ)

  3. OrderType() == orderType(買い/売りの種類が一致)

  4. 合えば count++


11) closeAllPosition()

  • このEAのポジションを全決済する関数

処理:

  1. OrdersTotal() をループ

  2. OrderSelectmagic一致 のものだけ対象

  3. orderPrice

    • 買いなら Bid

    • 売りなら Ask
      にして OrderClose() 実行

  4. 失敗したら Print