前回までには戦略を明文化することろまで行きました。
今回は、この戦略を実際にコード化するところまでを公開していきいます。
戦略の概要をおさらい
今回作成するトレード戦略の概要をもう一度おさらいしておきます。
【仕掛けルール】
X日間の高値の最大値をY時間足の実体で更新したらロング
X日間の安値の最小値をY時間足の実体で更新したらショート
最適化対象パラメータ:X、Y
ただし、パラメータYは多期間多市場テストの一環で堅牢性を確かめるとともに、最適化するものとする。
【手仕舞いルール】
ドテン戦略
戦略のコード化 ver1
#property strict
//--- input parameters
input int slippage=10;
input int day_count=3;//X日間の最高値/最安値
extern int magicnumber=123;
//input int time_frame;//Y時間足 多市場多期間テストで最適化→手動で調整
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
/*-----------------------------------------------------------------------------------
【仕掛けルール】
X日間の高値の最大値をY時間足の実体で更新したらロング
X日間の安値の最小値をY時間足の実体で更新したらショート
最適化対象パラメータ:
X→day_count
ただし、パラメータYは多期間多市場テストの一環で堅牢性を確かめるとともに、最適化するものとする。
【手仕舞いルール】
ドテン
ただしデイトレード戦略を保ちたいので、ロンドン時間の引けと同時に手仕舞い←これは後回し
-------------------------------------------------------------------------------------*/
void OnTick()
{
int Index_high=iHighest(NULL,0,MODE_HIGH,day_count,1);//ひとつ前の足から、day_count本前までの中での高値を抽出
int Index_low=iLowest(NULL,0,MODE_LOW,day_count,1);//ひとつ前の足から、day_count本前までの中での最安を抽出
double close=iClose(NULL,0,0);//最新の終値を参照
double highest=High[Index_high];//抽出した高値の中から、最高値を選ぶ
double lowest=Low[Index_low];//抽出した安値の中から、最安値を選ぶ
if((close < lowest) && OrdersTotal()==1)close_sell();//ショート手仕舞いの条件 ドテン
if((close > highest)&& OrdersTotal()==1)close_buy();//ロング手仕舞いの条件 ドテン
if((close > highest) && OrdersTotal()==0)//ロングの条件
{
printf("ロング");
OrderSend(Symbol(),OP_BUY,1,Ask,slippage,0,0,NULL,magicnumber,0,clrRed);//損切り、利確:指定なし,lot:1
}
if((close < lowest) && OrdersTotal()==0)//ショートの条件
{
printf("ショート");
OrderSend(Symbol(),OP_SELL,1,Bid,slippage,0,0,NULL,magicnumber,0,clrBlue);//損切り、利確:指定なし,lot:1
}
Comment(day_count+1,"期間の最高値は",highest,"|",
day_count+1,"期間の最安値は",lowest);
//---
}
void close_buy()
{
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)break;
if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magicnumber)continue;
if(OrderType()==OP_BUY)OrderClose(i,OrderLots(),Bid,slippage,clrRed);
}
}
void close_sell()
{
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)break;
if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magicnumber)continue;
if(OrderType()==OP_SELL)OrderClose(i,OrderLots(),Ask,slippage,clrBlue);
}
}
最初にこのようにコードを組み、無事コンパイルできたのですが、注文が一つしか実行されないという問題が発生しました。
原因がよくわからなかったので、今流行りのChatgptに訂正してもらいました。まじで便利な時代になりましたね。
コードの最終版
input int slippage = 10;
input int day_count = 3;
extern int magicnumber = 123;
int currentTradeType = -1; // -1: 保有ポジションなし, 0: ロングポジション, 1: ショートポジション
void OnTick()
{
double highest = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, day_count, 1));
double lowest = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, day_count, 1));
double close = iClose(NULL, 0, 0);
if (currentTradeType == 0 && close < lowest)
close_long(); // ロング手仕舞いの条件 ドテン
else if (currentTradeType == 1 && close > highest)
close_short(); // ショート手仕舞いの条件 ドテン
else if (currentTradeType == -1 && close > highest) // ロングの条件
{
printf("ロング");
OrderSend(Symbol(), OP_BUY, 1, Ask, slippage, 0, 0, NULL, magicnumber, 0, clrRed);
currentTradeType = 0; // ロングポジションをトラッキング
}
else if (currentTradeType == -1 && close < lowest) // ショートの条件
{
printf("ショート");
OrderSend(Symbol(), OP_SELL, 1, Bid, slippage, 0, 0, NULL, magicnumber, 0, clrBlue);
currentTradeType = 1; // ショートポジションをトラッキング
}
Comment(day_count + 1, "期間の最高値は", highest, "|",
day_count + 1, "期間の最安値は", lowest);
}
void close_long()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false)
break;
if (OrderSymbol() != Symbol() || OrderMagicNumber() != magicnumber)
continue;
if (OrderType() == OP_BUY)
{
double lots = OrderLots();
OrderClose(OrderTicket(), lots, Bid, slippage, clrRed);
currentTradeType = -1; // 保有ポジションなしにリセット
}
}
}
void close_short()
{
for (int i = 0; i < OrdersTotal(); i++)
{
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false)
break;
if (OrderSymbol() != Symbol() || OrderMagicNumber() != magicnumber)
continue;
if (OrderType() == OP_SELL)
{
double lots = OrderLots();
OrderClose(OrderTicket(), lots, Ask, slippage, clrBlue);
currentTradeType = -1; // 保有ポジションなしにリセット
}
}
}
実際に、MT4でバックテストしてみると、以上のようにしっかり機能していることが分かります。
次回は最適化の作業を行っていきたいとおもいます。