ハイローバイナリーのシステムトレード過去検証[MA,RSI,リバウンド]
バイナリーオプションの場合、リアルタイムの自動売買開発と過去検証のためのソフト開発は別物です。
自動売買はこちら
バイナリーオプションの自動売買を開発するやり方
過去検証の方がはるかに簡単なので、バイナリーオプション用のトレード手法はあるけどバックテストのやり方がわからない、という人向けに考察します。
バイナリーオプションは中身はFXなので、基本的にはMT4/MT5, jForex, cTrader, TradeStation, NinjaTraderなんでもいいですが、FX系のソフトでテスト可能です。
自動売買が禁止されているバイナリーオプション業者でも、システムを使って過去検証を行い手動で売買する分には問題ないので、バックテストをやらない理由がありません。
バイナリーオプションで過去検証する方法
最も基本的なバイナリーオプションの事例を考えます。
仮に、
- 5分おきに判定時刻があり、
- 1分前にプット/コールができなくなり
- ペイアウトが1.8
のオプションの場合、
- 分(Minute())が5で割り切れるときに決済。(足の更新のタイミング)
- 分(Minute())を5で割って、4余るときにはエントリー不可
- 最終的な勝率に対して1.8を掛ける
これだけで、バイナリーオプションでその手法が勝てるのかどうかテストすることができます。
※現在ハイローオーストラリアでは5分のモードはなくなっています。
上がるか下がるかだけなので、スリップ、スプレッド、約定拒否などは考えなくていいです。
FXのプログラミングをしたことがある方からすれば考慮するべき項目が激減するので超かんたんです。
ただし、バックテストするときには、スプレッドを可能な限り0に近づけます。
(MT4の場合1pointが限界です。)
ゴールデンクロス/デッドクロスでプログラミング
試しに、ゴールデンクロス、デッドクロスでプログラミングを組んでみましょう。
1分足で14単純移動平均線と28単純移動平均線のクロスのプログラムを組みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
double FastMA[3],SlowMA[3]; FastMA[1] = iMA(Symbol(),Period(),14,0,MODE_SMA,PRICE_CLOSE,1); FastMA[2] = iMA(Symbol(),Period(),14,0,MODE_SMA,PRICE_CLOSE,2); SlowMA[1] = iMA(Symbol(),Period(),28,0,MODE_SMA,PRICE_CLOSE,1); SlowMA[2] = iMA(Symbol(),Period(),28,0,MODE_SMA,PRICE_CLOSE,2); if( OrdersTotal() == 0 ) { if( Minute()%5 != 4 ) { if( FastMA[1] > SlowMA[1] && FastMA[2] <= SlowMA[2] ) { int T = OrderSend(Symbol(),OP_BUY,0.01,Ask,1,0,0,"",0,0,clrRed); } else if( FastMA[1] < SlowMA[1] && FastMA[2] >= SlowMA[2] ) { int T = OrderSend(Symbol(),OP_SELL,0.01,Bid,1,0,0,"",0,0,clrBlue); } } } |
「形成中の足でエントリーの判定を行うと、ダマシにあいやすい」というのが最近のセオリーになりつつあるので、確定足でエントリー条件を判定します。
バックテストのみで実際にリアルタイムでトレードさせる訳ではないので、スリッページやAsk,Bidなどはフェイルセイフ機能がない記述でもOKです。また、分を5で割って余りが4になるときはプットもコールもできないので、エントリーしないようにします。
次に、決済処理です。
|
Bar[1] = Bar[0]; Bar[0] = Bars; int OrdersTotal_ = OrdersTotal(); for( int i=0;i<OrdersTotal_;i++) { if( Minute()%5 == 0 && Bar[1] != Bar[0]) { bool R =OrderSelect(i,SELECT_BY_POS,MODE_TRADES); //exit if( OrderType() == OP_BUY ) R = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrYellow); if( OrderType() == OP_SELL ) R = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrYellow); } } |
バイナリーオプションの決済は5で割り切れる分の初めで行われます。
そのため、この時間になったら強制的に決済するように記述するだけです。
実際にソフト(MT4)を動かしてハイローバイナリー過去検証
これまで何度もやっているので、特に解説する必要はないと思います。
これでバックテストします。
モデリング品質が25%なのは、普段からMT4を触っていないのでデータがないということと
そもそも1分足なので本来はノイズが入りまくるということがあります。(つーか、これが限界)
トレード回数は46回で、勝ち回数25回なので、
毎回1000円ベットしたとすると、
投資コスト:46×1,000円=46,000円
リターン:25×1,000円x1.8=4,5000円
差額-1,000円
つまり、負けるってことですね。
実際には、スプレッド1ポイント分で負けなかった可能性もあるので、それも含めるとトントンといったところでしょうか。
ヒストリカルデータも完璧ではないので”ざっくり”としたデータであることは否めません。
(逆に、誤差の範囲でないと証明することもできませんが)
また、現実においては、
が影響するので、
一概に「このトレード手法はダメ、このトレード手法は勝てる!」と決定づけることはできません。
しかし、プレゼンするには良い資料になるかもしれないですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ static int Bar[2]; void OnTick() { //--- Bar[1] = Bar[0]; Bar[0] = Bars; int OrdersTotal_ = OrdersTotal(); for( int i=0;i<OrdersTotal_;i++) { if( Minute()%5 == 0 && Bar[1] != Bar[0]) { bool R =OrderSelect(i,SELECT_BY_POS,MODE_TRADES); //exit if( OrderType() == OP_BUY ) R = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrYellow); if( OrderType() == OP_SELL ) R = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrYellow); } } double FastMA[3],SlowMA[3]; FastMA[1] = iMA(Symbol(),Period(),14,0,MODE_SMA,PRICE_CLOSE,1); FastMA[2] = iMA(Symbol(),Period(),14,0,MODE_SMA,PRICE_CLOSE,2); SlowMA[1] = iMA(Symbol(),Period(),28,0,MODE_SMA,PRICE_CLOSE,1); SlowMA[2] = iMA(Symbol(),Period(),28,0,MODE_SMA,PRICE_CLOSE,2); if( OrdersTotal() == 0 ) { if( Minute()%5 != 4 ) { if( FastMA[1] > SlowMA[1] && FastMA[2] <= SlowMA[2] ) { int T = OrderSend(Symbol(),OP_BUY,0.01,Ask,1,0,0,"",0,0,clrRed); } else if( FastMA[1] < SlowMA[1] && FastMA[2] >= SlowMA[2] ) { int T = OrderSend(Symbol(),OP_SELL,0.01,Bid,1,0,0,"",0,0,clrBlue); } } } } //+---------- |
MT5ならリアルティックに基づいたバックテストが可能
MT4でバックテストすると、1分足未満のデータは疑似生成ティックになってしまいます。そのため、5分単位で勝ち負けが決まるような期間の短いバイナリーオプションでは正確な過去検証を行うことができません。
しかし、MT5であればより細かいヒストリーデータに基づいたリアルティックに基づいたバックテストが可能です。
MT5でコーディング
先ほどのMT4版をMT5版に書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
#include <Trade\Trade.mqh> CTrade m_trade; input uint ShortMASpan = 14; input uint LongMASpan = 28; input double Lot = 0.1; static int Slippage_in_point = 3; enum FillingType{ FOK = ORDER_FILLING_FOK, IOC = ORDER_FILLING_IOC, Return = ORDER_FILLING_RETURN }; input FillingType FillingMode; static int FillingMode_; bool R; static int Bar[2]; static double FastMA[], SlowMA[]; int OnInit() { if( FillingMode == ORDER_FILLING_FOK ) FillingMode_ = ORDER_FILLING_FOK; else if( FillingMode == ORDER_FILLING_IOC ) FillingMode_ = ORDER_FILLING_IOC; else if( FillingMode == ORDER_FILLING_RETURN ) FillingMode_ = ORDER_FILLING_RETURN; return(INIT_SUCCEEDED); } void OnTick() { //--- MqlDateTime DateTime; TimeToStruct(TimeCurrent(),DateTime); Bar[1] = Bar[0]; Bar[0] = Bars(_Symbol,_Period); int SMAHandle, LMAHandle; SMAHandle = iMA(_Symbol,0,ShortMASpan,0,MODE_SMA,PRICE_CLOSE); LMAHandle = iMA(_Symbol,0,LongMASpan,0,MODE_SMA,PRICE_CLOSE); ArraySetAsSeries( FastMA,true ); ArraySetAsSeries( SlowMA,true ); CopyBuffer( SMAHandle,0,0,3,FastMA ); CopyBuffer( LMAHandle,0,0,3,SlowMA ); //Exit int OrdersTotal_ = PositionsTotal(); for(int i=0; i<OrdersTotal_;i++) { if( PositionGetTicket(i)>0 ) { if( DateTime.min%5 == 0 && Bar[1] != Bar[0] ) { OrderClose(PositionGetTicket(i)); } } } if( PositionsTotal() == 0 ) { if( DateTime.min%5 != 4 ) { if( FastMA[1] > SlowMA[1] && FastMA[2] <= SlowMA[2] ) { OrderSending(0); } else if( FastMA[1] < SlowMA[1] && FastMA[2] >= SlowMA[2] ) { OrderSending(1); } } } } void OrderSending(int Direction) { MqlTradeRequest TRequest; MqlTradeResult TResult; ZeroMemory(TRequest); ZeroMemory(TResult); if( Direction == 0 ) { TRequest.type = ORDER_TYPE_BUY; TRequest.price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); } else if( Direction == 1 ) { TRequest.type = ORDER_TYPE_SELL; TRequest.price = SymbolInfoDouble(_Symbol,SYMBOL_BID); } TRequest.volume = Lot; TRequest.action = TRADE_ACTION_DEAL; TRequest.symbol = _Symbol; TRequest.magic = 1111; TRequest.comment = ""; TRequest.deviation = Slippage_in_point; TRequest.type_filling = FillingMode_; R = OrderSend(TRequest,TResult); if( !R ) Print("OrderSend for Open was rejected"); //we should check the return just in case. } void OrderClose(int Ticket) { MqlTradeRequest CRequest; MqlTradeResult CResult; ZeroMemory(CRequest); ZeroMemory(CResult); //ネッティングタイプの場合(ポジションが合体させられる場合)------------------------------------------------------------ if( AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_NETTING ) { //そのポジションと逆向きに同じ量の反対ポジションをとる R = PositionSelectByTicket(Ticket); if( PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ) { CRequest.type = ORDER_TYPE_SELL; CRequest.price = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL),SYMBOL_BID); Print("Order close Bid is "+CRequest.price); } else if( PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL ) { CRequest.type = ORDER_TYPE_BUY; CRequest.price = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL),SYMBOL_ASK); Print("Order close Ask is "+CRequest.price); } CRequest.action = TRADE_ACTION_DEAL; CRequest.symbol = PositionGetString(POSITION_SYMBOL); CRequest.volume = PositionGetDouble(POSITION_VOLUME); CRequest.sl=0; CRequest.tp=0; CRequest.magic = PositionGetInteger(POSITION_MAGIC); CRequest.comment = PositionGetString(POSITION_COMMENT); CRequest.type_filling = FillingMode_; R = OrderSend(CRequest,CResult); if(!R) Print("OrderClose was rejected"); } //ヘッジタイプの場合(MT4ライクな場合)------------------------------------------------------------------------- if( AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ) { m_trade.PositionClose(Ticket,Slippage_in_point); } } |
MQL5に変える際に注意すべき点は
- iMAが直接値を返すのではなくiMAのハンドルを返すこと。
- Minutes()関数が使えないこと
- ポジションの総数がOrdersTotal()ではなくPositionsTotal()であること
- Ordersendは構造体で引数を指定すること
- Barsに引数が必要なこと
- マージンモードとフィリングモードに汎用性を持たせておくこと
です。
短期移動平均の期間と長期移動平均の期間をパラメータ化して最適化できるようにしましょう。
早速検証してみます。
EURUSD 2020/4/1~2020/4/14 短期MA期間 長期MA期間 パラメータ最適化結果
どうやら移動平均線の期間の組み合わせをどんなに頑張っても負けてしまうことが分かります。この原因にはいくつか考えられます。
- MT5の場合テスターでスプレッドを変えることができないのでスプレッドの影響が大きくなってしまっている(テスト時:4)
- そもそもこんなシンプルなトレードロジックでは優位性なんてない
RSIで挑戦
そこでちょっと悪あがきをしてみます。移動平均線のゴールデンクロス、デッドクロスは順張り向けのトレードロジックなので、逆張りのオシレーターであるRSIにテクニカル指標を変えてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
#include <Trade\Trade.mqh> CTrade m_trade; input uint RSISpan = 14; input double RSIUpper = 70; input double RSILower = 30; input double Lot = 0.1; static int Slippage_in_point = 3; enum FillingType{ FOK = ORDER_FILLING_FOK, IOC = ORDER_FILLING_IOC, Return = ORDER_FILLING_RETURN }; input FillingType FillingMode; static int FillingMode_; bool R; static int Bar[2]; static double RSI[]; int OnInit() { if( FillingMode == ORDER_FILLING_FOK ) FillingMode_ = ORDER_FILLING_FOK; else if( FillingMode == ORDER_FILLING_IOC ) FillingMode_ = ORDER_FILLING_IOC; else if( FillingMode == ORDER_FILLING_RETURN ) FillingMode_ = ORDER_FILLING_RETURN; return(INIT_SUCCEEDED); } void OnTick() { //--- MqlDateTime DateTime; TimeToStruct(TimeCurrent(),DateTime); Bar[1] = Bar[0]; Bar[0] = Bars(_Symbol,_Period); int RSIHandle = iRSI(_Symbol,0,RSISpan,PRICE_CLOSE); ArraySetAsSeries( RSI,true ); CopyBuffer( RSIHandle,0,0,3,RSI ); //Exit int OrdersTotal_ = PositionsTotal(); for(int i=0; i<OrdersTotal_;i++) { if( PositionGetTicket(i)>0 ) { if( DateTime.min%5 == 0 && Bar[1] != Bar[0] ) { OrderClose(PositionGetTicket(i)); } } } if( PositionsTotal() == 0 ) { if( DateTime.min%5 != 4 ) { if( RSI[1] >= RSILower && RSI[2] < RSILower ) { OrderSending(0); } else if( RSI[1] <= RSIUpper && RSI[2] > RSIUpper ) { OrderSending(1); } } } Comment("RSI[1] "+RSI[1]+"\n"+ "RSI[2] "+RSI[2]); } void OrderSending(int Direction) { MqlTradeRequest TRequest; MqlTradeResult TResult; ZeroMemory(TRequest); ZeroMemory(TResult); if( Direction == 0 ) { TRequest.type = ORDER_TYPE_BUY; TRequest.price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); Print("sl "+TRequest.sl+" order "+TRequest.price+" tp "+TRequest.tp); } else if( Direction == 1 ) { TRequest.type = ORDER_TYPE_SELL; TRequest.price = SymbolInfoDouble(_Symbol,SYMBOL_BID); Print("sl "+TRequest.sl+" order "+TRequest.price+" tp "+TRequest.tp); } TRequest.volume = Lot; TRequest.action = TRADE_ACTION_DEAL; TRequest.symbol = _Symbol; TRequest.magic = 1111; TRequest.comment = ""; TRequest.deviation = Slippage_in_point; TRequest.type_filling = FillingMode_; R = OrderSend(TRequest,TResult); if( !R ) Print("OrderSend for Open was rejected"); //we should check the return just in case. } void OrderClose(int Ticket) { MqlTradeRequest CRequest; MqlTradeResult CResult; ZeroMemory(CRequest); ZeroMemory(CResult); //ネッティングタイプの場合(ポジションが合体させられる場合)------------------------------------------------------------ if( AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_NETTING ) { //そのポジションと逆向きに同じ量の反対ポジションをとる R = PositionSelectByTicket(Ticket); if( PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ) { CRequest.type = ORDER_TYPE_SELL; CRequest.price = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL),SYMBOL_BID); Print("Order close Bid is "+CRequest.price); } else if( PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL ) { CRequest.type = ORDER_TYPE_BUY; CRequest.price = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL),SYMBOL_ASK); Print("Order close Ask is "+CRequest.price); } CRequest.action = TRADE_ACTION_DEAL; CRequest.symbol = PositionGetString(POSITION_SYMBOL); CRequest.volume = PositionGetDouble(POSITION_VOLUME); CRequest.sl=0; CRequest.tp=0; CRequest.magic = PositionGetInteger(POSITION_MAGIC); CRequest.comment = PositionGetString(POSITION_COMMENT); CRequest.type_filling = FillingMode_; R = OrderSend(CRequest,CResult); if(!R) Print("OrderClose was rejected"); } //ヘッジタイプの場合(MT4ライクな場合)------------------------------------------------------------------------- if( AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ) { m_trade.PositionClose(Ticket,Slippage_in_point); } } |
EURUSD 2020/4/1~2020/4/14 RSI期間 RSI上下ライン パラメータ最適化結果
例えば、RSI期間16, RSI上:80, RSI下:20でテストすると、勝率は52.64%になります。取引数19に対して、勝ちトレードは10回です。
毎回1000円ベットしたとすると、
投資コスト:19×1,000円=19,000円
リターン:10×1,000円x1.8=18,000円
差額-1,000円
スプレッドによる負け取引の増加があったとしてもやはりトントンです。
HighLow 15分で
どうやらしばらく見ない間にハイローオーストラリアではHighLowの5分のモードは消えたようですね。最短でも15分が最も短い時間のようです。
という訳で15分のハイローで検証を行ってみます。検証に使うプラットフォームはMT4とMT5と迷うところですが、15分であればティックデータの誤差が軽減されるので、スプレッドを変更できるMT4にしましょう。
締め切りは5分のハイローの時同様に1分前までです。
分が、xx:04、xx:24、xx:39、xx:54のときに締め切りで、xx:05、xx:25、xx:40、xx:55のときに判定があったり、
分が、xx:59、xx:14、xx:29、xx:44のときに締め切りで、xx:00、xx:15、xx:30、xx:45のときに判定があったりしますが、後者の時間区切りの方が分かりやすいので後者の検証で行きましょう。
ペイアウトは1.85なので、勝てば1.85倍、負ければ0倍になります。
締め切りから判定まではプット/コールできません。エントリーには下記の条件が必要です。
|
if( (Minute() >= 5 && Minute() < 14) || (Minute() >= 20 && Minute() < 29) || (Minute() >= 35 && Minute() < 44) || (Minute() >= 55 && Minute() < 59) ) |
決済条件は建玉を持っている場合に下記の時間になったら決済です。
|
if( Minute() == 0 || Minute() == 15 || Minute() == 30 || Minute() == 45 ) |
また、終了時刻+5分はプット/コールできません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
input uint ShortMAPeriod = 14; input uint LongMAPeriod = 28; static int Bar[3]; void OnTick() { double FastMA[3],SlowMA[3]; FastMA[1] = iMA(Symbol(),Period(),ShortMAPeriod,0,MODE_SMA,PRICE_CLOSE,1); FastMA[2] = iMA(Symbol(),Period(),ShortMAPeriod,0,MODE_SMA,PRICE_CLOSE,2); SlowMA[1] = iMA(Symbol(),Period(),LongMAPeriod,0,MODE_SMA,PRICE_CLOSE,1); SlowMA[2] = iMA(Symbol(),Period(),LongMAPeriod,0,MODE_SMA,PRICE_CLOSE,2); if( OrdersTotal() == 0 ) { if( (Minute() >= 5 && Minute() < 14) || (Minute() >= 20 && Minute() < 29) || (Minute() >= 35 && Minute() < 44) || (Minute() >= 55 && Minute() < 59) ) { int Ticket; if( FastMA[1] > SlowMA[1] && FastMA[2] <= SlowMA[2] ) { Ticket = OrderSend(Symbol(),OP_BUY,0.01,Ask,1,0,0,"",0,0,clrRed); } else if( FastMA[1] < SlowMA[1] && FastMA[2] >= SlowMA[2] ) { Ticket = OrderSend(Symbol(),OP_SELL,0.01,Bid,1,0,0,"",0,0,clrBlue); } } } Bar[1] = Bar[0]; Bar[0] = Bars; int OrdersTotal_ = OrdersTotal(); for( int i=0;i<OrdersTotal_;i++) { if( (Minute() == 0 || Minute() == 15 || Minute() == 30 || Minute() == 45) && Bar[1] != Bar[0] ) { bool R =OrderSelect(i,SELECT_BY_POS,MODE_TRADES); //exit if( OrderType() == OP_BUY ) R = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrYellow); if( OrderType() == OP_SELL ) R = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrYellow); } } } |
あとは1分足で全ティックでスプレッド1でテストするだけです。
短期移動平均線の期間と長期移動平均線の期間を”過剰最適化”させると(54,14)が最適であるということが分かりました。
総取引数219に対して勝ちトレードが120で、勝率がなんとか50%を超えています。
コストは、219回x1000円=219,000円 に対して、
リターンは、1850円x120回=222,000円 なので1000円だけプラスです。
HighLow Turbo 3分の場合
ハイローオーストラリアにはバイナリーオプションの種類に”Turbo”というものがあり、指定された時間で閉じるのではなく、プット/コールした時間を起点にして30秒後、60秒後、180秒後、300秒後にレートが上がるか下がるかをベットするモードがあります。
こちらのモードの場合、ペイアウトは1.95で通常モードよりもなぜか”払い”が良いです。
EAのプログラミングはTurboモードの方が簡単です。エントリーから時間のフィルターを外し、決済を指定秒数後にするだけです。
|
input uint TurboTime_Sec = 180; if( TimeCurrent() >= OrderOpenTime() + TurboTime_Sec ) |
コード全体は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
input uint TurboTime_Sec = 180; input uint ShortMAPeriod = 14; input uint LongMAPeriod = 28; static int Bar[3]; void OnTick() { double FastMA[3],SlowMA[3]; FastMA[1] = iMA(Symbol(),Period(),ShortMAPeriod,0,MODE_SMA,PRICE_CLOSE,1); FastMA[2] = iMA(Symbol(),Period(),ShortMAPeriod,0,MODE_SMA,PRICE_CLOSE,2); SlowMA[1] = iMA(Symbol(),Period(),LongMAPeriod,0,MODE_SMA,PRICE_CLOSE,1); SlowMA[2] = iMA(Symbol(),Period(),LongMAPeriod,0,MODE_SMA,PRICE_CLOSE,2); if( OrdersTotal() == 0 ) { int Ticket; if( FastMA[1] > SlowMA[1] && FastMA[2] <= SlowMA[2] ) { Ticket = OrderSend(Symbol(),OP_BUY,0.01,Ask,1,0,0,"",0,0,clrRed); } else if( FastMA[1] < SlowMA[1] && FastMA[2] >= SlowMA[2] ) { Ticket = OrderSend(Symbol(),OP_SELL,0.01,Bid,1,0,0,"",0,0,clrBlue); } } Bar[1] = Bar[0]; Bar[0] = Bars; int OrdersTotal_ = OrdersTotal(); for( int i=0;i<OrdersTotal_;i++) { OrderSelect(i,SELECT_BY_POS); if( TimeCurrent() >= OrderOpenTime() + TurboTime_Sec ) { bool R =OrderSelect(i,SELECT_BY_POS,MODE_TRADES); //exit if( OrderType() == OP_BUY ) R = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrYellow); if( OrderType() == OP_SELL ) R = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrYellow); } } } |
例によってまた過剰最適化させます。
取引数796に対して勝ちトレードが415で、勝率が52.14%です。
投資コストは、796回 x 1000円 = 796,000円
リターンは、415回 x 1000円 x 1.95 = 809,250円
なので13,250円の儲けになります。実際はスプレッド分負けているトレードもあるのでこれよりもちょっと増えるはずです。
ハイロー Turbo リバウンド狙い戦略
これまでは移動平均線やRSIを過剰最適化することでしか勝率50%以上を出すことが困難でしたが、暴騰暴落のリバウンド狙いならもう少しマシな成果を出せます。
|
input uint TurboTime_Sec = 180; input uint Gap_in_point = 100; int Ticket; if( iClose(_Symbol, _Period, 0) > iOpen(_Symbol, _Period, 0) + Gap_in_point*_Point ) { Ticket = OrderSend(Symbol(),OP_SELL,0.01,Bid,1,0,0,"",0,0,clrBlue); } else if( iClose(_Symbol, _Period, 0) < iOpen(_Symbol, _Period, 0) - Gap_in_point*_Point ) { Ticket = OrderSend(Symbol(),OP_BUY,0.01,Ask,1,0,0,"",0,0,clrRed); } |
暴騰暴落局面は、通常のFX取引の場合は約定拒否やスプレッドが広大になる場面ですが、ハイローバイナリーの場合はスプレッドを無視できるので、(無視できるモードがあるので、)そこに”穴”があります。
また、FXの場合はレートがリバウンドせずにそのまま直行してしまった場合に、損失が膨大になりそれまでの利益を吹き飛ばしてしまいますが、ハイローバイナリーオプションの場合は損失が限定的なので、そういった意味でもバイナリーオプションでこそできる戦略だと思います。
リバウンド狙いの場合は通常のハイローバイナリーモードよりもTurboの方が有利なので、Turboで検証します。
|
int OrdersTotal_ = OrdersTotal(); for( int i=0;i<OrdersTotal_;i++) { OrderSelect(i,SELECT_BY_POS); if( TimeCurrent() >= OrderOpenTime() + TurboTime_Sec ) { bool R =OrderSelect(i,SELECT_BY_POS,MODE_TRADES); //exit if( OrderType() == OP_BUY ) R = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrYellow); if( OrderType() == OP_SELL ) R = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrYellow); } } |
Gap_in_pointが指定の暴騰暴落幅です。始値から現在レートまでにこの数値以上の開きを形成したときに逆張り(リバウンド狙い 落ちるナイフを掴む)取引します。大きな時間枠での暴騰暴落の場合はそのまま行ったっきりになることが多いですが、小さい時間枠チャートでの場合はリバウンドする率が高いです。
35~40pointあたりを頂点として優位性があることが分かります。(右側の収益性が低いパラメータでもプラス)
実際にグラフを確認してみると、
悪くはないグラフです。
総取引数:1256に対して、勝ちトレードが679です。
ベット総額:1256 x 1000円 = 1,256,000円
ペイアウト:679 x 1.95 x 1000円 = 1,324,050円
収益:68,050円
120万かけて7万のリターンを大きいとみるか、小さいとみるかは人それぞれでしょう。ただ、この取引数をこなすには自動売買が必要ですね。人件費を考慮しても… しかし、こんな取引をしたら自動売買であることがあからさまに検知されるので、やっぱり厳しいかな..
HighLow_SingalSender_turbo_rebound.ex4
HighLow_SingalSender_turbo_rebound_ATR.ex4
しかし、やはり単一のテクニカル指標程度ではごく短い時間枠チャートでのトレードの優位性を見出すこと自体が厳しい、ということでしょう。もうちょっと複雑にしたトレードロジックなら曙光が見えるかもしれません。
バイナリーオプションで何か検証してほしいトレードロジックがあればコメントにお願いします。
コメント
こんにちは。
プログラミング知識がありませんが(勉強中)バイナリ―1分足の00秒ペイアウト90%のノウハウでのバックテストをとりたくて奮闘しております。
文中にあるソースコードを1分用に編集できたとして、このソースをコンパイルしてどう使うのでしょうか?
・バックテスト対象のカスタムインジにのMQL4にこのソースを追加するのでしょうか?
・このソースをコンパイルするとストラテジーテスターにで選択できるようになり、選択することによりバックテストをかけたいカスタムインジを選択できるのでしょうか?
不敵させつなコメントであれば申し訳ありません。
宜しくお願いします。