2012年04月24日(火)
コピートレードのプログラミング(15) [MQL4]
これまで紹介してきたコピートレードのプログラムでは、コピー元のポジションのロット数がコピー先と全く同じになるようにトレードを行います。
ただ、場合によっては、コピー元の2倍のロット数でコピーしたい場合や、コピー元の半分のロット数にしたい場合などがあると思います。
今回は、コピー元のロット数に対して、コピー先のロット数を一定の倍率で変える場合についてプログラムしてみます。
まずは、その倍率を後から変更できるように
extern double Scaling = 1.0;
のように宣言しておきます。そして、このScalingという変数を
double remote_lots = FileReadNumber(handle) * Scaling;
のようにremote_lotsに掛けてあげます。
簡単な倍率の場合、これだけでもよいのですが、ロット数や倍率が小さい場合、ちょっと問題になることがあります。
例えば、コピー元のロット数が0.05で、倍率を0.7にした場合、コピー先のロット数は0.035となります。
オーダーできる最小ロット数やロット数の刻み幅は業者によって異なるので、ロット数の刻み幅が0.01の業者では、0.035ロットのオーダーを送信するとエラーになってしまいます。
なので、倍率をかけた後に、最小ロット数や刻み幅の条件にマッチするように調整する必要があります。
そこで、オーダーするロット数を調整する関数をAdjustLots()として次のように作成します。
double AdjustLots(double lots)
{
double abslots = MathAbs(lots);
double minlots = MarketInfo(Symbol(), MODE_MINLOT);
double lotstep = MarketInfo(Symbol(), MODE_LOTSTEP);
abslots = MathRound(abslots/lotstep)*lotstep;
if(abslots < minlots) abslots = 0;
if(lots < 0) abslots = -abslots;
return(abslots);
}
簡単に説明すると、まず、パラメータのlotsはプラスの場合とマイナスの場合があるので、abslotsにその絶対値を代入しておきます。
そして、MarketInfo()という関数で、お使いのMT4でオーダーできる最小ロット数をminlotsに、ロットの刻み幅をlotstepに求めます。
次に
abslots = MathRound(abslots/lotstep)*lotstep;
の式でロット数を調整するのですが、わかりやすいように具体的な数値を代入してみましょう。
例えば、abslots=0.042、lotstep=0.01の場合、abslots/lotstep=4.2となり、MathRound(abslots/lotstep)はそれを四捨五入するので4となります。それにlotstep=0.01をかけると、abslots= 0.04となり、刻み幅単位の値になります。
最後にabslotsがminlotsより小さければ0にし、元の符号をつけて返します。
この関数をtrade_lotsを求める式に追加します。
double trade_lots = AdjustLots(remote_lots - local_lots);
これで売買ロット数に端数が出ても、それを補正してオーダーが通るようになります。
全体のプログラムリストを以下に示します。
extern int MAGIC = 9999; // マジックナンバー
extern int Slippage = 2; // スリッページ
extern double Scaling = 1.0; // ロットスケーリング
int start()
{
int handle = FileOpen("Position¥¥"+Symbol()+".txt", FILE_CSV|FILE_READ);
if(handle == -1) return(0);
double remote_lots = FileReadNumber(handle) * Scaling;
FileClose(handle);
double local_lots = OpenLots();
if(IsTradeAllowed() == false) return(1);
double slippage = Slippage;
if(Digits == 3 || Digits == 5) slippage *= 10;
// 決済オーダー
if(local_lots != 0 && (remote_lots == 0 || remote_lots*local_lots < 0))
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS) == false ) break;
if(OrderSymbol() != Symbol() || OrderMagicNumber() != MAGIC) continue;
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
{
OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), slippage);
}
}
return(0);
}
// 部分決済オーダー
double trade_lots = AdjustLots(remote_lots - local_lots);
if(remote_lots*local_lots > 0 && local_lots*trade_lots < 0)
{
for(i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS) == false ) break;
if(OrderSymbol() != Symbol() || OrderMagicNumber() != MAGIC) continue;
if(OrderType() == OP_BUY || OrderType() == OP_SELL)
{
double close_lots = MathMin(OrderLots(), MathAbs(trade_lots));
OrderClose(OrderTicket(), close_lots, OrderClosePrice(), slippage);
return(0);
}
}
}
//売買オーダー
if(trade_lots > 0)
{
int ticket=OrderSend(Symbol(),OP_BUY,trade_lots,Ask,slippage,0,0,"",MAGIC);
}
if(trade_lots < 0)
{
ticket=OrderSend(Symbol(),OP_SELL,-trade_lots,Bid,slippage,0,0,"",MAGIC);
}
return(0);
}
// オープンロット数
double OpenLots()
{
double lots = 0.0;
for(int i=0; i<OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS) == false) break;
if(OrderSymbol() != Symbol() || OrderMagicNumber() != MAGIC) continue;
if(OrderType() == OP_BUY) lots += OrderLots();
if(OrderType() == OP_SELL) lots -= OrderLots();
}
return(lots);
}
// ロット数の補正
double AdjustLots(double lots)
{
double abslots = MathAbs(lots);
double minlots = MarketInfo(Symbol(), MODE_MINLOT);
double lotstep = MarketInfo(Symbol(), MODE_LOTSTEP);
abslots = MathRound(abslots/lotstep)*lotstep;
if(abslots < minlots) abslots = 0;
if(lots < 0) abslots = -abslots;
return(abslots);
}
ロット数補正の部分には、最大ロット数のチェックなども必要かもしれませんが、必要に応じて各自で追加してみてください。
以上でコピートレードのプログラミングの話は終わりにします。
次のネタは・・・これから考えます。
Posted at 10時14分