HYROLEAN

test_3ma_user_v3.mq5

Apr 24th, 2026 (edited)
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 59.20 KB | Money | 0 0
  1. // test_3ma_user_v3.mq5 (資金率換算版)
  2. //   by 2024-2026 (c)hyrolean
  3. //---------------------------------------------------------------------------
  4. #property copyright "2024-2026, (c)hyrolean"
  5. #property link      "https://pastebin.com/DvK0GaRg"
  6. #property version   "3.02"
  7.  
  8. #include <User/hyrDefs.mqh>    // https://pastebin.com/iHZKAWqC
  9. #include <User/hyrTmpl.mqh>    // https://pastebin.com/LG1vurny
  10. #include <User/hyrGlobal.mqh>  // https://pastebin.com/2PdBW6NQ
  11. #include <User/hyrIQueue.mqh>  // https://pastebin.com/3pRKTce4
  12. #include <User/hyrStatus.mqh>  // https://pastebin.com/d9Z8P2qD
  13.  
  14.   // version 3.02
  15.   //  - エントリ時の初期手数料の値幅換算が狂っていたバグを修正
  16.  
  17.   // version 3.01
  18.   //  - CalcLotsFromSlDistance のロット計算方法を改訂(TYPE-II)
  19.  
  20.   // version 3.00
  21.   //  - OrderMethod input項目を追加
  22.   //  - Compounding(複利関連) input項目を削除し、RTPer(資金率) input項目を追加
  23.  
  24.   // version 2.03
  25.   //  - 初期手数料が勘定されない仕様のサーバーに対応
  26.  
  27.   // version 2.02
  28.   //  - 建値移動する際に手数料(スワップを除く)分を加味する工程を追加
  29.  
  30.   // version 2.01
  31.   //  - AmountDig input項目を削除
  32.  
  33.   // version 2.00
  34.   //  - ユーザーロット調整機能を追加
  35.   //  - 約定が失敗した際に音とエラーメッセージで知らせる処理を追加
  36.   //  - 主要関数を自作ライブラリに置換えてコンパクト化
  37.  
  38. /*
  39.  
  40.  3EMA 手法 ( 状態遷移情報をターミナルに格納する変数を必要としないバージョン )
  41.  
  42.  ・ 建玉するときに、EMA50をストップロスに設定する(Stoploss=0の場合)
  43.  
  44.     ※ 現在価格がEMA50を下回るところでは、建玉を行わないようにする
  45.  
  46.  ・ ストップロスが玉の価格より下にあるものに的を絞り、EMA50を基準にトレーリングを行う
  47.  
  48.     ※ ただし、玉の価格がEMA50より下にある場合は、上記の操作を見送ることとする
  49.  
  50.  ・ ストップロスが玉の価格より下にあるものに的を絞り、ロウソク足が5期間経過後から、
  51.    現在のプライスが超えた時点でストップロスをエントリープライスに移動し、ロットの1/3を利確する
  52.  
  53.    ロウソク足の期間の出し方:
  54.      Bars(_Symbol, MainTimeFrame, <建玉時刻>, <現在時刻>)>=5
  55.  
  56.     ※ 5期間経過後に未だ現価が下にある場合は、現価が上に来るまでこの試行は継続
  57.       されることとし、現価がロウソク足1期間でも抜けたら即ストップロスをエントリープライスに移動
  58.       し、ロットの1/3利確することとする
  59.  
  60.  ・ 現在価格がEMA10を下回った場合、ストップロスがエントリープライスに一致する玉を検出し、
  61.    EMA20の位置にストップロスを移動し、ロットの1/2を利確する(この時点でEMA20も現在価格
  62.    を突破している場合は、全ロットを利確することとする)
  63.  
  64.     ※ ただし、玉の価格がEMA20より上にある場合は、上記の操作を見送ることとする
  65.  
  66.  ・ ストップロスが玉の価格より上にあるものに的を絞り、EMA20を基準にトレーリングを行う
  67.  
  68. */
  69.  
  70. /*
  71.  
  72.   使い方::
  73.  
  74.   1 クリック 約定モード: ( Order method on user entry = 1 click )
  75.  
  76.     左上の|SELL|BUY|ボタンを選ぶと即座に約定されます。
  77.     ポジションを打ったら、S/L(ストップロス)のBARを自分の好みの場所に移動させます。
  78.  
  79.   2 ステップ約定モード: ( Order method on user entry = 2 steps )
  80.  
  81.     左上の|SELL|BUY|ボタンを押すと、S/Lの赤いラインと|ENTRY|ボタンが表示されます。
  82.     赤いラインをドラッグしてS/Lの位置を決めてから、|ENTRY|ボタンを押すと約定されます。
  83.     約定前に取消する場合は、凹んでいる|SELL|BUY|ボタンをもう一度押してください。
  84.  
  85.   ロット数は最後の表記が'-'になっている場合は、資金率に応じて自動計算されます。
  86.   自分でロット数を決め打ちする場合は、最後の'-'を省いてから入力してください。
  87.   決め打ちのロット数から自動計算に戻す場合は、'-'だけをロット欄に入力してください。
  88.  
  89.   以降、3EMAの手法に従って自動的に利確されます。(逆行しなければですが…)
  90.   運悪く逆行してしまった場合は、損益の㌫、または、slに応じて自動損切されます。
  91.  
  92.   エントリーのコツとしては、上から現在価格,EMA10,EMA20,EMA50の順番で並んでいるときは、
  93.   ロング(買い)、逆に、上からEMA50,EMA20,EMA10,現在価格の順番で並んでいるときは、
  94.   ショート(売り)でエントリーすると上手くいくかもしれないです。
  95.  
  96.   (利確のタイミングを図りたい場合など、自動処理を一時的に中断したい場合は、Automate
  97.   Processing Orders をfalseに設定すると無効に出来ます。)
  98.  
  99.   MT5を閉じてもslとエントリープライスの位置だけで状態を把握する為、万が一VPS等が停止し
  100.   てしまってもサーバー側に建玉の情報さえ残っていればMT5を再度立ち上げてこのEAを有
  101.   効化するだけで状態復帰可能な仕様に仕上げています。
  102.  
  103.   以上ゞ
  104.  
  105. */
  106.  
  107. /*
  108.  
  109.   手数料の書き方::
  110.  
  111.    例1) 手数料が往復6ドルかかるサーバーを利用する場合:
  112.  
  113.       Initial Commission JPY per lot は、0.0 のまま
  114.       Initial Commission USD per lot に、6.0 と記述
  115.  
  116.    例2) 手数料が往復400円かかるサーバーを利用する場合:
  117.  
  118.       Initial Commission JPY per lot に、400.0 と記述
  119.       Initial Commission USD per lot は、0.0 のまま
  120.  
  121.    口座がドル建て円建てに関わらず、約定時にレートを拾ってきて自動換算されます。
  122.    通貨変換時に使用する通貨シンボルは、自動検索されますが、上手くいかない場合は、
  123.  
  124.       USDJPY Symbol name に USDJPY.raw や USDJPYp などの
  125.  
  126.    サーバーが保持している通貨名を直接入力してみてください。
  127.  
  128. */
  129.  
  130. #define ENTRY_NAME "3MAUserV3"
  131. #define ORDER_RETRY 10
  132. #define ORDER_RETRY_SLEEP 100
  133. #define ORDER_RETRY_DURATION 1000
  134.  
  135. enum ENUM_POSI {
  136.   POSI_STOP,                  // Stop
  137.   POSI_ONLY_LONG,             // Only Long
  138.   POSI_ONLY_SHORT,            // Only Short
  139.   POSI_HALF_LONG_AND_SHORT,   // Long & Short (Half duplex)
  140.   POSI_FULL_LONG_AND_SHORT    // Long & Short (Full duplex)
  141. };
  142.  
  143. enum ENUM_ORDERMETHOD {
  144.   ORDERMETHOD_ONE_CLICK,  // 1 click
  145.   ORDERMETHOD_TWO_STEPS   // 2 steps ( S/L move -> entry )
  146. };
  147.  
  148. enum ENUM_RTCALCTYPE {
  149.   RTCALCTYPE_I,           // TYPE-I ( Calculate with SYMBOL_TRADE_... )
  150.   RTCALCTYPE_II           // TYPE-II ( Use OrderCalcProfit function )
  151. };
  152.  
  153. #define STATAG_CHECKEDOUT 1
  154.  
  155. // ※ wine 環境だと文字化けする為、英字表記にしています
  156. input group "GENERAL"
  157. input bool      Automation      = true;     // Automate processing orders
  158. input ENUM_TIMEFRAMES MainTimeFrame = PERIOD_CURRENT; // Main Time Frame
  159. input MAGIC MAGICMA             = 0;        // Magic Number
  160. input group "TIME CONTROL"
  161. input bool      TimeControl     = false;    // Time Control
  162. input ENUM_TIMEBASE TimeBase    = TIMEBASE_LOCAL; // Time Base
  163. input string    TimeStart       = "09:00";  // Time Start
  164. input string    TimeEnd         = "15:00";  // Time End
  165. input ENUM_TIMEACT TimeAction   = TIMEACT_NONE; // Time Action when time end reached
  166. input group "3MA"
  167. input ENUM_MA_METHOD      MAMode= MODE_EMA; // MA mode
  168. input ENUM_APPLIED_PRICE  MAPriceType = PRICE_CLOSE; // MA price type
  169. input bool      MA3             = true;     // 3MA Enabled
  170. input int       MA3FastPeriod   = 10;       // 3MA Fast period
  171. input int       MA3MediumPeriod = 20;       // 3MA Medium period
  172. input int       MA3SlowPeriod   = 50;       // 3MA Slow period
  173. input int       MA3TLPeriod     = 5;        // 3MA TL(TimeLimited) period
  174. input group "ORDER"
  175. input int       Slippage        = 10;       // Max Slippage
  176. input int       Spread          = 50;       // Max Spread in points
  177. //input double    BaseLots        = 0.1;      // Base Lots
  178. input double    StepLots        = 0.01;     // Step Lots
  179. input double    MinLots         = 0.01;     // Minimum Lots
  180. input double    MaxLots         = 50.0;     // Maximum Lots
  181. input double    LotsDenomTL     = 3.0;      // Lots denom of 3MA TL(TimeLimited)
  182. input double    LotsDenomMAFast = 2.0;      // Lots denom of 3MA Fast MA
  183. input double    Takeprofit      = 0;        // Take profit in points (0 = unlimited)
  184. input double    Stoploss        = 100;      // Stop loss in points (0 = Grossloss per or SlowMA trail)
  185. input ENUM_ORDERMETHOD OrderMethod = ORDERMETHOD_TWO_STEPS; // Order method on user entry
  186. input group "BALANCE"
  187. input double    RTPer           = 2.0;      // Risk per Trade in percentage (資金率%)
  188. input ENUM_RTCALCTYPE RTCalcType = RTCALCTYPE_II; // Risk per Trade calculation type
  189. input double    MaxGrosslossPer = 80.0;     // Maximum Allowed Gross loss of Balance in percentage (EAの許容損失率%)
  190. input double    MaxDrawDownPer  = 80.0;     // Maximum Allowed Draw down of Balance in percentage (口座の許容損失率%)
  191. //input bool      Compounding     = false;    // Compounding interest Enabled
  192. //input double    CompoundingBase = 100000;   // Compounding Base Balance (Lots=BaseLots*Balance/BaseBalance)
  193. input bool      BalanceIncludeCredit= true; // Balance include Credit (資金の計算にボーナスを加味するかどうか)
  194. input double    InitialCommissionJPY = 0.0; // Initial Commission JPY per lot (1ロットあたりの初期手数料[JPY通貨単位])
  195. input double    InitialCommissionUSD = 0.0; // Initial Commission USD per lot (1ロットあたりの初期手数料[USD通貨単位])
  196. input string    USDJPYSymbolName = "";      // USDJPY Symbol name (USDJPY相互変換に使う通貨の名前[空の場合は自動検索])
  197. input group "TRAILING"
  198. input bool      Trailing        = false;    // Trailing Enabled
  199. input double    TrailingStart   = 300;      // Trailing Start in points
  200. input double    TrailingStop    = 200;      // Trailing Stop in points
  201. input group "APPEARANCE"
  202. input bool      ShowUserEntry   = true;     // Show user entry SELL/BUY buttons
  203. input bool      ShowCloseAll    = true;     // Show a CLOSE ALL button
  204. input bool      ShowCloseLong   = false;    // Show a CLOSE LONG button
  205. input bool      ShowCloseShort  = false;    // Show a CLOSE SHORT button
  206. input bool      ShowFlushTL     = true;     // Show a FLUSH TL button
  207. input bool      ShowBEP         = false;    // Show BEP ( Break Even Price )
  208. input bool      ShowAmount      = true;     // Show Current Amount
  209. //input int       AmountDig       = 0;        // Amount Number of decimal places
  210. input color     ClrAmountPosi   = clrLightGoldenrod; // Amount Positive color
  211. input color     ClrAmountNega   = clrLightPink; // Amount Negative color
  212. input color     ClrTimeControl  = clrYellow; // Time Control Status color
  213. input color     ClrBEPLong      = clrSteelBlue; // Long BEP color
  214. input color     ClrBEPShort     = clrMediumPurple; // Short BEP color
  215. input color     ClrUserStoploss = clrRed;    // User entry Stoploss color
  216. input color     ClrUserTakeprofit=clrOrange; // User entry Takeprofit color
  217. input group "DEBUGGING"
  218. input bool      DBGMODE         = true;     // DEBUG MODE
  219.  
  220. //===========================================================================
  221. // 型
  222. //---------------------------------------------------------------------------
  223. // OBJECT_PARTCLOSED
  224. struct OBJECT_PARTCLOSED {
  225.   TICKET Ticket;
  226.   OP Type;
  227.   double Price;
  228.   double Stoploss;
  229.   datetime Time;
  230.   OBJECT_PARTCLOSED(TICKET Ticket_, OP Type_, double Price_, datetime Time_, double Stoploss_=0) {
  231.     Ticket = Ticket_ ;
  232.     Type = Type_ ;
  233.     Price = Price_ ;
  234.     Time = Time_ ;
  235.     Stoploss = Stoploss_ ;
  236.   }
  237.   OBJECT_PARTCLOSED(const OBJECT_PARTCLOSED &src) {
  238.     Ticket = src.Ticket ;
  239.     Type = src.Type ;
  240.     Price = src.Price ;
  241.     Time = src.Time ;
  242.     Stoploss = src.Stoploss ;
  243.   }
  244.   bool operator <(const OBJECT_PARTCLOSED &rhs) const {
  245.     //if(Ticket < rhs.Ticket) return true ;
  246.     if(Type < rhs.Type) return true ;
  247.     if(Price < rhs.Price) return true ;
  248.     if(Time < rhs.Time) return true ;
  249.     return false ;
  250.   }
  251. };
  252.  
  253. //===========================================================================
  254.  
  255. double UserLots, Lots, CurBid, CurAsk, PrevBid, PrevAsk;
  256.  
  257. #define MAShift 0
  258.  
  259. datetime CurTime, TimeTick, StartTime, CancelTime, UserTime;
  260.  
  261. FLAG UserEntry = 0, UserMode = 0 ;
  262. double UserStoploss=0.0, UserTakeprofit=0.0;
  263. bool FlushTL = false ;
  264.  
  265. ENUM_ORDERMETHOD UserMethod ;
  266. int UserEntryBtnYPos = 0 ;
  267.  
  268. // オーダーの状態
  269. STATUS BuyWholeStatus(OP_BUY,MAGICMA,InitialCommissionJPY,InitialCommissionUSD,USDJPYSymbolName);
  270. STATUS SellWholeStatus(OP_SELL,MAGICMA,InitialCommissionJPY,InitialCommissionUSD,USDJPYSymbolName);
  271.  
  272. // サーバーがストップロスを更新しなかった場合のトラップ対策用配列
  273. CArrayObj *StoplossTrapArray = NULL;
  274.  
  275. #define LOTSED_NAME        "EntryLots"
  276. #define LOTSDEC_NAME       "LotsDecBtn"
  277. #define LOTSINC_NAME       "LotsIncBtn"
  278. #define SELLBTN_NAME       "EntrySell"
  279. #define BUYBTN_NAME        "EntryBuy"
  280. #define ENTRYBTN_NAME      "EntryDecide"
  281. #define SLLINE_NAME        "EntrySL"
  282. #define TPLINE_NAME        "EntryTP"
  283. #define CLOSEALLBTN_NAME   "CloseAll"
  284. #define CLOSELONGBTN_NAME  "CloseLong"
  285. #define CLOSESHORTBTN_NAME "CloseShort"
  286. #define FLUSHTLBTN_NAME    "FlushTL"
  287.  
  288. #define LOTSSAVE_NAME      (ENTRY_NAME "_UserLots_" + Symbol())
  289.  
  290. #define OFFTIME_NAME "OFF TIME"
  291. bool OffTimeVisible = false ;
  292.  
  293. #define AMOUNT_NAME "AMOUNT"
  294. #define AMOUNT_CLR_NEGA  ClrAmountNega
  295. #define AMOUNT_CLR_POSI  ClrAmountPosi
  296.  
  297. #define DBGINFO_NAME "DEBUG INFO"
  298.  
  299.   double AdjLots(double lots) {
  300.     lots = AdjustMarketLots(lots);
  301.     double roundLots = MathRound( MathMax(lots,StepLots) / StepLots ) ;
  302.     return MathMin(MathMax(roundLots*StepLots,MinLots),MaxLots) ;
  303.   }
  304.  
  305.   double GetBid() { return SymbolInfoDouble(_Symbol, SYMBOL_BID); }
  306.  
  307.   double GetAsk() { return SymbolInfoDouble(_Symbol, SYMBOL_ASK); }
  308.  
  309. //--- IQueue MA (3本分)
  310. CHyrIQueueMA QiFastMA, QiMediumMA, QiSlowMA;
  311.  
  312. //--- IQueue ATR14 (デバッグ用)
  313. CHyrIQueueATR QiATR14;
  314.  
  315. //---------------------------------------------------------------------------
  316. int OnInit()
  317. {
  318.   //テスターで表示されるインジケータを非表示にする
  319.   TesterHideIndicators(!DBGMODE);
  320.  
  321.   //--- IQueue MA 初期化(3本分)
  322.   int qsize = MA3SlowPeriod * 3; // 余裕を持ったキューサイズ
  323.   if(!QiFastMA.Init  (_Symbol, MainTimeFrame, MA3FastPeriod,   MAMode, MAPriceType, qsize) ||
  324.     !QiMediumMA.Init(_Symbol, MainTimeFrame, MA3MediumPeriod, MAMode, MAPriceType, qsize) ||
  325.     !QiSlowMA.Init  (_Symbol, MainTimeFrame, MA3SlowPeriod,   MAMode, MAPriceType, qsize))
  326.     return INIT_FAILED;
  327.  
  328.   //--- IQueue ATR 14 (デバッグ用)
  329.   if(!QiATR14.Init     (_Symbol, PERIOD_CURRENT, 14, 2))
  330.     return INIT_FAILED;
  331.  
  332.   CurTime = MainTime();
  333.   TimeTick = StartTime = CancelTime = UserTime = BaseTime(TimeBase);
  334.  
  335.   GlobalSettings(
  336.     ENTRY_NAME,
  337.     Slippage,
  338.     Spread,
  339.     ORDER_RETRY,
  340.     ORDER_RETRY_SLEEP,
  341.     ORDER_RETRY_DURATION );
  342.  
  343.   bool LotsLoaded = false ;
  344.   if(GlobalVariableCheck(LOTSSAVE_NAME)) {
  345.     UserLots = GlobalVariableGet(LOTSSAVE_NAME);
  346.     LotsLoaded = true ;
  347.   }
  348.  
  349.   UserLots = AdjLots(UserLots);
  350.   Lots = CalcLotsFromSlDistance(Stoploss,true) ;
  351.   CurBid=PrevBid = GetBid() ;
  352.   CurAsk=PrevAsk = GetAsk() ;
  353.  
  354.   UserMethod = OrderMethod ;
  355.   if(UserMethod==ORDERMETHOD_TWO_STEPS) {
  356.     if(Stoploss<=0.0) { // ストップロスがゼロ以下では2ステップモードの発動は不可能
  357.       PrintMessage("Order method on user entry was force set to 1 click due to stoploss<=0");
  358.       UserMethod = ORDERMETHOD_ONE_CLICK;
  359.     }
  360.   }
  361.  
  362.   //ストップロス更新確認用配列
  363.   StoplossTrapArray = new CArrayObj();
  364.   StoplossTrapArray.Sort(ARRAY_SORT_ASCEND);
  365.  
  366.   //DEBUG INFO
  367.   if(DBGMODE) {
  368.     ObjectCreate(0, DBGINFO_NAME, OBJ_LABEL, 0, 0, 0);
  369.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_XDISTANCE, 10);
  370.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_YDISTANCE, 15);
  371.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
  372.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
  373.     ObjectSetString (0, DBGINFO_NAME, OBJPROP_TEXT, "DEBUG INFO");
  374.     ObjectSetString (0, DBGINFO_NAME, OBJPROP_FONT, "Verdana");
  375.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_FONTSIZE, 8);
  376.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_COLOR, clrAquamarine);
  377.   }
  378.  
  379.   //金額表示
  380.   if(ShowAmount) {
  381.     ObjectCreate(0, AMOUNT_NAME, OBJ_LABEL, 0, 0, 0);
  382.     ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_XDISTANCE, 20);
  383.     ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_YDISTANCE, 35);
  384.     ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
  385.     ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
  386.     ObjectSetString (0, AMOUNT_NAME, OBJPROP_TEXT, "0-");
  387.     ObjectSetString (0, AMOUNT_NAME, OBJPROP_FONT, "Verdana");
  388.     ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_FONTSIZE, 15);
  389.     ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_COLOR, ClrAmountPosi);
  390.   }
  391.  
  392.   const int z_order = 1 ;
  393.  
  394.   //ユーザーエントリ用ボタン
  395.   if(ShowUserEntry) {
  396.  
  397.     int edit_y_pos = 20;
  398.     int btn_y_pos  = edit_y_pos + 24;
  399.  
  400.     // < 減らすボタン
  401.     ObjectCreate(0, LOTSDEC_NAME, OBJ_BUTTON, 0, 0, 0);
  402.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_XDISTANCE, 10);
  403.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_YDISTANCE, edit_y_pos);
  404.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_XSIZE, 20);
  405.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_YSIZE, 20);
  406.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  407.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
  408.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_FONTSIZE, 10);
  409.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_COLOR, clrWhite);
  410.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_BGCOLOR, clrDimGray);
  411.     ObjectSetInteger(0, LOTSDEC_NAME, OBJPROP_ZORDER, z_order);
  412.     ObjectSetString (0, LOTSDEC_NAME, OBJPROP_TEXT, "<");
  413.     ObjectSetString (0, LOTSDEC_NAME, OBJPROP_FONT, "Verdana");
  414.  
  415.     // エディットボックス
  416.     ObjectCreate(0, LOTSED_NAME, OBJ_EDIT, 0, 0, 0);
  417.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_XDISTANCE, 31);
  418.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_YDISTANCE, edit_y_pos);
  419.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_XSIZE, 66);
  420.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_YSIZE, 20);
  421.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  422.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
  423.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_ZORDER, z_order);
  424.     ObjectSetString (0, LOTSED_NAME, OBJPROP_TEXT, DoubleToString(UserLots,2)+(LotsLoaded?"":"-"));
  425.     ObjectSetInteger(0, LOTSED_NAME, OBJPROP_ALIGN, ALIGN_CENTER);
  426.     ObjectSetString(0, LOTSED_NAME, OBJPROP_TOOLTIP,
  427.       "Enter the lot size\n"
  428.       "Press the < > button, then dec/inc lots step by " + DoubleToString(StepLots, 2) + "\n"
  429.       "NOTE: It will be adjusted to the R/T lots if the text ends with a '-'" );
  430.  
  431.     // > 増やすボタン
  432.     ObjectCreate(0, LOTSINC_NAME, OBJ_BUTTON, 0, 0, 0);
  433.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_XDISTANCE, 98);
  434.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_YDISTANCE, edit_y_pos);
  435.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_XSIZE, 20);
  436.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_YSIZE, 20);
  437.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  438.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
  439.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_FONTSIZE, 10);
  440.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_COLOR, clrWhite);
  441.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_BGCOLOR, clrDimGray);
  442.     ObjectSetInteger(0, LOTSINC_NAME, OBJPROP_ZORDER, z_order);
  443.     ObjectSetString (0, LOTSINC_NAME, OBJPROP_TEXT, ">");
  444.     ObjectSetString (0, LOTSINC_NAME, OBJPROP_FONT, "Verdana");
  445.  
  446.     //SELLボタン
  447.     ObjectCreate(0, SELLBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  448.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_XDISTANCE, 10);
  449.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_YDISTANCE, btn_y_pos);
  450.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_XSIZE, 53);
  451.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_YSIZE, 27);
  452.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  453.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
  454.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_FONTSIZE, 12);
  455.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_COLOR, White);
  456.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_BGCOLOR, clrFireBrick);
  457.     ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_ZORDER, z_order);
  458.     ObjectSetString(0, SELLBTN_NAME, OBJPROP_TEXT, "SELL");
  459.     ObjectSetString(0, SELLBTN_NAME, OBJPROP_FONT, "Verdana");
  460.  
  461.     //BUYボタン
  462.     ObjectCreate(0, BUYBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  463.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_XDISTANCE, 65);
  464.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_YDISTANCE, btn_y_pos);
  465.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_XSIZE, 53);
  466.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_YSIZE, 27);
  467.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  468.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
  469.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_FONTSIZE, 12);
  470.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_COLOR, White);
  471.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_BGCOLOR, clrRoyalBlue);
  472.     ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_ZORDER, z_order);
  473.     ObjectSetString(0, BUYBTN_NAME, OBJPROP_TEXT, "BUY");
  474.     ObjectSetString(0, BUYBTN_NAME, OBJPROP_FONT, "Verdana");
  475.  
  476.     UserEntryBtnYPos = btn_y_pos+30 ;
  477.   }
  478.  
  479.   int btn_ofs_x = 0 ;
  480.   const int btn_distance = 102 ;
  481.  
  482.   //全決済ボタン
  483.   if(ShowCloseAll) {
  484.     ObjectCreate(0, CLOSEALLBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  485.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x);
  486.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_YDISTANCE, 35);
  487.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_XSIZE, 100);
  488.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_YSIZE, 25);
  489.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_LOWER);
  490.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
  491.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_FONTSIZE, 10);
  492.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_COLOR, clrWhite);
  493.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_BGCOLOR, clrDarkSlateGray);
  494.     ObjectSetInteger(0, CLOSEALLBTN_NAME, OBJPROP_ZORDER, z_order);
  495.     ObjectSetString (0, CLOSEALLBTN_NAME, OBJPROP_TEXT, "CLOSE ALL");
  496.     ObjectSetString (0, CLOSEALLBTN_NAME, OBJPROP_FONT, "Verdana");
  497.     btn_ofs_x += btn_distance;
  498.   }
  499.  
  500.   //LONG決済ボタン
  501.   if(ShowCloseLong) {
  502.     ObjectCreate(0, CLOSELONGBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  503.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x);
  504.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_YDISTANCE, 35);
  505.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_XSIZE, 100);
  506.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_YSIZE, 25);
  507.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_LOWER);
  508.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
  509.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_FONTSIZE, 10);
  510.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_COLOR, clrWhite);
  511.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_BGCOLOR, clrRoyalBlue);
  512.     ObjectSetInteger(0, CLOSELONGBTN_NAME, OBJPROP_ZORDER, z_order);
  513.     ObjectSetString (0, CLOSELONGBTN_NAME, OBJPROP_TEXT, "CLOSE LONG");
  514.     ObjectSetString (0, CLOSELONGBTN_NAME, OBJPROP_FONT, "Verdana");
  515.     btn_ofs_x += btn_distance;
  516.   }
  517.  
  518.   //SHORT決済ボタン
  519.   if(ShowCloseShort) {
  520.     ObjectCreate(0, CLOSESHORTBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  521.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x);
  522.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_YDISTANCE, 35);
  523.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_XSIZE, 100);
  524.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_YSIZE, 25);
  525.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_LOWER);
  526.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
  527.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_FONTSIZE, 10);
  528.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_COLOR, clrWhite);
  529.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_BGCOLOR, clrFireBrick);
  530.     ObjectSetInteger(0, CLOSESHORTBTN_NAME, OBJPROP_ZORDER, z_order);
  531.     ObjectSetString (0, CLOSESHORTBTN_NAME, OBJPROP_TEXT, "CLOSE SHORT");
  532.     ObjectSetString (0, CLOSESHORTBTN_NAME, OBJPROP_FONT, "Verdana");
  533.     btn_ofs_x += btn_distance;
  534.   }
  535.  
  536.   //TLフラッシュ決算ボタン
  537.   if(ShowFlushTL) {
  538.     ObjectCreate(0, FLUSHTLBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  539.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_XDISTANCE, 10 + btn_ofs_x);
  540.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_YDISTANCE, 35);
  541.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_XSIZE, 100);
  542.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_YSIZE, 25);
  543.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_LOWER);
  544.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
  545.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_FONTSIZE, 10);
  546.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_COLOR, clrWhite);
  547.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_BGCOLOR, clrDarkSlateBlue);
  548.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_ZORDER, z_order);
  549.     ObjectSetString (0, FLUSHTLBTN_NAME, OBJPROP_TEXT, "FLUSH TL");
  550.     ObjectSetString (0, FLUSHTLBTN_NAME, OBJPROP_FONT, "Verdana");
  551.   }
  552.  
  553.   //ユーザーエントリをリセット
  554.   UserEntry=0;
  555.  
  556.   return(INIT_SUCCEEDED);
  557. }
  558. //---------------------------------------------------------------------------
  559. void OnDeinit(const int reason)
  560. {
  561.   if(ShowBEP) BEPDelete(FLAG_BUY|FLAG_SELL,true);
  562.   if(ShowFlushTL) ObjectDelete(0, FLUSHTLBTN_NAME);
  563.   if(ShowCloseShort) ObjectDelete(0, CLOSESHORTBTN_NAME) ;
  564.   if(ShowCloseLong) ObjectDelete(0, CLOSELONGBTN_NAME) ;
  565.   if(ShowCloseAll) ObjectDelete(0, CLOSEALLBTN_NAME) ;
  566.   if(ShowUserEntry) {
  567.     LeaveUserOrdering();
  568.     string lots_str = ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT) ;
  569.     int ln = StringLen(lots_str);
  570.     if(ln>0) {
  571.       if(lots_str[ln-1]=='-') {
  572.         if(GlobalVariableCheck(LOTSSAVE_NAME))
  573.           GlobalVariableDel(LOTSSAVE_NAME);
  574.       }else {
  575.         double lots = StringToDouble(lots_str);
  576.         if(lots>0) {
  577.           lots = AdjLots(lots) ;
  578.           if(UserLots!=lots) {
  579.             UserLots = lots ;
  580.             GlobalVariableSet(LOTSSAVE_NAME, UserLots);
  581.           }
  582.         }
  583.       }
  584.     }
  585.     ObjectDelete(0, BUYBTN_NAME);
  586.     ObjectDelete(0, SELLBTN_NAME);
  587.     ObjectDelete(0, LOTSINC_NAME);
  588.     ObjectDelete(0, LOTSDEC_NAME);
  589.     ObjectDelete(0, LOTSED_NAME);
  590.   }
  591.   if(OffTimeVisible) {
  592.     ObjectDelete(0, OFFTIME_NAME) ;
  593.     OffTimeVisible=false ;
  594.   }
  595.   if(ShowAmount) {
  596.     ObjectDelete(0, AMOUNT_NAME) ;
  597.   }
  598.   if(DBGMODE) {
  599.     ObjectDelete(0, DBGINFO_NAME) ;
  600.   }
  601.   if(StoplossTrapArray!=NULL) {
  602.     delete StoplossTrapArray ;
  603.     StoplossTrapArray = NULL ;
  604.   }
  605. }
  606. //---------------------------------------------------------------------------
  607. void OnTick()
  608. {
  609.   datetime nextTime = MainTime() ;
  610.   bool nextTimed = nextTime != CurTime ;
  611.   CurTime = nextTime ;
  612.  
  613.   datetime nextTick = BaseTime(TimeBase) ;
  614.   bool nextTicked = nextTick != TimeTick ;
  615.   TimeTick = nextTick;
  616.  
  617.   CurBid = GetBid(); CurAsk = GetAsk();
  618.  
  619.   // キュー更新
  620.   QiFastMA      .Update();
  621.   QiMediumMA    .Update();
  622.   QiSlowMA      .Update();
  623.   QiATR14       .Update();
  624.  
  625.   // タイムコントロールチェック
  626.   CheckTimeControl(nextTicked);
  627.  
  628.   // 動作チェック
  629.   CheckBehavior(nextTimed);
  630.  
  631.   double atr14 = QiATR14.latest() ;
  632.   double spread = CurAsk-CurBid ;
  633.  
  634.   // デバッグ欄表示のサンプル
  635.   if(DBGMODE) {
  636.     DBGOUT(
  637.       // ATR in points
  638.       StringFormat("ATR(14): %.3f",atr14/_Point) + " | " +
  639.       // SPREAD in points
  640.       StringFormat("SPREAD: %g",spread/_Point) + " | " +
  641.       // 現在の値幅の変動倍率(ATR/SPREAD)
  642.       StringFormat("ATR(14)/SPREAD: %.3f",atr14/(spread<=0?1:spread))
  643.     );
  644.   }
  645.  
  646.   // ユーザーオーダー予約情報更新
  647.   UpdateUserOrdering();
  648.  
  649.   // ユーザーロット情報自動更新(ロットの最後が'-'で終わっている場合)
  650.   if(ShowUserEntry) {
  651.     string LotsStr = ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT) ;
  652.     int ln = StringLen(LotsStr);
  653.     if(ln>0) {
  654.       if(LotsStr[ln-1]=='-') {
  655.         if(UserLots!=Lots) {
  656.           UserLots = Lots;
  657.           ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT, DoubleToString(UserLots, 2)+"-");
  658.         }
  659.       }
  660.     }
  661.   }
  662.  
  663.   // エントリー処理
  664.   if( AccountInfoInteger(ACCOUNT_TRADE_EXPERT) &&
  665.       TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ) {
  666.  
  667.     FLAG busy = AlreadyOrdered(FLAG_BUY|FLAG_SELL,MAGICMA) ;
  668.  
  669.     // ユーザーの注文
  670.     if(UserEntry) {
  671.  
  672.       // ユーザーのエントリを確認
  673.       if(TimeTick-UserTime<60) {  // 発行されてから60秒以内の注文
  674.  
  675.         FLAG user = UserEntry ;
  676.  
  677.         // 注文
  678.         if(user/*&&!AlreadyOrdered(user,MAGICMA)*/) {
  679.  
  680.           // ユーザーロット取得と更新
  681.           if(ShowUserEntry) {
  682.             double lots = StringToDouble(ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT));
  683.             if(lots>0) {
  684.               lots = AdjLots(lots) ;
  685.               if(UserLots!=lots) {
  686.                 UserLots = lots ;
  687.                 GlobalVariableSet(LOTSSAVE_NAME, UserLots);
  688.               }
  689.             }
  690.           }
  691.  
  692.           OP entry = user == FLAG_BUY ? OP_BUY : OP_SELL ;
  693.           if(EntryManualPosition("USER", entry, UserLots, UserStoploss, UserTakeprofit)>0)
  694.             busy |= user ;
  695.           else {
  696.             PrintMessage("Order failed by USER.");
  697.             PlaySound("timeout.wav");
  698.           }
  699.           LeaveUserOrdering();
  700.           UserEntry=0;
  701.  
  702.         }
  703.  
  704.       }else { UserEntry=0; }
  705.  
  706.     }
  707.  
  708.     // MARK: 自動注文
  709.  
  710.     /*
  711.     do {
  712.  
  713.       // 自動注文 開始時間調整
  714.       if(StartTime>TimeTick||CancelTime>TimeTick)
  715.         break ;
  716.  
  717.       // スプレッド幅のチェック
  718.       if(MarketInfo(NULL,MODE_SPREAD) > Spread)
  719.         break ;
  720.  
  721.       // 自動注文 XMA+ZigZag Detector
  722.       if(nextTimed)
  723.         EAEntryXMAZigZagPosition(busy,1);
  724.  
  725.     }while(0);
  726.     */
  727.  
  728.   }else {
  729.  
  730.     if(StartTime-TimeTick<10)
  731.       StartTime = TimeTick+10 ;
  732.  
  733.   }
  734.  
  735.   /*
  736.   if(PmdTiming) {
  737.     PmdPrevBid = (PmdPrevBid+Bid)/2.0 ; PmdPrevAsk = (PmdPrevAsk+Ask)/2.0 ;
  738.   }*/
  739.   PrevBid = CurBid ; PrevAsk = CurAsk ;
  740. }
  741. //---------------------------------------------------------------------------
  742. void OnChartEvent(
  743.   const int id,
  744.   const long &lparam,
  745.   const double &dparam,
  746.   const string &sparam
  747.  )
  748. {
  749.   if(id == CHARTEVENT_OBJECT_ENDEDIT && sparam == LOTSED_NAME) {
  750.       string lotsStr = ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT);
  751.       int ln = StringLen(lotsStr);
  752.       bool invalid = true ;
  753.       if(ln > 0 && lotsStr[ln-1] != '-') {
  754.           // 数値として評価してチェック
  755.           double lots = StringToDouble(lotsStr);
  756.           if(lots > 0) {
  757.               // 正常値 → AdjLots で丸めて反映
  758.               lots = AdjLots(lots);
  759.               UserLots = lots;
  760.               GlobalVariableSet(LOTSSAVE_NAME, UserLots);
  761.               ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT,
  762.                               DoubleToString(UserLots, 2));
  763.               invalid = false ; // 適正値
  764.           }
  765.       }
  766.       if(invalid) { // 不正値、または、自動ロット設定値("-"で終わる場合)
  767.         UserLots = Lots;
  768.         ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT,
  769.                         DoubleToString(Lots, 2) + "-");
  770.       }
  771.   }
  772.   if(id == CHARTEVENT_OBJECT_CLICK &&
  773.      (sparam == LOTSDEC_NAME || sparam == LOTSINC_NAME)) {
  774.       double lots = StringToDouble(ObjectGetString(0, LOTSED_NAME, OBJPROP_TEXT));
  775.       lots += (sparam == LOTSINC_NAME ? +StepLots : -StepLots);
  776.       lots  = AdjLots(lots);
  777.       UserLots = lots;
  778.       GlobalVariableSet(LOTSSAVE_NAME, UserLots);
  779.       ObjectSetString(0, LOTSED_NAME, OBJPROP_TEXT, DoubleToString(UserLots, 2));
  780.       Sleep(100);
  781.       ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
  782.   }
  783.   if( ( sparam == CLOSEALLBTN_NAME ||
  784.         sparam == CLOSELONGBTN_NAME ||
  785.         sparam == CLOSESHORTBTN_NAME ) && id==CHARTEVENT_OBJECT_CLICK) {
  786.     int orderFlag = 0 ;
  787.     if(sparam == CLOSEALLBTN_NAME) orderFlag = FLAG_SELL | FLAG_BUY ;
  788.     else if(sparam == CLOSELONGBTN_NAME) orderFlag = FLAG_BUY ;
  789.     else if(sparam == CLOSESHORTBTN_NAME) orderFlag = FLAG_SELL ;
  790.     CheckoutOrders(orderFlag);
  791.     Sleep(100);
  792.     ObjectSetInteger(0, sparam, OBJPROP_STATE, false);
  793.     // 60秒エントリーを停止する
  794.     CancelTime = TimeTick + 60 ;
  795.   }
  796.   if(sparam == FLUSHTLBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
  797.     FlushTL=true;
  798.     Sleep(100);
  799.     ObjectSetInteger(0, FLUSHTLBTN_NAME, OBJPROP_STATE, false);
  800.   }
  801.   if(sparam == SELLBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
  802.     switch(UserMethod) {
  803.       case ORDERMETHOD_ONE_CLICK:
  804.         DecideUserOrdering(FLAG_SELL);
  805.         Sleep(100);
  806.         ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_STATE, false);
  807.         break;
  808.       case ORDERMETHOD_TWO_STEPS:
  809.         ToggleUserOrdering(FLAG_SELL);
  810.         break;
  811.     }
  812.   }
  813.   if(sparam == BUYBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
  814.     switch(UserMethod) {
  815.       case ORDERMETHOD_ONE_CLICK:
  816.         DecideUserOrdering(FLAG_BUY);
  817.         Sleep(100);
  818.         ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_STATE, false);
  819.         break;
  820.       case ORDERMETHOD_TWO_STEPS:
  821.         ToggleUserOrdering(FLAG_BUY);
  822.         break;
  823.     }
  824.   }
  825.   if(sparam == ENTRYBTN_NAME && id==CHARTEVENT_OBJECT_CLICK) {
  826.     DecideUserOrdering(UserMode);
  827.     Sleep(100);
  828.     ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_STATE, false);
  829.   }
  830. }
  831. //---------------------------------------------------------------------------
  832. // MARK: ユーザーオーダー予約
  833. //-----
  834.   // ユーザーオーダー予約決定
  835. void DecideUserOrdering(FLAG UserOrderFlag)
  836. {
  837.   UserEntry = UserOrderFlag ;
  838.   CancelTime = UserTime = TimeTick ; CancelTime+=60 ;
  839. }
  840. //-----
  841.   // ユーザーオーダー予約状態のトグル切替
  842. void ToggleUserOrdering(FLAG modFlag)
  843. {
  844.   bool buyDn = (bool)ObjectGetInteger(0, BUYBTN_NAME, OBJPROP_STATE);
  845.   bool sellDn = (bool)ObjectGetInteger(0, SELLBTN_NAME, OBJPROP_STATE);
  846.  
  847.   switch(modFlag) {
  848.     case FLAG_BUY:
  849.       ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_STATE, false);
  850.       sellDn=false;
  851.       break;
  852.     case FLAG_SELL:
  853.       ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_STATE, false);
  854.       buyDn=false;
  855.       break;
  856.   }
  857.  
  858.   FLAG mode = 0 ;
  859.   if(buyDn) mode |= FLAG_BUY ;
  860.   if(sellDn) mode |= FLAG_SELL ;
  861.  
  862.   if(!mode||mode==(FLAG_BUY|FLAG_SELL)) {
  863.     // オーダー予約取消
  864.     LeaveUserOrdering();
  865.     return ;
  866.   }
  867.  
  868.   // オーダー予約開始
  869.   EnterUserOrdering(mode);
  870. }
  871. //-----
  872.   // ユーザーオーダー予約開始
  873. void EnterUserOrdering(FLAG UserOrderMode)
  874. {
  875.   //ENTRYボタン
  876.   ObjectCreate(0, ENTRYBTN_NAME, OBJ_BUTTON, 0, 0, 0);
  877.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_XDISTANCE, 10);
  878.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_YDISTANCE, UserEntryBtnYPos);
  879.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_XSIZE, 108);
  880.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_YSIZE, 27);
  881.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  882.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
  883.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_FONTSIZE, 12);
  884.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_COLOR, White);
  885.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_BGCOLOR, clrDarkOrchid);
  886.   ObjectSetInteger(0, ENTRYBTN_NAME, OBJPROP_ZORDER, 1);
  887.   ObjectSetString(0, ENTRYBTN_NAME, OBJPROP_TEXT, "ENTRY");
  888.   ObjectSetString(0, ENTRYBTN_NAME, OBJPROP_FONT, "Verdana");
  889.  
  890.   double slDist = Stoploss*_Point;
  891.   double slPrice = UserOrderMode==FLAG_BUY ? CurAsk-slDist : CurBid+slDist ;
  892.   double tpDist = Takeprofit*_Point;
  893.   double tpPrice = UserOrderMode==FLAG_BUY ? CurAsk+tpDist : CurBid-tpDist ;
  894.  
  895.   //ストップロス調整用ライン
  896.   ObjectCreate(0, SLLINE_NAME, OBJ_HLINE, 0, 0, slPrice);
  897.   ObjectSetInteger(0, SLLINE_NAME, OBJPROP_COLOR, ClrUserStoploss);
  898.   ObjectSetInteger(0, SLLINE_NAME, OBJPROP_WIDTH, 2);
  899.   ObjectSetInteger(0, SLLINE_NAME, OBJPROP_SELECTABLE, true);
  900.   ObjectSetInteger(0, SLLINE_NAME, OBJPROP_SELECTED, true); // すぐ動かせるように
  901.   ObjectSetString(0, SLLINE_NAME, OBJPROP_TEXT,
  902.     "Entry SL "+DoubleToString(slPrice,_Digits));
  903.   ObjectSetString(0, SLLINE_NAME, OBJPROP_TOOLTIP,
  904.     "Move S/L, next press the ENTRY button to open your position.");
  905.  
  906.   //テイクプロフィット確認用ライン
  907.   if(Takeprofit>0.0) {
  908.     ObjectCreate(0, TPLINE_NAME, OBJ_HLINE, 0, 0, tpPrice);
  909.     ObjectSetInteger(0, TPLINE_NAME, OBJPROP_COLOR, ClrUserTakeprofit);
  910.     ObjectSetInteger(0, TPLINE_NAME, OBJPROP_WIDTH, 2);
  911.     ObjectSetInteger(0, TPLINE_NAME, OBJPROP_SELECTABLE, false);
  912.     ObjectSetString(0, TPLINE_NAME, OBJPROP_TEXT,
  913.       "Entry TP "+DoubleToString(tpPrice,_Digits));
  914.     ObjectSetString(0, TPLINE_NAME, OBJPROP_TOOLTIP, "Estimated T/P");
  915.   }
  916.  
  917.   UserMode = UserOrderMode ;
  918.   UpdateUserOrdering();
  919. }
  920. //-----
  921.   // ユーザーオーダー予約終了
  922. void LeaveUserOrdering()
  923. {
  924.   ObjectDelete(0, TPLINE_NAME);
  925.   ObjectDelete(0, SLLINE_NAME);
  926.   ObjectDelete(0, ENTRYBTN_NAME);
  927.   ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_STATE, false);
  928.   ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_STATE, false);
  929.  
  930.   UserStoploss = 0 ;
  931.   UserTakeprofit = 0 ;
  932.   UserMode = 0 ;
  933. }
  934. //-----
  935.   // ユーザーオーダー予約更新
  936. void UpdateUserOrdering()
  937. {
  938.   if(UserMode) {
  939.  
  940.     double slPrice = ObjectGetDouble(0, SLLINE_NAME, OBJPROP_PRICE);
  941.     switch(UserMode) {
  942.       case FLAG_BUY:
  943.         if(slPrice>CurAsk) {
  944.           ObjectSetInteger(0, SELLBTN_NAME, OBJPROP_STATE, true);
  945.           ToggleUserOrdering(FLAG_SELL);
  946.           ObjectSetDouble(0, SLLINE_NAME, OBJPROP_PRICE, slPrice);
  947.         }
  948.         break;
  949.       case FLAG_SELL:
  950.         if(slPrice<CurBid) {
  951.           ObjectSetInteger(0, BUYBTN_NAME, OBJPROP_STATE, true);
  952.           ToggleUserOrdering(FLAG_BUY);
  953.           ObjectSetDouble(0, SLLINE_NAME, OBJPROP_PRICE, slPrice);
  954.         }
  955.         break;
  956.     }
  957.  
  958.     double slDist = UserMode==FLAG_BUY ? CurAsk-slPrice : slPrice-CurBid ;
  959.     Lots = CalcLotsFromSlDistance(slDist/_Point,true);
  960.  
  961.     ObjectSetString(0, SLLINE_NAME, OBJPROP_TEXT,
  962.       "Entry SL "+DoubleToString(slPrice,_Digits));
  963.     UserStoploss = slPrice ;
  964.  
  965.     if(Takeprofit>0.0) {
  966.       double ratioRR = Takeprofit/Stoploss ;
  967.       double tpDist = slDist * ratioRR ;
  968.       double commDist = MathAbs(CalcCommissionPointsFromTime(
  969.         CurTime,UserMode==FLAG_BUY?BuyWholeStatus:SellWholeStatus)) * _Point ;
  970.       double tpPrice = UserMode==FLAG_BUY ?
  971.         tpDist+CurAsk+commDist : CurBid-tpDist-commDist ;
  972.       ObjectSetDouble(0, TPLINE_NAME, OBJPROP_PRICE, tpPrice);
  973.       ObjectSetString(0, TPLINE_NAME, OBJPROP_TEXT,
  974.           "Entry TP "+DoubleToString(tpPrice,_Digits));
  975.       UserTakeprofit = tpPrice ;
  976.     }
  977.  
  978.   }else {
  979.  
  980.     Lots = CalcLotsFromSlDistance(Stoploss,true);
  981.  
  982.   }
  983. }
  984. //---------------------------------------------------------------------------
  985. // MARK: BEP ( Break Even Price )
  986. #define BEPLONG_NAME       "BEPLong"
  987. #define BEPSHORT_NAME      "BEPShort"
  988. FLAG BEPFlag=0;
  989. //-----
  990. void BEPDelete(FLAG flag, bool force=false)
  991. {
  992.   if((flag&FLAG_BUY)!=0&&(force||(BEPFlag&FLAG_BUY)!=0)) {
  993.     ObjectDelete(0, BEPLONG_NAME);
  994.     BEPFlag &= ~FLAG_BUY ;
  995.   }
  996.   if((flag&FLAG_SELL)!=0&&(force||(BEPFlag&FLAG_SELL)!=0)) {
  997.     ObjectDelete(0, BEPSHORT_NAME);
  998.     BEPFlag &= ~FLAG_SELL ;
  999.   }
  1000. }
  1001. //-----
  1002. void BEPUpdate(const STATUS &Status)
  1003. {
  1004.   FLAG flag = Status.Flag ;
  1005.   if(!Status.Positions) {
  1006.     BEPDelete(flag);
  1007.     return ;
  1008.   }
  1009.   double bep = Status.BorderPrice ;
  1010.   color col = (flag&FLAG_BUY)!=0 ? ClrBEPLong : ClrBEPShort ;
  1011.   string nam = (flag&FLAG_BUY)!=0 ? BEPLONG_NAME : BEPSHORT_NAME ;
  1012.   string tip = (flag&FLAG_BUY)!=0 ? "LONG BEP" : "SHORT BEP" ;
  1013.   if((flag&BEPFlag)!=0) { // BEP 表示中
  1014.     ObjectSetDouble(0, nam, OBJPROP_PRICE, bep);
  1015.   }else { // 新規
  1016.     ObjectCreate(0, nam, OBJ_HLINE, 0, 0, bep);
  1017.     ObjectSetInteger(0, nam, OBJPROP_COLOR, col);
  1018.     ObjectSetInteger(0, nam, OBJPROP_STYLE, STYLE_DOT);
  1019.     ObjectSetInteger(0, nam, OBJPROP_SELECTABLE, false);
  1020.     ObjectSetString(0, nam, OBJPROP_TOOLTIP, tip );
  1021.     BEPFlag |= flag ;
  1022.   }
  1023.   ObjectSetString(0, nam, OBJPROP_TEXT, tip+" "+DoubleToString(bep,_Digits));
  1024. }
  1025. //---------------------------------------------------------------------------
  1026. //DBGOUT
  1027. void DBGOUT(string text)
  1028. {
  1029.   if(DBGMODE) {
  1030.     ObjectSetString(0, DBGINFO_NAME, OBJPROP_TEXT, text);
  1031.   }
  1032. }
  1033. //---------------------------------------------------------------------------
  1034. //タイムコントロールチェック
  1035. void CheckTimeControl(bool nextTicked)
  1036. {
  1037.   if(!TimeControl) {
  1038.     if(OffTimeVisible) {
  1039.       ObjectDelete(0, OFFTIME_NAME);
  1040.       OffTimeVisible = false ;
  1041.     }
  1042.     return ;
  1043.   }
  1044.   if(!nextTicked) return ;
  1045.   if(!ControlTimeAction(
  1046.       TimeTick,StringToTime(TimeStart),StringToTime(TimeEnd),
  1047.       StartTime,MAGICMA,TimeAction)) {
  1048.     datetime timOff = StartTime - TimeTick ;
  1049.     if(!OffTimeVisible) {
  1050.       // OFF TIME テキストを表示
  1051.       ObjectCreate(0, OFFTIME_NAME, OBJ_LABEL, 0, 0, 0);
  1052.       ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_XDISTANCE, 10);
  1053.       ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_YDISTANCE, 25);
  1054.       ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
  1055.       ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
  1056.       ObjectSetString (0, OFFTIME_NAME, OBJPROP_TEXT, "OFF TIME");
  1057.       ObjectSetString (0, OFFTIME_NAME, OBJPROP_FONT, "Verdana");
  1058.       ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_FONTSIZE, 8);
  1059.       ObjectSetInteger(0, OFFTIME_NAME, OBJPROP_COLOR, ClrTimeControl);
  1060.       OffTimeVisible = true ;
  1061.     }
  1062.   }else if(OffTimeVisible) {
  1063.     ObjectDelete(0, OFFTIME_NAME);
  1064.     OffTimeVisible = false ;
  1065.   }
  1066. }
  1067. //---------------------------------------------------------------------------
  1068. //メインタイムを返す
  1069. datetime MainTime(int shift=0)
  1070. {
  1071.   return iTime(Symbol(), MainTimeFrame, shift);
  1072. }
  1073. //---------------------------------------------------------------------------
  1074. //メインPERIODを返す
  1075. int MainPeriod()
  1076. {
  1077.   int period = MainTimeFrame ;
  1078.   if(!period) period = Period();
  1079.   return period ;
  1080. }
  1081. //---------------------------------------------------------------------------
  1082. //金額表示の更新
  1083. void UpdateAmount(double amount, int positions)
  1084. {
  1085.   if(ShowAmount) {
  1086.     if(positions>0) {
  1087.       string s = DoubleToAmount(amount,(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS)) ;
  1088.       if(amount>0) s = "+" + s ;
  1089.       ObjectSetString(0, AMOUNT_NAME, OBJPROP_TEXT, s);
  1090.       if(amount<0)
  1091.         ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_COLOR, AMOUNT_CLR_NEGA);
  1092.       else
  1093.         ObjectSetInteger(0, AMOUNT_NAME, OBJPROP_COLOR, AMOUNT_CLR_POSI);
  1094.     }else {
  1095.       string s = ObjectGetString(0, AMOUNT_NAME, OBJPROP_TEXT);
  1096.       int ln=StringLen(s);
  1097.       if(ln>0) {
  1098.         if(s[ln-1]!='-')
  1099.           ObjectSetString(0, AMOUNT_NAME, OBJPROP_TEXT, s+"-");
  1100.       }
  1101.     }
  1102.   }
  1103. }
  1104. //---------------------------------------------------------------------------
  1105. //MARK:動作チェック
  1106. void CheckBehavior(bool nextTimed)
  1107. {
  1108.   // 全体のステータスを取得
  1109.   for(int n=0;n<2;n++) {
  1110.     CheckStatus(OP_BUY, MAGICMA, &BuyWholeStatus);
  1111.     BuyWholeStatus.OrdersSort(ORDERSORT_PRICE_ASCEND);
  1112.     if(!CheckoutStoplossTrappedOrders(&BuyWholeStatus)) break;
  1113.   }
  1114.   for(int n=0;n<2;n++) {
  1115.     CheckStatus(OP_SELL, MAGICMA, &SellWholeStatus);
  1116.     SellWholeStatus.OrdersSort(ORDERSORT_PRICE_DESCEND);
  1117.     if(!CheckoutStoplossTrappedOrders(&SellWholeStatus)) break;
  1118.   }
  1119.   StoplossTrapArray.Clear();
  1120.  
  1121.   // BEP 更新
  1122.   if(ShowBEP) {
  1123.     BEPUpdate(BuyWholeStatus);
  1124.     BEPUpdate(SellWholeStatus);
  1125.   }
  1126.  
  1127.   // 金額を更新
  1128.   double CurAmount = BuyWholeStatus.GrossProfit+SellWholeStatus.GrossProfit ;
  1129.   int CurPositions = BuyWholeStatus.Positions+SellWholeStatus.Positions ;
  1130.   UpdateAmount(CurAmount,CurPositions);
  1131.  
  1132.   // 自動処理
  1133.   if(Automation) {
  1134.  
  1135.     // 最大損益のチェック
  1136.     if(CurAmount<0) {
  1137.       double balance = AccountInfoDouble(ACCOUNT_BALANCE);
  1138.       if(BalanceIncludeCredit) balance += AccountInfoDouble(ACCOUNT_CREDIT);
  1139.       double equity  = AccountInfoDouble(ACCOUNT_EQUITY);
  1140.       bool grossloss = balance*MaxGrosslossPer/100.0<=-CurAmount ;
  1141.       bool drawdown = balance*MaxDrawDownPer/100.0<=balance-equity ;
  1142.       if( grossloss || drawdown ) {
  1143.         //最大損益を超えた場合は、すべて決済する
  1144.         CheckoutOrders(FLAG_BUY|FLAG_SELL);
  1145.         string reason = grossloss ?
  1146.           "over Maximum Allowed Gross loss" :
  1147.           "over Maximum Allowed Draw down" ;
  1148.         PrintMessage("Check-out orders by " + reason);
  1149.         return;
  1150.       }
  1151.     }
  1152.  
  1153.     // オーダーの処理
  1154.     ProcessOrders(nextTimed, OP_BUY, BuyWholeStatus, SellWholeStatus);
  1155.     ProcessOrders(nextTimed, OP_SELL, SellWholeStatus, BuyWholeStatus);
  1156.  
  1157.   }
  1158.  
  1159.   FlushTL=false;
  1160. }
  1161. //---------------------------------------------------------------------------
  1162. //MARK:オーダーの処理
  1163. void ProcessOrders(bool nextTimed, OP orderType, const STATUS &status, const STATUS &revStatus)
  1164. {
  1165.   if(status.Positions<=0) return ;
  1166.  
  1167.   // トレーリング
  1168.   if(Trailing) {
  1169.     double tstart = TrailingStart*_Point ;
  1170.     double tstop = TrailingStop*_Point ;
  1171.     double minPadding = tstart+tstop ;
  1172.     for(int i=0;i<status.OrdersCount();i++) {
  1173.       COrderStatus *order = status.OrdersAt(i) ;
  1174.       if((order.Tag&STATAG_CHECKEDOUT)!=0) continue ; // 決済済
  1175.       if( orderType==OP_BUY ?
  1176.             order.BorderPrice>CurBid-minPadding : order.BorderPrice<CurAsk+minPadding )
  1177.         break;
  1178.       double sl=0.0 ;
  1179.       if( order.Stoploss==0.0 ||
  1180.           ( orderType==OP_BUY ?
  1181.               order.Stoploss<order.BorderPrice : order.Stoploss>order.BorderPrice ) ) {
  1182.         //初回トレール
  1183.         sl = orderType==OP_BUY ? order.BorderPrice+tstart : order.BorderPrice-tstart ;
  1184.       }else {
  1185.         //既にトレール済
  1186.         sl = order.Stoploss ;
  1187.       }
  1188.       while( ( orderType==OP_BUY ? CurBid-sl : sl-CurAsk ) >= tstop*2 ) {
  1189.         //カクカクにトレール幅を狭めていく
  1190.         sl += orderType==OP_BUY ? +tstop : -tstop ;
  1191.       }
  1192.       if(!InnerPoint(sl,order.Stoploss)) {
  1193.         //ストップロスを更新
  1194.         if(ModifyOrderSlTp(order.Ticket,sl,order.Takeprofit)) {
  1195.           order.Stoploss = sl ;
  1196.           EntryStoplossTrap(orderType, order, sl);
  1197.         }else PrintLastError();
  1198.       }
  1199.     }
  1200.   }
  1201.  
  1202.   // 3EMA処理
  1203.   if(MA3 && (nextTimed||FlushTL)) {
  1204.     double HalfSpread = (CurAsk-CurBid)/2.0;
  1205.     double FastMA0 = QiFastMA.latest() +HalfSpread ;
  1206.     double MediumMA0 = QiMediumMA.latest() +HalfSpread ;
  1207.     double SlowMA0 = QiSlowMA.latest() +HalfSpread ;
  1208.     for(int i=0;i<status.OrdersCount();i++) {
  1209.       COrderStatus *order = status.OrdersAt(i) ;
  1210.       if((order.Tag&STATAG_CHECKEDOUT)!=0) continue ; // 決済済
  1211.       double price = order.InitialBorderPrice ;
  1212.       double sl = order.Stoploss ;
  1213.       double trail_sl=0.0;
  1214.       double checkout_denom=0.0;
  1215.       string checkout_reason="";
  1216.       if(InnerPoint(sl,price)) { // プライスがslに一致
  1217.         if(FlushTL&&!nextTimed) continue;
  1218.         if(!InnerPoint(MediumMA0,price) &&
  1219.           (orderType==OP_BUY?MediumMA0-HalfSpread>price:MediumMA0+HalfSpread<price)) { // Medium MA がプライス以上
  1220.           if(orderType==OP_BUY?FastMA0>CurAsk:FastMA0<CurBid) { // Fast MA が現価以上
  1221.             // 決済設定
  1222.             checkout_denom = LotsDenomMAFast ;
  1223.             checkout_reason = "Check-out by Fast MA" ;
  1224.             if(orderType==OP_BUY?MediumMA0>CurAsk:MediumMA0<CurBid) // Medium MA が現価より上
  1225.             { checkout_reason += " & Medium MA"; checkout_denom = 1.0 ;} // 全決済する
  1226.             // ストップロスを Medium MA 値に更新する
  1227.             trail_sl = MediumMA0 + (orderType==OP_BUY?-HalfSpread:+HalfSpread) ;
  1228.           }
  1229.         }
  1230.       }else if(sl!=0.0&&(orderType==OP_BUY?sl>price:sl<price)) { //プライスがslより下
  1231.         if(FlushTL&&!nextTimed) continue;
  1232.         if(orderType==OP_BUY?CurAsk<=MediumMA0:CurBid>=MediumMA0) { //現価が Medium MA より下になった
  1233.           // 決済設定
  1234.           checkout_denom = 1.0 ; // 全決済
  1235.           checkout_reason = "Check-out by Medium MA" ;
  1236.         }
  1237.       }else { //プライスがslより上、もしくは、slが設定されていない
  1238.         if(FlushTL||MA3TLPeriod>0) { // TL(TimeLimited) ポジションが有効
  1239.           //ロウソク足の期間を計測
  1240.           /* 旧方式
  1241.           datetime tperiod = MainPeriod() * 60 ;
  1242.           int period = int((CurTime-order.OpenTime)/tperiod);
  1243.           bool overTime = period>=MA3TLPeriod-1 ;
  1244.           */
  1245.           // 新方式
  1246.           int period = Bars(_Symbol, MainTimeFrame, order.OpenTime, CurTime);
  1247.           bool overTime = period>=MA3TLPeriod ;
  1248.           if(FlushTL||overTime) { //TL(TimeLimited)期間が過ぎている
  1249.             if(orderType==OP_BUY?CurBid>price:CurAsk<price) { // 利確できる位置にある
  1250.               if(!FlushTL&&(orderType==OP_BUY?FastMA0>CurAsk||MediumMA0>CurAsk:FastMA0<CurBid||MediumMA0<CurBid)) { // 2MA が現価より上
  1251.                 // 現価が 2MA を抜かすまでの間、ストップロスを建値ギリギリまで引き上げておく
  1252.                 trail_sl = price + (orderType==OP_BUY?-_Point:+_Point);
  1253.               }else { // FastMA が現価以下
  1254.                 // 決済設定
  1255.                 checkout_denom = LotsDenomTL ;
  1256.                 checkout_reason = "Check-out by TL(TimeLimited)" ;
  1257.                 // ストップロスを建値に引き上げる
  1258.                 trail_sl = price ;
  1259.               }
  1260.             }
  1261.           }
  1262.         }
  1263.         if(!FlushTL||nextTimed) {
  1264.           if(sl==0.0) { //ストップロスが設定されていない
  1265.             if(MaxGrosslossPer>=100.0) { // Max Gross loss が 100%以上
  1266.               if(orderType==OP_BUY?CurAsk<=SlowMA0:CurBid>=SlowMA0) { //現価が Slow MA より下になった
  1267.                 // 損切設定
  1268.                 checkout_denom = 1.0 ; // 全決済
  1269.                 checkout_reason = "Loss-cut order by Slow MA" ;
  1270.               }
  1271.             }
  1272.           }
  1273.         }
  1274.       }
  1275.       if(trail_sl!=0.0) {
  1276.         //MAによるトレーリング
  1277.         if(sl==0.0||(!InnerPoint(sl,trail_sl)&&(orderType==OP_BUY?sl<trail_sl:sl>trail_sl))) {
  1278.           sl = trail_sl ;
  1279.           if(ModifyOrderSlTp(order.Ticket,sl,order.Takeprofit)) {
  1280.             order.Stoploss = sl ;
  1281.             EntryStoplossTrap(orderType, order, sl);
  1282.           }else PrintLastError();
  1283.         }
  1284.       }
  1285.       if(checkout_denom>0.0) {
  1286.         //MAによる決済処理
  1287.         double lots = AdjLots(order.Lots/checkout_denom) ;
  1288.         if(lots<MinLots) lots = MinLots ;
  1289.         if(lots>order.Lots) lots = order.Lots ;
  1290.         if(CheckoutOrder(orderType,order.Ticket,lots)) {
  1291.           PrintMessage(checkout_reason);
  1292.           order.Lots -= lots ;
  1293.           if(order.Lots<=0)
  1294.              order.Tag |= STATAG_CHECKEDOUT ; // 決済済
  1295.         }
  1296.       }
  1297.     }
  1298.   }
  1299. }
  1300. //---------------------------------------------------------------------------
  1301. //マニュアルポジション発注
  1302. TICKET EntryManualPosition(string detector, OP entryType, double lots,
  1303.   double sl=0.0, double tp=0.0)
  1304. {
  1305.   double slDist = Stoploss*_Point ;
  1306.   double tpDist = Takeprofit*_Point ;
  1307.   double ratioRR = tpDist/slDist ;
  1308.   if(sl>0.0) {
  1309.     slDist = MathAbs( entryType==OP_BUY ? CurAsk-sl : sl-CurBid );
  1310.     tpDist = slDist * ratioRR ;
  1311.   }
  1312.   if(tpDist!=0.0)
  1313.     tpDist += MathAbs(CalcCommissionPointsFromTime(
  1314.           CurTime,entryType==OP_BUY?BuyWholeStatus:SellWholeStatus))*_Point;
  1315.   if(tp>0.0) {
  1316.     tpDist = MathAbs( entryType==OP_BUY ? tp-CurAsk : CurBid-tp );
  1317.   }
  1318.   switch(entryType)  {
  1319.     case OP_BUY:
  1320.       if(slDist!=0.0) sl = CurAsk-slDist ;
  1321.       if(sl>0.0&&sl>=CurBid) {
  1322.         PrintMessage("Entring failed due to s/l over BID reached");
  1323.         return 0 ; // invalid
  1324.       }
  1325.       if(tpDist!=0.0) tp = CurAsk+tpDist ;
  1326.       break;
  1327.     case OP_SELL:
  1328.       if(slDist!=0.0) sl = CurBid+slDist ;
  1329.       if(sl>0.0&&sl<=CurAsk) {
  1330.         PrintMessage("Entring failed due to s/l under ASK reached");
  1331.         return 0 ; // invalid
  1332.       }
  1333.       if(tpDist!=0.0) tp = CurBid-tpDist ;
  1334.       break;
  1335.   }
  1336.   if(sl==0.0) {
  1337.     if(MaxGrosslossPer>=100.0) {
  1338.       // SlowMAの現在位置がAsk/Bidよりも上回っていないことを確認する
  1339.       double HalfSpread = (CurAsk-CurBid)/2.0;
  1340.       double SlowMA0 = QiSlowMA.latest()+HalfSpread ;
  1341.       if(entryType==OP_BUY?SlowMA0>=CurAsk:SlowMA0<=CurBid) {
  1342.         string reason = entryType==OP_BUY ? "over" : "under" ;
  1343.         PrintMessage("Entring failed due to Slow MA "+reason+" price reached");
  1344.         return 0 ; // invalid
  1345.       }
  1346.     }
  1347.   }
  1348.   return MakeOrder(entryType,lots,sl,tp,detector,MAGICMA);
  1349. }
  1350. //---------------------------------------------------------------------------
  1351. //マジックナンバーと一致する全オーダーのチェックアウト
  1352. void CheckoutOrders(FLAG flag)
  1353. {
  1354.   CheckoutOrderAll(flag,MAGICMA);
  1355. }
  1356. //---------------------------------------------------------------------------
  1357. // オーダーを StoplossTrapArray に登録
  1358. bool EntryStoplossTrap(OP type, const COrderStatus *order, double stoploss=0)
  1359. {
  1360.   if(stoploss==0) stoploss = order.Stoploss ;
  1361.   if(stoploss==0) return false ;
  1362.   OBJECT_PARTCLOSED part(order.Ticket,type,order.Price,order.OpenTime,stoploss);
  1363.   int idx = SearchSortedArray(StoplossTrapArray,part);
  1364.   if(idx>=0) { // 既にエントリ済
  1365.     CSortable<OBJECT_PARTCLOSED>* obj =
  1366.       (CSortable<OBJECT_PARTCLOSED>*)StoplossTrapArray.At(idx) ;
  1367.     obj.v.Stoploss = stoploss ; // ストップロスの値を更新
  1368.   }else { // 新規エントリ
  1369.     AddToSortedArray(StoplossTrapArray,part);
  1370.   }
  1371.   return true ;
  1372. }
  1373. //---------------------------------------------------------------------------
  1374. // オーダーのストップロスが前回登録したストップロス情報と一致しているか調べる
  1375. bool CheckStoplossTrap(OP type, const COrderStatus *order, double stoploss=0)
  1376. {
  1377.   if(stoploss==0) stoploss = order.Stoploss ;
  1378.   if(stoploss==0) return true ; // 無視
  1379.   OBJECT_PARTCLOSED part(order.Ticket,type,order.Price,order.OpenTime,stoploss);
  1380.   int idx = SearchSortedArray(StoplossTrapArray,part);
  1381.   if(idx>=0) { // 既にエントリ済
  1382.     CSortable<OBJECT_PARTCLOSED>* obj =
  1383.       (CSortable<OBJECT_PARTCLOSED>*)StoplossTrapArray.At(idx) ;
  1384.     return InnerPoint(obj.v.Stoploss, stoploss); // ストップロスの一致を返す
  1385.   }
  1386.   return true ; // エントリされていないので無視
  1387. }
  1388. //---------------------------------------------------------------------------
  1389. // ストップロスが更新されていないオーダーを全て決済する
  1390. int CheckoutStoplossTrappedOrders(STATUS *status)
  1391. {
  1392.   int n=0;
  1393.   for(int i=status.OrdersCount()-1;i>=0;i--) {
  1394.     COrderStatus *order = status.OrdersAt(i);
  1395.     if((order.Tag&STATAG_CHECKEDOUT)!=0) continue ;
  1396.     if(!CheckStoplossTrap(status.Type,order)) {
  1397.       if(CheckoutOrder(status.Type,order.Ticket,order.Lots)) {
  1398.         order.Lots = 0 ;
  1399.         order.Tag |= STATAG_CHECKEDOUT ;
  1400.         PrintMessage("Checkout Order by ST(StoplossTrapped)");
  1401.         n++;
  1402.       }
  1403.     }
  1404.   }
  1405.   return n;
  1406. }
  1407. //---------------------------------------------------------------------------
  1408. //MARK: ストップロスの幅からロットを換算して返す @ 2026/06/23
  1409. double CalcLotsFromSlDistance(double slPoints, bool adjustable=false)
  1410. {
  1411.   // 口座残高を計算
  1412.   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
  1413.   if(BalanceIncludeCredit) balance += AccountInfoDouble(ACCOUNT_CREDIT);
  1414.  
  1415.   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
  1416.  
  1417.   // 口座残高のRTPer%をリスク額とする
  1418.   double riskAmount = MathMin(balance, equity) * RTPer/100.0 ;
  1419.  
  1420.   // リスク額とS/Lから生ロット値計算
  1421.   double rawLot = 0.0;
  1422.   switch(RTCalcType) {
  1423.     case RTCALCTYPE_I:
  1424.       rawLot = CalcLotsFromSlDistance_TYPE_I(slPoints, riskAmount) ;
  1425.       break;
  1426.     case RTCALCTYPE_II:
  1427.       rawLot = CalcLotsFromSlDistance_TYPE_II(slPoints, riskAmount) ;
  1428.       break;
  1429.   }
  1430.  
  1431.   return adjustable ? AdjLots(rawLot) : rawLot ;
  1432. }
  1433. //-----(TYPE-I)-----
  1434. //SymbolInfoDouble(SYMBOL_TRADE_...)系から情報を取得して換算する
  1435. //(※サーバー側が間違った情報を返す場合は、正常に機能しないことがある)
  1436. double CalcLotsFromSlDistance_TYPE_I(double slPoints, double riskAmount)
  1437. {
  1438.   // ティックサイズ(値幅の最小単位)を得る
  1439.   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
  1440.  
  1441.   // 1ロットあたり、1ポイント動いた時の価格を取得
  1442.   //double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
  1443.  
  1444.   // 1ロットあたり、1ポイント動いた時の価格(口座通貨ベース)を取得
  1445.   double tickValueProfit = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE_PROFIT);
  1446.  
  1447.   // ポイント値をティック数に換算
  1448.   double stopTicks = (slPoints * _Point) / tickSize ;
  1449.  
  1450.   // ロット数を計算 (リスク額 / (S/Lのティック数 * 1ティックの口座価値))
  1451.   double rawLot = riskAmount / (stopTicks * tickValueProfit);
  1452.  
  1453.   return rawLot ;
  1454. }
  1455. //-----(TYPE-II)-----
  1456. //MT5が自前で用意しているOrderCalcProfit関数から損益を取得してロットを換算する
  1457. double CalcLotsFromSlDistance_TYPE_II(double slPoints, double riskAmount)
  1458. {
  1459.   double price = CurAsk ;
  1460.   double sl = CurAsk - (slPoints * _Point);
  1461.  
  1462.   double lot1 = 1.0 ; // 1 lot
  1463.   double lossPerLot = 0.0 ;
  1464.  
  1465.   if(OrderCalcProfit(ORDER_TYPE_BUY, _Symbol, lot1, price, sl, lossPerLot)) {
  1466.  
  1467.     // 損失額はマイナスで返るため正数に変換
  1468.     double riskPerLot = MathAbs(lossPerLot);
  1469.  
  1470.     // ロット数を計算 (リスク額 / ロット当たりの損失額)
  1471.     double rawLot = riskAmount / riskPerLot ;
  1472.  
  1473.     return rawLot ;
  1474.   }
  1475.  
  1476.   return 0.0;
  1477. }
  1478. //---------------------------------------------------------------------------
  1479. // タイム値から手数料に掛かる値幅(ポイント)を換算して返す
  1480. double CalcCommissionPointsFromTime(datetime time, STATUS &status)
  1481. {
  1482.   // 1ポイントあたりの利益額(口座通貨)
  1483.   double point_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE_PROFIT)
  1484.     / _Point ;
  1485.  
  1486.   if(point_value == 0) return 0;
  1487.  
  1488.   return status.USDJPYCommissionPerLotAt(time) / point_value ;
  1489. }
  1490. //---------------------------------------------------------------------------
  1491.  
Tags: Mt5
Advertisement
Add Comment
Please, Sign In to add comment