グランビルの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() を呼ぶ」制御をしています
処理:
-
currentDate = iTime(Symbol(), PERIOD_D1, 0)
→ 「今日の日足バーの時刻(=今日の日付の基準)」を取得 -
processedDate != currentDateのときだけtrade()実行 -
実行後
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()
買い注文を出す前に「ポジション整理」をします。
処理:
-
すでに買いポジがあれば何もしない(重複エントリー防止)
-
売りポジがあれば全部決済(ドテン)
-
Askで成行買いとしてorder(OP_BUY, Ask)
8) sell()
売り版。やることは buy() と同じ。
処理:
-
すでに売りポジがあれば何もしない
-
買いポジがあれば全部決済
-
Bidで成行売りとしてorder(OP_SELL, Bid)
9) hasBuyPosition() / hasSellPosition()
-
自分(このEA)の保有ポジ(注文)があるか確認するだけの関数
-
内部では
getPositionCount(OP_BUY/OP_SELL)を使う
10) getPositionCount(int orderType)
-
今ある注文(ポジション)一覧
OrdersTotal()を順番にチェックして数える
チェック条件:
-
OrderSelect(...)できないものはスキップ -
OrderMagicNumber() == EA_MAGIC_NOのものだけ対象(このEAの注文だけ) -
OrderType() == orderType(買い/売りの種類が一致) -
合えば
count++
11) closeAllPosition()
-
このEAのポジションを全決済する関数
処理:
-
OrdersTotal()をループ -
OrderSelect→magic一致のものだけ対象 -
orderPriceを-
買いなら
Bid -
売りなら
Ask
にしてOrderClose()実行
-
-
失敗したら Print