見出し画像

逆張りナンピンEAをつくる

なんとなくEAを作れるようになったので、今回は練習として「逆張りナンピン」をする。

逆張りナンピン

逆張りは以下の意味で

逆張り(逆バリ)とは、上昇相場のときに売って下落相場のときに買うというような、相場の流れや人気に逆らって売買する投資手法のこと。読みは「ぎゃくばり」。(引用:逆張りとは 意味/解説 - シマウマ用語集

ナンピンは以下の意味

ナンピン(難平)買いとは、保有している銘柄の株価が下がったときに、さらに買い増しをして平均購入単価を下げることです。(引用:ナンピン買い│初めてでもわかりやすい用語集│SMBC日興証券

ナンピンしていって、利益が出たタイミングで利確する。を繰り返すらしい。

どっちのポジションを取るのかをどう考えたら良いのかはわからない。から、ロジックに落とし込む。

ロジック

・15分足で取引を行う。
・EA起動時に、0.001 のロングポジションを取る。
・過去100本の最高価格から最低価格を引いた額を基本価格差とする。
・ロング後、最低価格が基本価格差の5%分の値段が下がる度に、今までロングした分と同じ量ロングする。
・建値から基本価格差の5%分値段が上がると全ポジションを利確する。
・全利確後、0.001 のショートポジションを取る。
・以後、ロング時の逆の考え方でナンピンと利確をする。

基本設定

string          c_symbol; // symbol
ENUM_TIMEFRAMES c_period; // period

int OnInit()
 {
  c_symbol = "USDBTC";
  c_period = PERIOD_M15;
  return(INIT_SUCCEEDED);
 }

ここで、シンボルと足を定義する。

基本価格差を定義

過去の価格を取り出すために、CopyClose を使う。また、それらの価格の最大値は ArrayMaximum 、最小値は ArrayMinimum で算出してくれる。

実装は以下のコード、変数定義を外に出してる部分もあるけど重要な実装はここ。

void update_diff_price()
 {
  if(CopyClose(c_symbol, c_period, 0, 100, close_prices) == -1)
    {
     Print(GetLastError());
     return;
    }
  max_price  = close_prices[ArrayMaximum(close_prices, 0, WHOLE_ARRAY)];
  min_price  = close_prices[ArrayMinimum(close_prices, 0, WHOLE_ARRAY)];
  diff_price = max_price - min_price;
  Print("diff price = ", diff_price);
 }

ランタイムエラーについて

MQL5ではエラーに関してはエラーコードを取得して確認できるみたい。確認するための関数は GetLastError または定数、_LastError でも確認できる。

ほんで、取得したエラーコードの内容は ランタイムエラー で確認できる。

コードレベルの注文と利確部分のロジック

注文と利確部分をコードレベルまで落とし込む。

基本的には注文時にテイクプロフィットをしていするから、自動的に利確される。注文をするべきかどうかを考える関数と、適切な注文をする関数を作る必要がある。

そうなると、注文内容が返ってくる関数がいる。何もしない、ロング、ショートの3種類と注文量、テイクプロフィットの値が返ってくる。

最初のポジションはトレンドなどをもとにロングするか、ショートするかが重要になる。

ナンピンするかどうかは現在の価格が今まで取得したポジションの中で最も高い(低い)ポジションよりも、基本価格差の5%分高い(低い)状態になっているときに注文する。

🤔(となると、そもそも最初にポジション取ったときに指値しておくべきなのではないか?と思ってしまう。ここらへんはトレードの知識がいるから微妙なんか?)

テイクプロフィットはしないことにする。

void OnTick()
 {
  bool shuold_start   = get_shuold_start();
  bool should_average = get_shuold_average();
  bool should_settle  = get_shuold_settle();

  if(!shuold_start)
    {
     start();
     return;
    }

  if(should_average)
    {
     average();
     return;
    }

  if(should_settle)
    {
     should_settle();
     return;
    }
 }

should_* () の実装

void get_shuold_start()
{
  bool shuold_start = !position.Select(c_symbol); // TODO: 
  return shuold_start
}
void get_shuold_average()
 {
  bool should_average = ((
                            current_position_type == POSITION_TYPE_BUY
                            && current_price < last_order_price - diff_price * 0.05
                         ) || (
                            current_position_type == POSITION_TYPE_SELL
                            && current_price > last_order_price + diff_price * 0.05
                         )
                        );

  return should_average;
 }
void get_shuold_settle()
 {
  bool shuold_settle = (
                          (
                             current_position_type == POSITION_TYPE_BUY
                             && current_price >= settle_price
                          ) || (
                             current_position_type == POSITION_TYPE_SELL
                             && current_price <= settle_price
                          )
                       );


  return shuold_settle;
 }

再設計と調査

タイミングをこれで把握したとしても、そのための値を取得しないといけない。グローバル変数に何を持つのかを再設計するために、 Trade\PositionInfo.mqh にどこまで含まれているのかを調べる。

CPositionInfo.SelectByIndex

ポジションを指定することができる。

ポジションをインデックスで選択しプロパティにアクセスします。

PositionsTotal

これ総数取れる

未決済ポジションの数を返します。

最新の注文の情報を取得

上の2つの関数をつかって、For文を回せばいいけど、毎回回すと計算量がふえるからグローバル変数に入れておくことにする。

注文時にその価格とポジションの種別を設定するでいいかな?と考えている。

今回の成果

疲れたので途中で終わり。次回続きを作っていきます。


この記事が気に入ったらサポートをしてみませんか?