Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // test_3ma_user_v2.mq4
- // by 2024-2026 (c)hyrolean
- //---------------------------------------------------------------------------
- #property copyright "2024-2026, (c)hyrolean"
- #property link "https://pastebin.com/rAPtby8g"
- #property version "2.00"
- #property strict
- #include <stdlib.mqh>
- #include <User/hyrDefs.mqh> // https://pastebin.com/iHZKAWqC
- #include <User/hyrTmpl.mqh> // https://pastebin.com/LG1vurny
- #include <User/hyrGlobal.mqh> // https://pastebin.com/2PdBW6NQ
- #include <User/hyrStatus.mqh> // https://pastebin.com/D9JP5Ujq
- // version 2.00
- // - ユーザーロット調整機能を追加
- // - 約定が失敗した際に音とエラーメッセージで知らせる処理を追加
- // - 主要関数を自作ライブラリに置換えてコンパクト化
- /*
- 3EMA 手法 ( 状態遷移情報をターミナルに格納する変数を必要としないバージョン )
- ・ 建玉するときに、EMA50をストップロスに設定する(Stoploss=0の場合)
- ※ 現在価格がEMA50を下回るところでは、建玉を行わないようにする
- ・ ストップロスが玉の価格より下にあるものに的を絞り、EMA50を基準にトレーリングを行う
- ※ ただし、玉の価格がEMA50より下にある場合は、上記の操作を見送ることとする
- ・ ストップロスが玉の価格より下にあるものに的を絞り、ロウソク足が5期間経過後から、
- 現在のプライスが超えた時点でストップロスをエントリープライスに移動し、ロットの1/3を利確する
- ロウソク足の期間の出し方:
- iBarShift(_Symbol, MainTimeFrame, <建玉時刻>)>=5
- ※ 5期間経過後に未だ現価が下にある場合は、現価が上に来るまでこの試行は継続
- されることとし、現価がロウソク足1期間でも抜けたら即ストップロスをエントリープライスに移動
- し、ロットの1/3利確することとする
- ・ 現在価格がEMA10を下回った場合、ストップロスがエントリープライスに一致する玉を検出し、
- EMA20の位置にストップロスを移動し、ロットの1/2を利確する(この時点でEMA20も現在価格
- を突破している場合は、全ロットを利確することとする)
- ※ ただし、玉の価格がEMA20より上にある場合は、上記の操作を見送ることとする
- ・ ストップロスが玉の価格より上にあるものに的を絞り、EMA20を基準にトレーリングを行う
- */
- /*
- 使い方::
- 左上の|SELL|BUY|ボタンを選んでポジションを自分で打ちます。
- ポジションを打ったら、sl(ストップロス)のBARを自分の好みの場所に移動させます。
- 以降、3EMAの手法に従って自動的に利確されます。(逆行しなければですが…)
- 運悪く逆行してしまった場合は、損益の㌫、または、slに応じて自動損切されます。
- エントリーのコツとしては、上から現在価格,EMA10,EMA20,EMA50の順番で並んでいるときは、
- ロング(買い)、逆に、上からEMA50,EMA20,EMA10,現在価格の順番で並んでいるときは、
- ショート(売り)でエントリーすると上手くいくかもしれないです。
- (利確のタイミングを図りたい場合など、自動処理を一時的に中断したい場合は、Automate
- Processing Orders をfalseに設定すると無効に出来ます。)
- MT4を閉じてもslとエントリープライスの位置だけで状態を把握する為、万が一VPS等が停止し
- てしまってもサーバー側に建玉の情報さえ残っていればMT4を再度立ち上げてこのEAを有
- 効化するだけで状態復帰可能な仕様に仕上げています。
- 以上ゞ
- */
- #define ENTRY_NAME "3MAUserV2"
- #define ORDER_RETRY 10
- #define ORDER_RETRY_SLEEP 100
- #define ORDER_RETRY_DURATION 1000
- enum ENUM_POSI {
- POSI_STOP, // Stop
- POSI_ONLY_LONG, // Only Long
- POSI_ONLY_SHORT, // Only Short
- POSI_HALF_LONG_AND_SHORT, // Long & Short (Half duplex)
- POSI_FULL_LONG_AND_SHORT // Long & Short (Full duplex)
- };
- #define STATAG_CHECKEDOUT 1
- input bool Automation = true; // Automate processing orders
- input ENUM_TIMEFRAMES MainTimeFrame = PERIOD_CURRENT; // Main Time Frame
- input MAGIC MAGICMA = 0; // Magic Number
- input bool TimeControl = false; // Time Control
- input ENUM_TIMEBASE TimeBase = TIMEBASE_LOCAL; // Time Base
- input string TimeStart = "09:00"; // Time Start
- input string TimeEnd = "15:00"; // Time End
- input ENUM_TIMEACT TimeAction = TIMEACT_NONE; // Time Action when time end reached
- input ENUM_MA_METHOD MAMode= MODE_EMA; // MA mode
- input ENUM_APPLIED_PRICE MAPriceType = PRICE_CLOSE; // MA price type
- input bool MA3 = true; // 3MA Enabled
- input int MA3FastPeriod = 10; // 3MA Fast period
- input int MA3MediumPeriod = 20; // 3MA Medium period
- input int MA3SlowPeriod = 50; // 3MA Slow period
- input int MA3TLPeriod = 5; // 3MA TL(TimeLimited) period
- input int Slippage = 10; // Max Slippage
- input int Spread = 50; // Max Spread in points
- input double BaseLots = 0.1; // Base Lots
- input double StepLots = 0.01; // Step Lots
- input double MinLots = 0.01; // Minimum Lots
- input double MaxLots = 50.0; // Maximum Lots
- input double LotsDenomTL = 3.0; // Lots denom of 3MA TL(TimeLimited)
- input double LotsDenomMAFast = 2.0; // Lots denom of 3MA Fast MA
- input double Takeprofit = 0; // Take profit in points (0 = unlimited)
- input double Stoploss = 200; // Stop loss in points (0 = Grossloss per or SlowMA trail)
- input double MaxGrosslossPer = 25; // Maximum Allowed Gross loss of Balance in percentage
- input bool Compounding = false; // Compounding interest Enabled
- input double CompoundingBase = 100000; // Compounding Base Balance (Lots=BaseLots*Balance/BaseBalance)
- input bool BalanceIncludeCredit= true; // Balance include Credit
- input bool Trailing = false; // Trailing Enabled
- input double TrailingStart = 300; // Trailing Start in points
- input double TrailingStop = 200; // Trailing Stop in points
- input bool ShowUserEntry = true; // Show user entry SELL/BUY buttons
- input bool ShowCloseAll = true; // Show a CLOSE ALL button
- input bool ShowCloseLong = false; // Show a CLOSE LONG button
- input bool ShowCloseShort = false; // Show a CLOSE SHORT button
- input bool ShowFlushTL = true; // Show a FLUSH TL button
- input bool ShowAmount = true; // Show Current Amount
- input int AmountDig = 0; // Amount Number of decimal places
- input color ClrAmountPosi = clrLightGoldenrod; // Amount Positive color
- input color ClrAmountNega = clrLightPink; // Amount Negative color
- input color ClrTimeControl = clrYellow; // Time Control Status color
- input color ClrLongArrow = clrBlue; // Long Arrow color
- input color ClrShortArrow = clrRed; // Short Arrow color
- input bool DBGMODE = true; // DEBUG MODE
- //===========================================================================
- // 型
- //---------------------------------------------------------------------------
- // OBJECT_PARTCLOSED
- struct OBJECT_PARTCLOSED {
- TICKET Ticket;
- OP Type;
- double Price;
- double Stoploss;
- datetime Time;
- OBJECT_PARTCLOSED(TICKET Ticket_, OP Type_, double Price_, datetime Time_, double Stoploss_=0) {
- Ticket = Ticket_ ;
- Type = Type_ ;
- Price = Price_ ;
- Time = Time_ ;
- Stoploss = Stoploss_ ;
- }
- OBJECT_PARTCLOSED(const OBJECT_PARTCLOSED &src) {
- Ticket = src.Ticket ;
- Type = src.Type ;
- Price = src.Price ;
- Time = src.Time ;
- Stoploss = src.Stoploss ;
- }
- bool operator <(const OBJECT_PARTCLOSED &rhs) const {
- //if(Ticket < rhs.Ticket) return true ;
- if(Type < rhs.Type) return true ;
- if(Price < rhs.Price) return true ;
- if(Time < rhs.Time) return true ;
- return false ;
- }
- };
- //===========================================================================
- double UserLots, Lots, PrevBid, PrevAsk;
- #define MAShift 0
- datetime CurTime, TimeTick, StartTime, CancelTime, UserTime;
- FLAG UserEntry = 0 ;
- bool FlushTL = false ;
- // サーバーがストップロスを更新しなかった場合のトラップ対策用配列
- CArrayObj *StoplossTrapArray = NULL;
- #define LOTSED_NAME "EntryLots"
- #define LOTSDEC_NAME "LotsDecBtn"
- #define LOTSINC_NAME "LotsIncBtn"
- #define SELLBTN_NAME "EntrySell"
- #define BUYBTN_NAME "EntryBuy"
- #define CLOSEALLBTN_NAME "CloseAll"
- #define CLOSELONGBTN_NAME "CloseLong"
- #define CLOSESHORTBTN_NAME "CloseShort"
- #define FLUSHTLBTN_NAME "FlushTL"
- #define LOTSSAVE_NAME (ENTRY_NAME "_UserLots_" + Symbol())
- #define OFFTIME_NAME "OFF TIME"
- bool OffTimeVisible = false ;
- #define AMOUNT_NAME "AMOUNT"
- #define AMOUNT_CLR_NEGA ClrAmountNega
- #define AMOUNT_CLR_POSI ClrAmountPosi
- #define DBGINFO_NAME "DEBUG INFO"
- double AdjLots(double lots) {
- lots = AdjustMarketLots(lots);
- double roundLots = MathRound( MathMax(lots,StepLots) / StepLots ) ;
- return MathMin(MathMax(roundLots*StepLots,MinLots),MaxLots) ;
- }
- //---------------------------------------------------------------------------
- int OnInit()
- {
- //テスターで表示されるインジケータを非表示にする
- HideTestIndicators(!DBGMODE);
- CurTime = MainTime();
- TimeTick = StartTime = CancelTime = UserTime = BaseTime(TimeBase);
- GlobalSettings(
- ENTRY_NAME,
- Slippage,
- Spread,
- ORDER_RETRY,
- ORDER_RETRY_SLEEP,
- ORDER_RETRY_DURATION );
- OrderColorSetting(
- ClrLongArrow,
- ClrShortArrow );
- bool LotsLoaded = false ;
- if(GlobalVariableCheck(LOTSSAVE_NAME)) {
- UserLots = GlobalVariableGet(LOTSSAVE_NAME);
- LotsLoaded = true ;
- }
- UserLots = AdjLots(UserLots);
- Lots = AdjLots(BaseLots) ; PrevBid = Bid ; PrevAsk = Ask ;
- //ストップロス更新確認用配列
- StoplossTrapArray = new CArrayObj();
- StoplossTrapArray.Sort(ARRAY_SORT_ASCEND);
- //DEBUG INFO
- if(DBGMODE) {
- ObjectCreate(DBGINFO_NAME, OBJ_LABEL, 0, 0, 0);
- ObjectSet(DBGINFO_NAME, OBJPROP_XDISTANCE, 10);
- ObjectSet(DBGINFO_NAME, OBJPROP_YDISTANCE, 15);
- ObjectSet(DBGINFO_NAME, OBJPROP_CORNER, 3);
- ObjectSetString(0, DBGINFO_NAME, OBJPROP_TEXT, "DEBUG INFO");
- ObjectSetString(0, DBGINFO_NAME, OBJPROP_FONT, "Verdana");
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_FONTSIZE, 8);
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_COLOR, clrAquamarine);
- }
- //金額表示
- if(ShowAmount) {
- ObjectCreate(AMOUNT_NAME, OBJ_LABEL, 0, 0, 0);
- ObjectSet(AMOUNT_NAME, OBJPROP_XDISTANCE, 20);
- ObjectSet(AMOUNT_NAME, OBJPROP_YDISTANCE, 35);
- ObjectSet(AMOUNT_NAME, OBJPROP_CORNER, 3);
- ObjectSetString(0, AMOUNT_NAME, OBJPROP_TEXT, "0-");
- ObjectSetString(0, AMOUNT_NAME, OBJPROP_FONT, "Verdana");
- ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_FONTSIZE, 15);
- ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_COLOR, AMOUNT_CLR_POSI);
- }
- //ユーザーエントリ用ボタン
- if(ShowUserEntry) {
- int edit_y_pos = 20;
- int btn_y_pos = edit_y_pos + 24;
- // < 減らすボタン
- ObjectCreate(0, LOTSDEC_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_XDISTANCE, 10);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_YDISTANCE, edit_y_pos);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_XSIZE, 20);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_YSIZE, 20);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_CORNER, 0);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_FONTSIZE, 10);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_COLOR, clrWhite);
- ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_BGCOLOR, clrDimGray);
- ObjectSetString (0, LOTSDEC_NAME, OBJPROP_TEXT, "<");
- ObjectSetString (0, LOTSDEC_NAME, OBJPROP_FONT, "Verdana");
- // エディットボックス
- ObjectCreate(0, LOTSED_NAME, OBJ_EDIT, 0, 0, 0);
- ObjectSetInteger(0, LOTSED_NAME, OBJPROP_XDISTANCE, 31);
- ObjectSetInteger(0, LOTSED_NAME, OBJPROP_YDISTANCE, edit_y_pos);
- ObjectSetInteger(0, LOTSED_NAME, OBJPROP_XSIZE, 66);
- ObjectSetInteger(0, LOTSED_NAME, OBJPROP_YSIZE, 20);
- ObjectSetString (0, LOTSED_NAME, OBJPROP_TEXT, DoubleToString(UserLots,2)+(LotsLoaded?"":"-"));
- ObjectSetInteger(0, LOTSED_NAME, OBJPROP_ALIGN, ALIGN_CENTER);
- ObjectSetString(0, LOTSED_NAME, OBJPROP_TOOLTIP,
- "Enter the lot size\n"
- "Press the < > button, then dec/inc lots step by " + DoubleToString(StepLots, 2) + "\n"
- "NOTE: It will be reset to the base lots if the text ends with a '-'" );
- // > 増やすボタン
- ObjectCreate(0, LOTSINC_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_XDISTANCE, 98);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_YDISTANCE, edit_y_pos);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_XSIZE, 20);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_YSIZE, 20);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_CORNER, 0);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_FONTSIZE, 10);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_COLOR, clrWhite);
- ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_BGCOLOR, clrDimGray);
- ObjectSetString (0, LOTSINC_NAME, OBJPROP_TEXT, ">");
- ObjectSetString (0, LOTSINC_NAME, OBJPROP_FONT, "Verdana");
- //SELLボタン
- ObjectCreate(SELLBTN_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSet(SELLBTN_NAME, OBJPROP_XDISTANCE, 10);
- ObjectSet(SELLBTN_NAME, OBJPROP_YDISTANCE, btn_y_pos);
- ObjectSet(SELLBTN_NAME, OBJPROP_XSIZE, 53);
- ObjectSet(SELLBTN_NAME, OBJPROP_YSIZE, 27);
- ObjectSet(SELLBTN_NAME, OBJPROP_CORNER, 0);
- ObjectSet(SELLBTN_NAME, OBJPROP_FONTSIZE, 12);
- ObjectSet(SELLBTN_NAME, OBJPROP_COLOR, White);
- ObjectSet(SELLBTN_NAME, OBJPROP_BGCOLOR, clrFireBrick);
- ObjectSetString(0, SELLBTN_NAME, OBJPROP_TEXT, "SELL");
- ObjectSetString(0, SELLBTN_NAME, OBJPROP_FONT, "Verdana");
- //BUYボタン
- ObjectCreate(BUYBTN_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSet(BUYBTN_NAME, OBJPROP_XDISTANCE, 65);
- ObjectSet(BUYBTN_NAME, OBJPROP_YDISTANCE, btn_y_pos);
- ObjectSet(BUYBTN_NAME, OBJPROP_XSIZE, 53);
- ObjectSet(BUYBTN_NAME, OBJPROP_YSIZE, 27);
- ObjectSet(BUYBTN_NAME, OBJPROP_CORNER, 0);
- ObjectSet(BUYBTN_NAME, OBJPROP_FONTSIZE, 12);
- ObjectSet(BUYBTN_NAME, OBJPROP_COLOR, White);
- ObjectSet(BUYBTN_NAME, OBJPROP_BGCOLOR, clrRoyalBlue);
- ObjectSetString(0, BUYBTN_NAME, OBJPROP_TEXT, "BUY");
- ObjectSetString(0, BUYBTN_NAME, OBJPROP_FONT, "Verdana");
- }
- int btn_ofs_x = 0 ;
- const int btn_distance = 102 ;
- //全決済ボタン
- if(ShowCloseAll) {
- ObjectCreate(CLOSEALLBTN_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x );
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_YDISTANCE, 35);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_XSIZE, 100);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_YSIZE, 25);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_CORNER, 2);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_FONTSIZE, 10);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_COLOR, White);
- ObjectSet(CLOSEALLBTN_NAME, OBJPROP_BGCOLOR, /*clrDarkGreen*/clrDarkSlateGray);
- ObjectSetString(0, CLOSEALLBTN_NAME, OBJPROP_TEXT, "CLOSE ALL");
- ObjectSetString(0, CLOSEALLBTN_NAME, OBJPROP_FONT, "Verdana");
- btn_ofs_x += btn_distance ;
- }
- //LONG決済ボタン
- if(ShowCloseLong) {
- ObjectCreate(CLOSELONGBTN_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x );
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_YDISTANCE, 35);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_XSIZE, 100);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_YSIZE, 25);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_CORNER, 2);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_FONTSIZE, 10);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_COLOR, White);
- ObjectSet(CLOSELONGBTN_NAME, OBJPROP_BGCOLOR, clrRoyalBlue);
- ObjectSetString(0, CLOSELONGBTN_NAME, OBJPROP_TEXT, "CLOSE LONG");
- ObjectSetString(0, CLOSELONGBTN_NAME, OBJPROP_FONT, "Verdana");
- btn_ofs_x += btn_distance ;
- }
- //SHORT決済ボタン
- if(ShowCloseShort) {
- ObjectCreate(CLOSESHORTBTN_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x );
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_YDISTANCE, 35);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_XSIZE, 100);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_YSIZE, 25);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_CORNER, 2);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_FONTSIZE, 10);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_COLOR, White);
- ObjectSet(CLOSESHORTBTN_NAME, OBJPROP_BGCOLOR, clrFireBrick);
- ObjectSetString(0, CLOSESHORTBTN_NAME, OBJPROP_TEXT, "CLOSE SHORT");
- ObjectSetString(0, CLOSESHORTBTN_NAME, OBJPROP_FONT, "Verdana");
- btn_ofs_x += btn_distance ;
- }
- //TLフラッシュ決算ボタン
- if(ShowFlushTL) {
- ObjectCreate(FLUSHTLBTN_NAME, OBJ_BUTTON, 0, 0, 0);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x );
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_YDISTANCE, 35);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_XSIZE, 100);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_YSIZE, 25);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_CORNER, 2);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_FONTSIZE, 10);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_COLOR, White);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_BGCOLOR, clrDarkSlateBlue);
- ObjectSetString(0, FLUSHTLBTN_NAME, OBJPROP_TEXT, "FLUSH TL");
- ObjectSetString(0, FLUSHTLBTN_NAME, OBJPROP_FONT, "Verdana");
- btn_ofs_x += btn_distance ;
- }
- //ユーザーエントリをリセット
- UserEntry=0;
- return(INIT_SUCCEEDED);
- }
- //---------------------------------------------------------------------------
- void OnDeinit(const int reason)
- {
- if(ShowFlushTL) ObjectDelete(FLUSHTLBTN_NAME);
- if(ShowCloseShort) ObjectDelete(CLOSESHORTBTN_NAME) ;
- if(ShowCloseLong) ObjectDelete(CLOSELONGBTN_NAME) ;
- if(ShowCloseAll) ObjectDelete(CLOSEALLBTN_NAME) ;
- if(ShowUserEntry) {
- string lots_str = ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT) ;
- int ln = StringLen(lots_str);
- if(ln>0) {
- if(lots_str[ln-1]=='-') {
- if(GlobalVariableCheck(LOTSSAVE_NAME))
- GlobalVariableDel(LOTSSAVE_NAME);
- }else {
- double lots = StringToDouble(lots_str);
- if(lots>0) {
- lots = AdjLots(lots) ;
- if(UserLots!=lots) {
- UserLots = lots ;
- GlobalVariableSet(LOTSSAVE_NAME, UserLots);
- }
- }
- }
- }
- ObjectDelete(BUYBTN_NAME);
- ObjectDelete(SELLBTN_NAME);
- ObjectDelete(LOTSINC_NAME);
- ObjectDelete(LOTSDEC_NAME);
- ObjectDelete(LOTSED_NAME);
- }
- if(OffTimeVisible) {
- ObjectDelete(OFFTIME_NAME) ;
- OffTimeVisible=false ;
- }
- if(ShowAmount) {
- ObjectDelete(AMOUNT_NAME) ;
- }
- if(DBGMODE) {
- ObjectDelete(DBGINFO_NAME) ;
- }
- if(StoplossTrapArray!=NULL) {
- delete StoplossTrapArray ;
- StoplossTrapArray = NULL ;
- }
- }
- //---------------------------------------------------------------------------
- void OnTick()
- {
- datetime nextTime = MainTime() ;
- bool nextTimed = nextTime != CurTime ;
- CurTime = nextTime ;
- datetime nextTick = BaseTime(TimeBase) ;
- bool nextTicked = nextTick != TimeTick ;
- TimeTick = nextTick;
- // タイムコントロールチェック
- CheckTimeControl(nextTicked);
- // 動作チェック
- CheckBehavior(nextTimed);
- double atr14 = iATR(NULL,0,14,0) ;
- double spread = Ask-Bid ;
- // デバッグ欄表示のサンプル
- if(DBGMODE) {
- DBGOUT(
- // ATR in points
- StringFormat("ATR(14): %.3f",atr14/Point) + " | " +
- // SPREAD in points
- StringFormat("SPREAD: %g",spread/Point) + " | " +
- // 現在の値幅の変動倍率(ATR/SPREAD)
- StringFormat("ATR(14)/SPREAD: %.3f",atr14/(spread<=0?1:spread))
- );
- }
- // エントリー処理
- if(IsExpertEnabled()&&IsTradeAllowed()) {
- FLAG busy = AlreadyOrdered(FLAG_BUY|FLAG_SELL,MAGICMA) ;
- // ユーザーロット情報自動更新(ロットの最後が'-'で終わっている場合)
- if(ShowUserEntry) {
- string LotsStr = ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT) ;
- int ln = StringLen(LotsStr);
- if(ln>0) {
- if(LotsStr[ln-1]=='-') {
- if(UserLots!=Lots) {
- UserLots = Lots;
- ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT, DoubleToString(UserLots, 2)+"-");
- }
- }
- }
- }
- // ユーザーの注文
- if(UserEntry) {
- // ユーザーのエントリを確認
- if(TimeTick-UserTime<60) { // 発行されてから60秒以内の注文
- FLAG user = UserEntry ;
- // 注文
- if(user/*&&!AlreadyOrdered(user,MAGICMA)*/) {
- // ユーザーロット取得と更新
- if(ShowUserEntry) {
- double lots = StringToDouble(ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT));
- if(lots>0) {
- lots = AdjLots(lots) ;
- if(UserLots!=lots) {
- UserLots = lots ;
- GlobalVariableSet(LOTSSAVE_NAME, UserLots);
- }
- }
- }
- OP entry = user == FLAG_BUY ? OP_BUY : OP_SELL ;
- if(EntryManualPosition("USER", entry, UserLots)>=0)
- busy |= user ;
- else {
- PrintMessage("Order failed by USER.");
- PlaySound("timeout.wav");
- }
- UserEntry = 0 ;
- }
- }else { UserEntry=0; }
- }
- // MARK: 自動注文
- /*
- do {
- // 自動注文 開始時間調整
- if(StartTime>TimeTick||CancelTime>TimeTick)
- break ;
- // スプレッド幅のチェック
- if(MarketInfo(NULL,MODE_SPREAD) > Spread)
- break ;
- // 自動注文 XMA+ZigZag Detector
- if(nextTimed)
- EAEntryXMAZigZagPosition(busy,1);
- }while(0);
- */
- }else {
- if(StartTime-TimeTick<10)
- StartTime = TimeTick+10 ;
- }
- /*
- if(PmdTiming) {
- PmdPrevBid = (PmdPrevBid+Bid)/2.0 ; PmdPrevAsk = (PmdPrevAsk+Ask)/2.0 ;
- }*/
- PrevBid = Bid ; PrevAsk = Ask ;
- }
- //---------------------------------------------------------------------------
- void OnChartEvent(
- const int id,
- const long &lparam,
- const double &dparam,
- const string &sparam
- )
- {
- if(id == CHARTEVENT_OBJECT_ENDEDIT && sparam == LOTSED_NAME) {
- string lotsStr = ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT);
- int ln = StringLen(lotsStr);
- bool invalid = true ;
- if(ln > 0 && lotsStr[ln-1] != '-') {
- // 数値として評価してチェック
- double lots = StringToDouble(lotsStr);
- if(lots > 0) {
- // 正常値 → AdjLots で丸めて反映
- lots = AdjLots(lots);
- UserLots = lots;
- GlobalVariableSet(LOTSSAVE_NAME, UserLots);
- ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT,
- DoubleToString(UserLots, 2));
- invalid = false ; // 適正値
- }
- }
- if(invalid) { // 不正値、または、自動ロット設定値("-"で終わる場合)
- UserLots = Lots;
- ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT,
- DoubleToString(Lots, 2) + "-");
- }
- }
- if(id == CHARTEVENT_OBJECT_CLICK &&
- (sparam == LOTSDEC_NAME || sparam == LOTSINC_NAME)) {
- double lots = StringToDouble(ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT));
- lots += (sparam == LOTSINC_NAME ? +StepLots : -StepLots);
- lots = AdjLots(lots);
- UserLots = lots;
- GlobalVariableSet(LOTSSAVE_NAME, UserLots);
- ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT, DoubleToString(UserLots, 2));
- Sleep(100);
- ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
- }
- if( ( sparam == CLOSEALLBTN_NAME ||
- sparam == CLOSELONGBTN_NAME ||
- sparam == CLOSESHORTBTN_NAME ) && id==CHARTEVENT_OBJECT_CLICK) {
- int orderFlag = 0 ;
- if(sparam == CLOSEALLBTN_NAME) orderFlag = FLAG_SELL | FLAG_BUY ;
- else if(sparam == CLOSELONGBTN_NAME) orderFlag = FLAG_BUY ;
- else if(sparam == CLOSESHORTBTN_NAME) orderFlag = FLAG_SELL ;
- CheckoutOrders(orderFlag);
- Sleep(100);
- ObjectSet(sparam, OBJPROP_STATE, False);
- // 60秒エントリーを停止する
- CancelTime = TimeTick + 60 ;
- }
- if(sparam == FLUSHTLBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
- FlushTL=true;
- Sleep(100);
- ObjectSet(FLUSHTLBTN_NAME, OBJPROP_STATE, False);
- }
- if(sparam == SELLBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
- { UserEntry = FLAG_SELL ; CancelTime = UserTime = TimeTick ; CancelTime+=60 ; }
- Sleep(100);
- ObjectSet(SELLBTN_NAME, OBJPROP_STATE, False);
- }
- if(sparam == BUYBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
- { UserEntry = FLAG_BUY ; CancelTime = UserTime = TimeTick ; CancelTime+=60 ; }
- Sleep(100);
- ObjectSet(BUYBTN_NAME, OBJPROP_STATE, False);
- }
- }
- //---------------------------------------------------------------------------
- //DBGOUT
- void DBGOUT(string text)
- {
- if(DBGMODE) {
- ObjectSetString(0, DBGINFO_NAME, OBJPROP_TEXT, text);
- }
- }
- //---------------------------------------------------------------------------
- //タイムコントロールチェック
- void CheckTimeControl(bool nextTicked)
- {
- if(!TimeControl) {
- if(OffTimeVisible) {
- ObjectDelete(OFFTIME_NAME);
- OffTimeVisible = false ;
- }
- return ;
- }
- if(!nextTicked) return ;
- if(!ControlTimeAction(
- TimeTick,StringToTime(TimeStart),StringToTime(TimeEnd),
- StartTime,MAGICMA,TimeAction)) {
- datetime timOff = StartTime - TimeTick ;
- if(!OffTimeVisible) {
- // OFF TIME テキストを表示
- ObjectCreate(OFFTIME_NAME, OBJ_LABEL, 0, 0, 0);
- ObjectSet(OFFTIME_NAME, OBJPROP_XDISTANCE, 10);
- ObjectSet(OFFTIME_NAME, OBJPROP_YDISTANCE, 25);
- ObjectSet(OFFTIME_NAME, OBJPROP_CORNER, 1);
- ObjectSetString(0, OFFTIME_NAME, OBJPROP_TEXT, "OFF TIME");
- ObjectSetString(0, OFFTIME_NAME, OBJPROP_FONT, "Verdana");
- ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_FONTSIZE, 8);
- ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_COLOR, ClrTimeControl);
- OffTimeVisible = true ;
- }
- }else if(OffTimeVisible) {
- ObjectDelete(OFFTIME_NAME);
- OffTimeVisible = false ;
- }
- }
- //---------------------------------------------------------------------------
- //メインタイムを返す
- datetime MainTime(int shift=0)
- {
- return iTime(Symbol(), MainTimeFrame, shift);
- }
- //---------------------------------------------------------------------------
- //メインPERIODを返す
- int MainPeriod()
- {
- int period = MainTimeFrame ;
- if(!period) period = Period();
- return period ;
- }
- //---------------------------------------------------------------------------
- //金額表示の更新
- void UpdateAmount(double amount, int positions)
- {
- if(ShowAmount) {
- if(positions>0) {
- string s = DoubleToAmount(amount,AmountDig) ;
- if(amount>0) s = "+" + s ;
- ObjectSetString(0, AMOUNT_NAME, OBJPROP_TEXT, s);
- if(amount<0)
- ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_COLOR, AMOUNT_CLR_NEGA);
- else
- ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_COLOR, AMOUNT_CLR_POSI);
- }else {
- string s = ObjectGetString(0, AMOUNT_NAME, OBJPROP_TEXT);
- int ln=StringLen(s);
- if(ln>0) {
- if(s[ln-1]!='-')
- ObjectSetString(0, AMOUNT_NAME, OBJPROP_TEXT, s+"-");
- }
- }
- }
- }
- //---------------------------------------------------------------------------
- //MARK:動作チェック
- void CheckBehavior(bool nextTimed)
- {
- // 複利ロット計算
- if(Compounding) {
- double balance = AccountBalance();
- if(BalanceIncludeCredit) balance += AccountCredit();
- Lots = balance*BaseLots/CompoundingBase ;
- if(Lots<MinLots) Lots = MinLots ;
- if(Lots>MaxLots) Lots = MaxLots ;
- }
- // 全体のステータスを取得
- STATUS BuyWholeStatus, SellWholeStatus ;
- for(int n=0;n<2;n++) {
- CheckStatus(OP_BUY, MAGICMA, &BuyWholeStatus);
- BuyWholeStatus.OrdersSort(ORDERSORT_PRICE_ASCEND);
- if(!CheckoutStoplossTrappedOrders(&BuyWholeStatus)) break;
- }
- for(int n=0;n<2;n++) {
- CheckStatus(OP_SELL, MAGICMA, &SellWholeStatus);
- SellWholeStatus.OrdersSort(ORDERSORT_PRICE_DESCEND);
- if(!CheckoutStoplossTrappedOrders(&SellWholeStatus)) break;
- }
- StoplossTrapArray.Clear();
- // 金額を更新
- double CurAmount = BuyWholeStatus.GrossProfit+SellWholeStatus.GrossProfit ;
- int CurPositions = BuyWholeStatus.Positions+SellWholeStatus.Positions ;
- UpdateAmount(CurAmount,CurPositions);
- // 自動処理
- if(Automation) {
- // 最大損益のチェック
- if(CurAmount<0) {
- double balance = AccountBalance();
- if(BalanceIncludeCredit) balance += AccountCredit();
- if(balance*MaxGrosslossPer/100.0<-CurAmount) {
- //最大損益を超えた場合は、すべて決済する
- CheckoutOrders(FLAG_BUY|FLAG_SELL);
- PrintMessage("Check-out orders by over Maximum Gross Loss");
- return;
- }
- }
- // オーダーの処理
- ProcessOrders(nextTimed, OP_BUY, BuyWholeStatus, SellWholeStatus);
- ProcessOrders(nextTimed, OP_SELL, SellWholeStatus, BuyWholeStatus);
- }
- FlushTL=false;
- }
- //---------------------------------------------------------------------------
- //MARK:オーダーの処理
- void ProcessOrders(bool nextTimed, OP orderType, const STATUS &status, const STATUS &revStatus)
- {
- if(status.Positions<=0) return ;
- // トレーリング
- if(Trailing) {
- double tstart = TrailingStart*Point ;
- double tstop = TrailingStop*Point ;
- double minPadding = tstart+tstop ;
- for(int i=0;i<status.OrdersCount();i++) {
- COrderStatus *order = status.OrdersAt(i) ;
- if((order.Tag&STATAG_CHECKEDOUT)!=0) continue ; // 決済済
- if( orderType==OP_BUY ?
- order.Price>Bid-minPadding : order.Price<Ask+minPadding )
- break;
- double sl=0.0 ;
- if( order.Stoploss==0.0 ||
- ( orderType==OP_BUY ?
- order.Stoploss<order.Price : order.Stoploss>order.Price ) ) {
- //初回トレール
- sl = orderType==OP_BUY ? order.Price+tstart : order.Price-tstart ;
- }else {
- //既にトレール済
- sl = order.Stoploss ;
- }
- while( ( orderType==OP_BUY ? Bid-sl : sl-Ask ) >= tstop*2 ) {
- //カクカクにトレール幅を狭めていく
- sl += orderType==OP_BUY ? +tstop : -tstop ;
- }
- if(!InnerPoint(sl,order.Stoploss)) {
- //ストップロスを更新
- if(ModifyOrderSlTp(order.Ticket,sl,order.Takeprofit)) {
- order.Stoploss = sl ;
- EntryStoplossTrap(orderType, order, sl);
- }else PrintLastError();
- }
- }
- }
- // 3EMA処理
- if(MA3 && (nextTimed||FlushTL)) {
- double HalfSpread = (Ask-Bid)/2.0;
- double FastMA0 = iMA(NULL, MainTimeFrame, MA3FastPeriod, MAShift, MAMode, MAPriceType, 0) +HalfSpread ;
- double MediumMA0 = iMA(NULL, MainTimeFrame, MA3MediumPeriod, MAShift, MAMode, MAPriceType, 0) +HalfSpread ;
- double SlowMA0 = iMA(NULL, MainTimeFrame, MA3SlowPeriod, MAShift, MAMode, MAPriceType, 0) +HalfSpread ;
- for(int i=0;i<status.OrdersCount();i++) {
- COrderStatus *order = status.OrdersAt(i) ;
- if((order.Tag&STATAG_CHECKEDOUT)!=0) continue ; // 決済済
- double price = order.Price ;
- double sl = order.Stoploss ;
- double trail_sl=0.0;
- double checkout_denom=0.0;
- string checkout_reason="";
- if(InnerPoint(sl,price)) { // プライスがslに一致
- if(FlushTL&&!nextTimed) continue;
- if(!InnerPoint(MediumMA0,price) &&
- (orderType==OP_BUY?MediumMA0-HalfSpread>price:MediumMA0+HalfSpread<price)) { // Medium MA がプライス以上
- if(orderType==OP_BUY?FastMA0>Ask:FastMA0<Bid) { // Fast MA が現価以上
- // 決済設定
- checkout_denom = LotsDenomMAFast ;
- checkout_reason = "Check-out by Fast MA" ;
- if(orderType==OP_BUY?MediumMA0>Ask:MediumMA0<Bid) // Medium MA が現価より上
- { checkout_reason += " & Medium MA"; checkout_denom = 1.0 ;} // 全決済する
- // ストップロスを Medium MA 値に更新する
- trail_sl = MediumMA0 + (orderType==OP_BUY?-HalfSpread:+HalfSpread) ;
- }
- }
- }else if(sl!=0.0&&(orderType==OP_BUY?sl>price:sl<price)) { //プライスがslより下
- if(FlushTL&&!nextTimed) continue;
- if(orderType==OP_BUY?Ask<=MediumMA0:Bid>=MediumMA0) { //現価が Medium MA より下になった
- // 決済設定
- checkout_denom = 1.0 ; // 全決済
- checkout_reason = "Check-out by Medium MA" ;
- }
- }else { //プライスがslより上、もしくは、slが設定されていない
- if(FlushTL||MA3TLPeriod>0) { // TL(TimeLimited) ポジションが有効
- //ロウソク足の期間を計測
- /* 旧方式
- datetime tperiod = MainPeriod() * 60 ;
- int period = int((CurTime-order.OpenTime)/tperiod);
- bool overTime = period>=MA3TLPeriod-1 ;
- */
- // 新方式
- int period = iBarShift(_Symbol, MainTimeFrame, order.OpenTime);
- bool overTime = period>=MA3TLPeriod ;
- if(FlushTL||overTime) { //TL(TimeLimited)期間が過ぎている
- if(orderType==OP_BUY?Bid>price:Ask<price) { // 利確できる位置にある
- if(!FlushTL&&(orderType==OP_BUY?FastMA0>Ask||MediumMA0>Ask:FastMA0<Bid||MediumMA0<Bid)) { // 2MA が現価より上
- // 現価が 2MA を抜かすまでの間、ストップロスを建値ギリギリまで引き上げておく
- trail_sl = price + (orderType==OP_BUY?-Point:+Point);
- }else { // FastMA が現価以下
- // 決済設定
- checkout_denom = LotsDenomTL ;
- checkout_reason = "Check-out by TL(TimeLimited)" ;
- // ストップロスを建値に引き上げる
- trail_sl = price ;
- }
- }
- }
- }
- if(!FlushTL||nextTimed) {
- if(sl==0.0) { //ストップロスが設定されていない
- if(MaxGrosslossPer>=100.0) { // Max Gross loss が 100%以上
- if(orderType==OP_BUY?Ask<=SlowMA0:Bid>=SlowMA0) { //現価が Slow MA より下になった
- // 損切設定
- checkout_denom = 1.0 ; // 全決済
- checkout_reason = "Loss-cut order by Slow MA" ;
- }
- }
- }
- }
- }
- if(trail_sl!=0.0) {
- //MAによるトレーリング
- if(sl==0.0||(!InnerPoint(sl,trail_sl)&&(orderType==OP_BUY?sl<trail_sl:sl>trail_sl))) {
- sl = trail_sl ;
- if(ModifyOrderSlTp(order.Ticket,sl,order.Takeprofit)) {
- order.Stoploss = sl ;
- EntryStoplossTrap(orderType, order, sl);
- }else PrintLastError();
- }
- }
- if(checkout_denom>0.0) {
- //MAによる決済処理
- double lots = AdjLots(order.Lots/checkout_denom) ;
- if(lots<MinLots) lots = MinLots ;
- if(lots>order.Lots) lots = order.Lots ;
- if(CheckoutOrder(orderType,order.Ticket,lots)) {
- PrintMessage(checkout_reason);
- order.Lots -= lots ;
- if(order.Lots<=0)
- order.Tag |= STATAG_CHECKEDOUT ; // 決済済
- }
- }
- }
- }
- }
- //---------------------------------------------------------------------------
- //マニュアルポジション発注
- TICKET EntryManualPosition(string detector, OP entryType, double lots)
- {
- double sl=0.0, tp=0.0;
- switch(entryType) {
- case OP_BUY:
- if(Stoploss!=0.0) sl = Ask-Stoploss*Point ;
- if(Takeprofit!=0.0) tp = Ask+Takeprofit*Point ;
- break;
- case OP_SELL:
- if(Stoploss!=0.0) sl = Bid+Stoploss*Point ;
- if(Takeprofit!=0.0) tp = Bid-Takeprofit*Point ;
- break;
- }
- if(sl==0.0) {
- if(MaxGrosslossPer>=100.0) {
- // SlowMAの現在位置がAsk/Bidよりも上回っていないことを確認する
- double HalfSpread = (Ask-Bid)/2.0;
- double SlowMA0 = iMA(NULL, MainTimeFrame, MA3SlowPeriod, MAShift, MAMode, MAPriceType, 0) +HalfSpread ;
- if(entryType==OP_BUY?SlowMA0>=Ask:SlowMA0<=Bid) {
- PrintMessage("Entring failed due to Slow MA over price reached");
- return -1 ; // invalid
- }
- }
- }
- return MakeOrder(entryType,lots,sl,tp,detector,MAGICMA);
- }
- //---------------------------------------------------------------------------
- //マジックナンバーと一致する全オーダーのチェックアウト
- void CheckoutOrders(FLAG flag)
- {
- CheckoutOrderAll(flag,MAGICMA);
- }
- //---------------------------------------------------------------------------
- // オーダーを StoplossTrapArray に登録
- bool EntryStoplossTrap(OP type, const COrderStatus *order, double stoploss=0)
- {
- if(stoploss==0) stoploss = order.Stoploss ;
- if(stoploss==0) return false ;
- OBJECT_PARTCLOSED part(order.Ticket,type,order.Price,order.OpenTime,stoploss);
- int idx = SearchSortedArray(StoplossTrapArray,part);
- if(idx>=0) { // 既にエントリ済
- CSortable<OBJECT_PARTCLOSED>* obj =
- (CSortable<OBJECT_PARTCLOSED>*)StoplossTrapArray.At(idx) ;
- obj.v.Stoploss = stoploss ; // ストップロスの値を更新
- }else { // 新規エントリ
- AddToSortedArray(StoplossTrapArray,part);
- }
- return true ;
- }
- //---------------------------------------------------------------------------
- // オーダーのストップロスが前回登録したストップロス情報と一致しているか調べる
- bool CheckStoplossTrap(OP type, const COrderStatus *order, double stoploss=0)
- {
- if(stoploss==0) stoploss = order.Stoploss ;
- if(stoploss==0) return true ; // 無視
- OBJECT_PARTCLOSED part(order.Ticket,type,order.Price,order.OpenTime,stoploss);
- int idx = SearchSortedArray(StoplossTrapArray,part);
- if(idx>=0) { // 既にエントリ済
- CSortable<OBJECT_PARTCLOSED>* obj =
- (CSortable<OBJECT_PARTCLOSED>*)StoplossTrapArray.At(idx) ;
- return InnerPoint(obj.v.Stoploss, stoploss); // ストップロスの一致を返す
- }
- return true ; // エントリされていないので無視
- }
- //---------------------------------------------------------------------------
- // ストップロスが更新されていないオーダーを全て決済する
- int CheckoutStoplossTrappedOrders(STATUS *status)
- {
- int n=0;
- for(int i=status.OrdersCount()-1;i>=0;i--) {
- COrderStatus *order = status.OrdersAt(i);
- if((order.Tag&STATAG_CHECKEDOUT)!=0) continue ;
- if(!CheckStoplossTrap(status.Type,order)) {
- if(CheckoutOrder(status.Type,order.Ticket,order.Lots)) {
- order.Lots = 0 ;
- order.Tag |= STATAG_CHECKEDOUT ;
- PrintMessage("Checkout Order by ST(StoplossTrapped)");
- n++;
- }
- }
- }
- return n;
- }
- //---------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment