#property strict #include CTrade trade; //--- object names string BTN_NAME = "CreateLineButton"; string LINE_NAME = "EntryLine"; //--- trend settings input int TrendPeriod = 50; int ma_handle = INVALID_HANDLE; //+------------------------------------------------------------------+ //| Expert initialization | //+------------------------------------------------------------------+ int OnInit() { CreateButton(); ma_handle = iMA(_Symbol, _Period, TrendPeriod, 0, MODE_SMA, PRICE_CLOSE); if(ma_handle == INVALID_HANDLE) { Print("MA handle creation failed"); return INIT_FAILED; } return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectDelete(0, BTN_NAME); ObjectDelete(0, LINE_NAME); } //+------------------------------------------------------------------+ //| Create button | //+------------------------------------------------------------------+ void CreateButton() { if(ObjectFind(0, BTN_NAME) != -1) return; if(!ObjectCreate(0, BTN_NAME, OBJ_BUTTON, 0, 0, 0)) { Print("Failed to create button"); return; } ObjectSetInteger(0, BTN_NAME, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, BTN_NAME, OBJPROP_YDISTANCE, 20); ObjectSetInteger(0, BTN_NAME, OBJPROP_XSIZE, 140); ObjectSetInteger(0, BTN_NAME, OBJPROP_YSIZE, 30); ObjectSetString(0, BTN_NAME, OBJPROP_TEXT, "Add Entry Line"); ObjectSetInteger(0, BTN_NAME, OBJPROP_COLOR, clrWhite); ObjectSetInteger(0, BTN_NAME, OBJPROP_BGCOLOR, clrBlue); ObjectSetInteger(0, BTN_NAME, OBJPROP_BORDER_COLOR, clrBlack); } //+------------------------------------------------------------------+ //| Create draggable horizontal line | //+------------------------------------------------------------------+ void CreateEntryLine() { if(ObjectFind(0, LINE_NAME) != -1) return; double price = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(!ObjectCreate(0, LINE_NAME, OBJ_HLINE, 0, 0, price)) { Print("Failed to create line"); return; } ObjectSetInteger(0, LINE_NAME, OBJPROP_COLOR, clrRed); ObjectSetInteger(0, LINE_NAME, OBJPROP_WIDTH, 2); ObjectSetInteger(0, LINE_NAME, OBJPROP_SELECTABLE, true); ObjectSetInteger(0, LINE_NAME, OBJPROP_SELECTED, true); } //+------------------------------------------------------------------+ //| Chart event handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id == CHARTEVENT_OBJECT_CLICK) { Print("ChartEvent: clicked object = ", sparam); if(sparam == BTN_NAME) { Print("Button clicked → creating line"); CreateEntryLine(); } } } //+------------------------------------------------------------------+ //| Trend direction using MA | //+------------------------------------------------------------------+ int GetTrendDirection() { if(ma_handle == INVALID_HANDLE) return 0; double ma_buf[1]; if(CopyBuffer(ma_handle, 0, 0, 1, ma_buf) != 1) return 0; double ma = ma_buf[0]; double price = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(price > ma) return 1; // uptrend if(price < ma) return -1; // downtrend return 0; } //+------------------------------------------------------------------+ //| OnTick: keep UI alive + trade logic | //+------------------------------------------------------------------+ void OnTick() { // In tester, chart can reset → ensure button exists if(ObjectFind(0, BTN_NAME) == -1) CreateButton(); if(ObjectFind(0, LINE_NAME) == -1) return; double linePrice = ObjectGetDouble(0, LINE_NAME, OBJPROP_PRICE); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); int trend = GetTrendDirection(); if(trend == 0) return; if((trend == 1 && ask >= linePrice) || (trend == -1 && bid <= linePrice)) { double lot = 0.1; if(trend == 1) { Print("Buying at line touch"); trade.Buy(lot, _Symbol); } else { Print("Selling at line touch"); trade.Sell(lot, _Symbol); } ObjectDelete(0, LINE_NAME); } }