last ...
This commit is contained in:
@@ -0,0 +1,243 @@
|
|||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| SpikeDetectorEA.mq5 |
|
||||||
|
//| Copyright 2025, Your Name/Company |
|
||||||
|
//| https://www.example.com |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
#property copyright "Copyright 2025, Your Name/Company"
|
||||||
|
#property link "https://www.example.com"
|
||||||
|
#property version "1.01" // Incremented version
|
||||||
|
#property description "Expert Advisor to detect and draw price spikes (pin bars)."
|
||||||
|
|
||||||
|
//--- Input Parameters
|
||||||
|
input group "Spike Definition" input double InpMinWickToBodyRatio = 2.0; // Minimum ratio of the main wick to the body (e.g., 2.0 means wick is 2x body)
|
||||||
|
input double InpMaxOppositeWickToBodyRatio = 1.0; // Maximum ratio of the opposite wick to the body (e.g., 1.0 means opposite wick <= body)
|
||||||
|
input double InpMaxBodyToTotalRangeRatio = 0.33; // Maximum ratio of body to total candle range (H-L) (e.g., 0.33 means body is < 1/3 of range)
|
||||||
|
|
||||||
|
input group "Drawing Settings" input int InpArrowOffsetPoints = 10; // Arrow offset from High/Low in points
|
||||||
|
input color InpBullishSpikeColor = clrLimeGreen; // Color for bullish spike arrows
|
||||||
|
input color InpBearishSpikeColor = clrRed; // Color for bearish spike arrows
|
||||||
|
input int InpLookbackForDrawing = 200; // How many past bars to check on EA load/recompile
|
||||||
|
|
||||||
|
// Wingdings Arrow Codes (commonly used for OBJ_ARROW)
|
||||||
|
#define WINGDINGS_ARROW_UP 241
|
||||||
|
#define WINGDINGS_ARROW_DOWN 242
|
||||||
|
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Expert initialization function |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
int OnInit()
|
||||||
|
{
|
||||||
|
//---
|
||||||
|
// You can add any one-time initialization logic here if needed
|
||||||
|
Print("SpikeDetectorEA initialized. Symbol: ", _Symbol, ", Timeframe: ", EnumToString((ENUM_TIMEFRAMES)Period()));
|
||||||
|
//---
|
||||||
|
return (INIT_SUCCEEDED);
|
||||||
|
}
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Expert deinitialization function |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
void OnDeinit(const int reason)
|
||||||
|
{
|
||||||
|
//---
|
||||||
|
// Optional: Clean up objects when EA is removed or chart is closed
|
||||||
|
// For more targeted deletion, you might loop through objects and check names
|
||||||
|
// ObjectsDeleteAll(0, "SpikeArrow_Bearish_" + _Symbol);
|
||||||
|
// ObjectsDeleteAll(0, "SpikeArrow_Bullish_" + _Symbol);
|
||||||
|
// A more robust way if you have many EAs or indicators:
|
||||||
|
long chart_id = ChartID();
|
||||||
|
for (int i = ObjectsTotal(chart_id, -1, OBJ_ARROW) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
string obj_name = ObjectName(chart_id, i, -1, OBJ_ARROW);
|
||||||
|
if (StringFind(obj_name, "SpikeArrow_Bearish_" + _Symbol + "_" + EnumToString((ENUM_TIMEFRAMES)Period())) == 0 ||
|
||||||
|
StringFind(obj_name, "SpikeArrow_Bullish_" + _Symbol + "_" + EnumToString((ENUM_TIMEFRAMES)Period())) == 0)
|
||||||
|
{
|
||||||
|
ObjectDelete(chart_id, obj_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Print("SpikeDetectorEA deinitialized. Reason: ", reason);
|
||||||
|
}
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Expert tick function (not used for bar analysis in this EA) |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
void OnTick()
|
||||||
|
{
|
||||||
|
//---
|
||||||
|
// We will use OnCalculate for bar-based analysis
|
||||||
|
}
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Chart event function (not strictly needed for this EA) |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
void OnChartEvent(const int id,
|
||||||
|
const long &lparam,
|
||||||
|
const double &dparam,
|
||||||
|
const string &sparam)
|
||||||
|
{
|
||||||
|
//---
|
||||||
|
// Can be used to handle chart events if necessary
|
||||||
|
}
|
||||||
|
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
//| Expert new bar function / Indicator calculation event |
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
|
int OnCalculate(const int rates_total, // Size of the price[] arrays
|
||||||
|
const int prev_calculated, // Bars calculated at the previous call
|
||||||
|
const datetime &time[], // Time array
|
||||||
|
const double &open[], // Open price array
|
||||||
|
const double &high[], // High price array
|
||||||
|
const double &low[], // Low price array
|
||||||
|
const double &close[], // Close price array
|
||||||
|
const long &tick_volume[], // Tick Volume array
|
||||||
|
const long &volume[], // Real Volume array
|
||||||
|
const int &spread[]) // Spread array
|
||||||
|
{
|
||||||
|
//--- Check for minimal rates_total
|
||||||
|
if (rates_total < 2) // Need at least one closed bar to compare
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
//--- Determine how many bars to calculate
|
||||||
|
int first_bar_to_calculate;
|
||||||
|
// On the very first call of OnCalculate (prev_calculated == 0) or if history was changed drastically
|
||||||
|
if (prev_calculated == 0 || prev_calculated > rates_total || rates_total - prev_calculated > InpLookbackForDrawing + 10) // Added a buffer for safety
|
||||||
|
{
|
||||||
|
first_bar_to_calculate = MathMax(0, rates_total - InpLookbackForDrawing);
|
||||||
|
Print("SpikeDetectorEA: First run or history refresh. Processing up to ", InpLookbackForDrawing, " bars from bar index ", first_bar_to_calculate);
|
||||||
|
// Clean up old arrows if doing a full refresh to avoid orphaned objects if bar times change
|
||||||
|
long chart_id = ChartID();
|
||||||
|
for (int k = ObjectsTotal(chart_id, -1, OBJ_ARROW) - 1; k >= 0; k--)
|
||||||
|
{
|
||||||
|
string obj_name_check = ObjectName(chart_id, k, -1, OBJ_ARROW);
|
||||||
|
if (StringFind(obj_name_check, "SpikeArrow_Bearish_" + _Symbol + "_" + EnumToString((ENUM_TIMEFRAMES)Period())) == 0 ||
|
||||||
|
StringFind(obj_name_check, "SpikeArrow_Bullish_" + _Symbol + "_" + EnumToString((ENUM_TIMEFRAMES)Period())) == 0)
|
||||||
|
{
|
||||||
|
ObjectDelete(chart_id, obj_name_check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// prev_calculated is the number of bars calculated by the previous call.
|
||||||
|
// We want to start from one bar before the last one calculated by the previous call,
|
||||||
|
// to catch updates to the forming bar that has now closed, plus any new bars.
|
||||||
|
// rates_total - prev_calculated gives the number of new bars.
|
||||||
|
// We process (rates_total - prev_calculated) + 1 bars (the forming bar that closed + new bars)
|
||||||
|
// So, start from rates_total - (rates_total - prev_calculated + 1) = prev_calculated - 1
|
||||||
|
first_bar_to_calculate = prev_calculated - 1;
|
||||||
|
}
|
||||||
|
// Ensure we don't go out of bounds (e.g. if prev_calculated was 0 due to error or very few bars)
|
||||||
|
first_bar_to_calculate = MathMax(0, first_bar_to_calculate);
|
||||||
|
// We don't want to process the current, still-forming bar (index rates_total - 1 usually)
|
||||||
|
// So loop up to rates_total - 1 (or < rates_total)
|
||||||
|
// If we are processing historical bars, i can go up to rates_total - 1
|
||||||
|
// If we are processing only new bars, the last bar is rates_total - 1.
|
||||||
|
|
||||||
|
//--- Main loop for processing bars
|
||||||
|
// We iterate up to rates_total-1 because the last bar (rates_total-1) is the current forming bar
|
||||||
|
// We are interested in closed bars. So, the last closed bar is at index rates_total-2 if rates_total > 1.
|
||||||
|
// However, if we start from prev_calculated-1, this logic handles it correctly.
|
||||||
|
// The loop should go up to `rates_total - 1` to process all available historical bars.
|
||||||
|
// The current bar (index rates_total - 1) will be processed on the next tick once it closes and a new bar forms.
|
||||||
|
for (int i = first_bar_to_calculate; i < rates_total; i++)
|
||||||
|
{
|
||||||
|
// Skip the current forming bar (bar 0 in terminal, index rates_total-1 in array if processing live)
|
||||||
|
// This logic is implicitly handled by how OnCalculate is typically called.
|
||||||
|
// The loop goes from an older bar up to the most recent *available* bar data.
|
||||||
|
// The last bar in the `time`, `open`, etc. arrays is `rates_total - 1`.
|
||||||
|
// If `i == rates_total - 1`, it's the current, potentially unclosed bar.
|
||||||
|
// We generally want to analyze closed bars. Let's adjust the loop to `i < rates_total -1` if we only want confirmed closed bars.
|
||||||
|
// However, for drawing on historical data, `i < rates_total` is fine.
|
||||||
|
// The key is that `prev_calculated` helps us only recalculate what's necessary.
|
||||||
|
// Let's assume we process up to the last available bar, and if it's the current forming bar,
|
||||||
|
// its spike status might change. The object deletion logic handles this.
|
||||||
|
|
||||||
|
// If it's the very first bar available (index 0) and it has no history to form wicks properly, skip.
|
||||||
|
// This check might be too simplistic, but helps avoid issues with incomplete data at the start of history.
|
||||||
|
// if (i == 0 && rates_total < 3) continue; // This might be too restrictive.
|
||||||
|
|
||||||
|
// Define object names for this bar to manage them
|
||||||
|
// Using time ensures uniqueness per bar. Adding symbol and timeframe for robustness.
|
||||||
|
string obj_time_str = TimeToString(time[i], TIME_DATE | TIME_MINUTES | TIME_SECONDS); // Added seconds for more uniqueness
|
||||||
|
string bearish_obj_name = StringFormat("SpikeArrow_Bearish_%s_%s_%s", _Symbol, EnumToString((ENUM_TIMEFRAMES)Period()), obj_time_str);
|
||||||
|
string bullish_obj_name = StringFormat("SpikeArrow_Bullish_%s_%s_%s", _Symbol, EnumToString((ENUM_TIMEFRAMES)Period()), obj_time_str);
|
||||||
|
|
||||||
|
// Delete existing arrows for this bar before re-evaluating
|
||||||
|
// This allows settings changes to reflect immediately and removes arrows if a spike no longer qualifies
|
||||||
|
ObjectDelete(0, bearish_obj_name);
|
||||||
|
ObjectDelete(0, bullish_obj_name);
|
||||||
|
|
||||||
|
// Get OHLC for the current bar i
|
||||||
|
double O = open[i];
|
||||||
|
double H = high[i];
|
||||||
|
double L = low[i];
|
||||||
|
double C = close[i];
|
||||||
|
|
||||||
|
// Calculate candle components
|
||||||
|
double body_size = MathAbs(O - C);
|
||||||
|
double total_range = H - L;
|
||||||
|
double upper_wick = H - MathMax(O, C);
|
||||||
|
double lower_wick = MathMin(O, C) - L;
|
||||||
|
|
||||||
|
// Avoid division by zero or issues with flat candles (doji, etc.)
|
||||||
|
if (total_range < _Point * 0.1) // If candle range is very small, skip (e.g. less than 0.1 points)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool is_bearish_spike = false;
|
||||||
|
bool is_bullish_spike = false;
|
||||||
|
double body_plus_epsilon = body_size + (_Point * 0.01); // Add a very small value related to point size
|
||||||
|
|
||||||
|
// --- Bearish Spike Detection (Spike High) ---
|
||||||
|
// 1. Body is a small part of the total range
|
||||||
|
// 2. Upper wick is significantly larger than the body
|
||||||
|
// 3. Lower wick is small compared to the body (or upper wick)
|
||||||
|
if (body_size / total_range <= InpMaxBodyToTotalRangeRatio &&
|
||||||
|
upper_wick / body_plus_epsilon >= InpMinWickToBodyRatio &&
|
||||||
|
lower_wick / body_plus_epsilon <= InpMaxOppositeWickToBodyRatio &&
|
||||||
|
upper_wick > lower_wick) // Ensure upper wick is dominant
|
||||||
|
{
|
||||||
|
is_bearish_spike = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Bullish Spike Detection (Spike Low) ---
|
||||||
|
// 1. Body is a small part of the total range
|
||||||
|
// 2. Lower wick is significantly larger than the body
|
||||||
|
// 3. Upper wick is small compared to the body (or lower wick)
|
||||||
|
if (body_size / total_range <= InpMaxBodyToTotalRangeRatio &&
|
||||||
|
lower_wick / body_plus_epsilon >= InpMinWickToBodyRatio &&
|
||||||
|
upper_wick / body_plus_epsilon <= InpMaxOppositeWickToBodyRatio &&
|
||||||
|
lower_wick > upper_wick) // Ensure lower wick is dominant
|
||||||
|
{
|
||||||
|
is_bullish_spike = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Drawing ---
|
||||||
|
double arrow_offset_actual = InpArrowOffsetPoints * _Point;
|
||||||
|
|
||||||
|
if (is_bearish_spike)
|
||||||
|
{
|
||||||
|
if (ObjectCreate(0, bearish_obj_name, OBJ_ARROW, 0, time[i], H + arrow_offset_actual))
|
||||||
|
{
|
||||||
|
ObjectSetInteger(0, bearish_obj_name, OBJPROP_ARROWCODE, WINGDINGS_ARROW_DOWN); // Corrected
|
||||||
|
ObjectSetInteger(0, bearish_obj_name, OBJPROP_COLOR, InpBearishSpikeColor);
|
||||||
|
ObjectSetInteger(0, bearish_obj_name, OBJPROP_WIDTH, 1);
|
||||||
|
ObjectSetInteger(0, bearish_obj_name, OBJPROP_STYLE, STYLE_SOLID);
|
||||||
|
ObjectSetString(0, bearish_obj_name, OBJPROP_TOOLTIP, "Bearish Spike");
|
||||||
|
}
|
||||||
|
// else { PrintFormat("Failed to create bearish spike arrow for bar at %s. Error: %d", TimeToString(time[i]), GetLastError()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_bullish_spike)
|
||||||
|
{
|
||||||
|
if (ObjectCreate(0, bullish_obj_name, OBJ_ARROW, 0, time[i], L - arrow_offset_actual))
|
||||||
|
{
|
||||||
|
ObjectSetInteger(0, bullish_obj_name, OBJPROP_ARROWCODE, WINGDINGS_ARROW_UP); // Corrected
|
||||||
|
ObjectSetInteger(0, bullish_obj_name, OBJPROP_COLOR, InpBullishSpikeColor);
|
||||||
|
ObjectSetInteger(0, bullish_obj_name, OBJPROP_WIDTH, 1);
|
||||||
|
ObjectSetInteger(0, bullish_obj_name, OBJPROP_STYLE, STYLE_SOLID);
|
||||||
|
ObjectSetString(0, bullish_obj_name, OBJPROP_TOOLTIP, "Bullish Spike");
|
||||||
|
}
|
||||||
|
// else { PrintFormat("Failed to create bullish spike arrow for bar at %s. Error: %d", TimeToString(time[i]), GetLastError()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//--- Return value of prev_calculated for next call
|
||||||
|
return (rates_total);
|
||||||
|
}
|
||||||
|
//+------------------------------------------------------------------+
|
||||||
@@ -152,6 +152,14 @@ input bool eaReportSignals = true; // Report Signals
|
|||||||
input bool eaReportProtector = true; // Report Protector Actions
|
input bool eaReportProtector = true; // Report Protector Actions
|
||||||
input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished
|
input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished
|
||||||
|
|
||||||
|
//
|
||||||
|
// Collector ...
|
||||||
|
input group "Collector";
|
||||||
|
input bool eaSaveTrades = false; // Save Trades
|
||||||
|
input bool eaSaveSignals = false; // Save Signals
|
||||||
|
input bool eaSaveWins = false; // Save Winning Conditions
|
||||||
|
input bool eaSaveLosts = false; // Save Lost Conditions
|
||||||
|
|
||||||
//
|
//
|
||||||
// Variables ...
|
// Variables ...
|
||||||
|
|
||||||
@@ -446,7 +454,14 @@ void OnTick()
|
|||||||
eaSignal.targets,
|
eaSignal.targets,
|
||||||
eaConditions.targets //
|
eaConditions.targets //
|
||||||
);
|
);
|
||||||
eaSignal.conditions = eaCatbConditions.GenerateSummary();
|
eaSignal.conditions =
|
||||||
|
eaCatbConditions
|
||||||
|
.GenerateSummary(
|
||||||
|
false, // Commons ...
|
||||||
|
true, // Conditions ...
|
||||||
|
true, // Scores ...
|
||||||
|
false // Ignore Falses ...
|
||||||
|
);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Execute Signal ...
|
// Execute Signal ...
|
||||||
@@ -796,13 +811,18 @@ void InitRequirements()
|
|||||||
eaTradeManager = new XCXCATBEATradeManager(
|
eaTradeManager = new XCXCATBEATradeManager(
|
||||||
eaTrade //
|
eaTrade //
|
||||||
);
|
);
|
||||||
eaTradeManager.SaveTrades(true);
|
//
|
||||||
eaTradeManager.SetAlertPrefix(eaTag);
|
eaTradeManager.SetAlertPrefix(eaTag);
|
||||||
eaTradeManager.SetAlertLogAlerts(eaLogAlerts);
|
eaTradeManager.SetAlertLogAlerts(eaLogAlerts);
|
||||||
eaTradeManager.SetAlertMailAlerts(eaMailAlerts);
|
eaTradeManager.SetAlertMailAlerts(eaMailAlerts);
|
||||||
eaTradeManager.SetAlertPushAlerts(eaPushAlerts);
|
eaTradeManager.SetAlertPushAlerts(eaPushAlerts);
|
||||||
eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts);
|
eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts);
|
||||||
eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts);
|
eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts);
|
||||||
|
//
|
||||||
|
eaTradeManager.SaveWins(eaSaveWins);
|
||||||
|
eaTradeManager.SaveLosts(eaSaveLosts);
|
||||||
|
eaTradeManager.SaveTrades(eaSaveTrades);
|
||||||
|
eaTradeManager.SaveSignals(eaSaveSignals);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Setting Trade Reports ...
|
// Setting Trade Reports ...
|
||||||
|
|||||||
@@ -1665,6 +1665,32 @@ struct XSignal
|
|||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
string GetFileName()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string result = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
if (!IsValid())
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
result =
|
||||||
|
//
|
||||||
|
symbol + "\\" +
|
||||||
|
ToString(type) + "\\" +
|
||||||
|
ToString(period) + "_" +
|
||||||
|
ToFormatString(time)
|
||||||
|
//
|
||||||
|
;
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
///////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SaherElm IT Center MQL5 Indicator
|
||||||
|
// -------------------------------------------------
|
||||||
|
// Name: XCXCATBEASignaller ...
|
||||||
|
// Description: Class for XCATBEA Signaller ...
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Maintainer:
|
||||||
|
// ------------
|
||||||
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Global Properties ...
|
||||||
|
#property library
|
||||||
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
||||||
|
#property link "https://saherelm.ir"
|
||||||
|
#property version "1.00"
|
||||||
|
#property description "SaherElm Class for XCATBEA Signaller"
|
||||||
|
#property strict
|
||||||
|
|
||||||
|
//
|
||||||
|
// Imports ...
|
||||||
|
#include "../Libraries/xcatbea.lib.mq5";
|
||||||
|
#include "../Libraries/xcatbea.signaller.lib.mq5";
|
||||||
|
|
||||||
|
//
|
||||||
|
// Definitions ...
|
||||||
|
class XCXCATBEASignaller : XCBase
|
||||||
|
{
|
||||||
|
};
|
||||||
@@ -114,10 +114,10 @@ class XCXCATBEADataCollector : public XCBase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save Specified Content into Specified File Name ...
|
* Save Specified Content into Specified File Name ...
|
||||||
*
|
*
|
||||||
* @param fileName: string, file name ...
|
* @param fileName: string, file name ...
|
||||||
* @param content: string, content ...
|
* @param content: string, content ...
|
||||||
*
|
*
|
||||||
* @return ( bool )
|
* @return ( bool )
|
||||||
*/
|
*/
|
||||||
bool Save(
|
bool Save(
|
||||||
@@ -153,6 +153,48 @@ class XCXCATBEADataCollector : public XCBase
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append Specified Content into Specified File Name ...
|
||||||
|
*
|
||||||
|
* @param fileName: string, file name ...
|
||||||
|
* @param content: string, content ...
|
||||||
|
*
|
||||||
|
* @return ( bool )
|
||||||
|
*/
|
||||||
|
bool Append(
|
||||||
|
string fileName,
|
||||||
|
string content //
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
result = IsValid(content);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
int mHandler = GetFileHandlerForWrite(fileName);
|
||||||
|
result = mHandler != INVALID_HANDLE;
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
FileSeek(mHandler, 0, SEEK_END);
|
||||||
|
FileWrite(mHandler, content);
|
||||||
|
FileFlush(mHandler);
|
||||||
|
FileClose(mHandler);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Protected ...
|
// Protected ...
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -459,15 +459,15 @@ struct XCATBEATrade
|
|||||||
//
|
//
|
||||||
result =
|
result =
|
||||||
//
|
//
|
||||||
ToString("Swap: ", swap) +
|
ToString("Swap", swap) +
|
||||||
ToString("Profit: ", profit) +
|
ToString("Profit", profit) +
|
||||||
ToString("Commission: ", commission) +
|
ToString("Commission", commission) +
|
||||||
ToString("Finalize: ", ToString(finalize)) +
|
ToString("Finalize", ToString(finalize)) +
|
||||||
ToString("PositionID: ", positionID) +
|
ToString("PositionID", positionID) +
|
||||||
ToString("----------------") + "\n" +
|
ToString("----------------") + "\n" +
|
||||||
ToString("Signaled At: ", ToFormatString(signaledAt)) +
|
ToString("Signaled At", ToFormatString(signaledAt)) +
|
||||||
ToString("Executed At: ", ToFormatString(executedAt)) +
|
ToString("Executed At", ToFormatString(executedAt)) +
|
||||||
ToString("Finalized At: ", ToFormatString(finalizedAt))
|
ToString("Finalized At", ToFormatString(finalizedAt))
|
||||||
//
|
//
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -581,6 +581,111 @@ struct XCATBEATrade
|
|||||||
//
|
//
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string GetConditionsString()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string result = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
double bullishScore = 0;
|
||||||
|
double bearishScore = 0;
|
||||||
|
conditions
|
||||||
|
.conditions
|
||||||
|
.GenerateScore(
|
||||||
|
bullishScore,
|
||||||
|
bearishScore //
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
string conditionsStr =
|
||||||
|
conditions
|
||||||
|
.conditions
|
||||||
|
.GenerateSummary(
|
||||||
|
false,
|
||||||
|
true, // Only Conditions ...
|
||||||
|
false,
|
||||||
|
false // Ignore False Conditions ...
|
||||||
|
);
|
||||||
|
string condParts[];
|
||||||
|
int condPartsCount = SplitContent(
|
||||||
|
condParts,
|
||||||
|
conditionsStr,
|
||||||
|
"\n" //
|
||||||
|
);
|
||||||
|
if (IsValidSize(condPartsCount))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
conditionsStr = NULL;
|
||||||
|
while (HasChild(condParts))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string iStr = condParts[0];
|
||||||
|
ArrayRemove(
|
||||||
|
condParts,
|
||||||
|
0,
|
||||||
|
1 //
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
bool isLast = !HasChild(condParts);
|
||||||
|
|
||||||
|
//
|
||||||
|
bool isCond = Contains(
|
||||||
|
"is",
|
||||||
|
iStr,
|
||||||
|
false //
|
||||||
|
);
|
||||||
|
if (isCond)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string iParts[];
|
||||||
|
int iPartsCount = SplitContent(
|
||||||
|
iParts,
|
||||||
|
iStr,
|
||||||
|
":" //
|
||||||
|
);
|
||||||
|
if (iPartsCount == 2)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string iVal = iParts[1];
|
||||||
|
StringTrimLeft(iVal);
|
||||||
|
StringTrimRight(iVal);
|
||||||
|
bool isPassed = ToBoolean(iVal);
|
||||||
|
conditionsStr += (isPassed ? "" : "!") + "conditions." + iParts[0] + (!isLast ? " &&" : "") + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Clean(condParts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conditionsStr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
result =
|
||||||
|
"(" + "\n" +
|
||||||
|
"\\" + "\\" + " " + ToString("Type", ToString(signal.type)) +
|
||||||
|
"\\" + "\\" + " " + ToString("Profit", profit) +
|
||||||
|
"\\" + "\\" + " " + ToString("Finalize", ToString(finalize)) +
|
||||||
|
"\\" + "\\" + " " + ToString("PositionID", positionID) +
|
||||||
|
"\\" + "\\" + " " + ToString("----------------") + "\n" +
|
||||||
|
"\\" + "\\" + " " + ToString("Signaled At", ToFormatString(signaledAt)) +
|
||||||
|
"\\" + "\\" + " " + ToString("Executed At", ToFormatString(executedAt)) +
|
||||||
|
"\\" + "\\" + " " + ToString("Finalized At", ToFormatString(finalizedAt)) +
|
||||||
|
"\\" + "\\" + " " + ToString("----------------") + "\n" +
|
||||||
|
"\\" + "\\" + " " + ToString("Scores:") + "\n" +
|
||||||
|
"\\" + "\\" + " " + ToString("Bullish", bullishScore) +
|
||||||
|
"\\" + "\\" + " " + ToString("Bearish", bearishScore) +
|
||||||
|
"\\" + "\\" + " " + ToString("----------------") + "\n" +
|
||||||
|
conditionsStr +
|
||||||
|
(IsValid(conditionsStr) ? "" : "") +
|
||||||
|
") && ";
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -677,6 +782,42 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
mSaveTrades = value;
|
mSaveTrades = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
bool SaveSignals()
|
||||||
|
{
|
||||||
|
return mSaveSignals;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void SaveSignals(bool value)
|
||||||
|
{
|
||||||
|
mSaveSignals = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
bool SaveWins()
|
||||||
|
{
|
||||||
|
return mSaveWins;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void SaveWins(bool value)
|
||||||
|
{
|
||||||
|
mSaveWins = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
bool SaveLosts()
|
||||||
|
{
|
||||||
|
return mSaveLosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void SaveLosts(bool value)
|
||||||
|
{
|
||||||
|
mSaveLosts = value;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
void SetForceCloseTradesAt(
|
void SetForceCloseTradesAt(
|
||||||
string _forceCloseAt //
|
string _forceCloseAt //
|
||||||
@@ -1191,6 +1332,9 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
SendAlert(message);
|
SendAlert(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
SaveSignal(signal);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check Trade Permission ...
|
// Check Trade Permission ...
|
||||||
if (!allowTrade)
|
if (!allowTrade)
|
||||||
@@ -1480,7 +1624,8 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
|
|
||||||
//
|
//
|
||||||
// Save Trade ...
|
// Save Trade ...
|
||||||
Save(trades[idx]);
|
SaveWin(trades[idx]);
|
||||||
|
SaveTrade(trades[idx]);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Handle Balance Reporting ...
|
// Handle Balance Reporting ...
|
||||||
@@ -1533,7 +1678,7 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
|
|
||||||
//
|
//
|
||||||
// Save Trade ...
|
// Save Trade ...
|
||||||
Save(trades[idx]);
|
SaveTrade(trades[idx]);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Handle Balance Reporting ...
|
// Handle Balance Reporting ...
|
||||||
@@ -1545,6 +1690,14 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
|
|
||||||
//
|
//
|
||||||
bool isInProfit = trades[idx].profit > 0;
|
bool isInProfit = trades[idx].profit > 0;
|
||||||
|
if (isInProfit)
|
||||||
|
{
|
||||||
|
SaveWin(trades[idx]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SaveLost(trades[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
XCATBEASymbolInfo iSymbolInfo;
|
XCATBEASymbolInfo iSymbolInfo;
|
||||||
@@ -1605,7 +1758,15 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
|
|
||||||
//
|
//
|
||||||
// Save Trade ...
|
// Save Trade ...
|
||||||
Save(trades[idx]);
|
SaveTrade(trades[idx]);
|
||||||
|
if (isInProfit)
|
||||||
|
{
|
||||||
|
SaveWin(trades[idx]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SaveLost(trades[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Handle Balance Reporting ...
|
// Handle Balance Reporting ...
|
||||||
@@ -1863,17 +2024,17 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
// Tools ...
|
// Tools ...
|
||||||
|
|
||||||
//
|
//
|
||||||
string GetFilePath(XCATBEATrade &trade)
|
string GetTradeFilePath(XCATBEATrade &trade)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
string fileName = trade.GetFileName();
|
string fileName = trade.GetFileName();
|
||||||
|
|
||||||
//
|
//
|
||||||
return GetFilePath(fileName);
|
return GetTradeFilePath(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
string GetFilePath(string fileName)
|
string GetTradeFilePath(string fileName)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
string result = NULL;
|
string result = NULL;
|
||||||
@@ -1892,6 +2053,72 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
string GetSignalFilePath(string fileName)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string result = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
string mPath = collector.Path();
|
||||||
|
|
||||||
|
//
|
||||||
|
result =
|
||||||
|
//
|
||||||
|
mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log"
|
||||||
|
//
|
||||||
|
;
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
string GetWinsFilePath(XCATBEATrade &trade)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string result = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
string mPath = collector.Path();
|
||||||
|
|
||||||
|
//
|
||||||
|
result =
|
||||||
|
//
|
||||||
|
mPath + "\\" +
|
||||||
|
"Conditions" + "\\" +
|
||||||
|
trade.signal.symbol + "\\" +
|
||||||
|
ToString(trade.signal.period) + "_wins.x121.log"
|
||||||
|
//
|
||||||
|
;
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
string GetLostsFilePath(XCATBEATrade &trade)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
string result = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
string mPath = collector.Path();
|
||||||
|
|
||||||
|
//
|
||||||
|
result =
|
||||||
|
//
|
||||||
|
mPath + "\\" +
|
||||||
|
"Conditions" + "\\" +
|
||||||
|
trade.signal.symbol + "\\" +
|
||||||
|
ToString(trade.signal.period) + "_losts.x121.log"
|
||||||
|
//
|
||||||
|
;
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
void HandleReportBalance(string prefix = NULL)
|
void HandleReportBalance(string prefix = NULL)
|
||||||
{
|
{
|
||||||
@@ -1928,7 +2155,8 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
bool Save(
|
// Save Trades ...
|
||||||
|
bool SaveTrade(
|
||||||
XCATBEATrade &trade,
|
XCATBEATrade &trade,
|
||||||
bool includeSummary = true,
|
bool includeSummary = true,
|
||||||
bool includeSignal = true,
|
bool includeSignal = true,
|
||||||
@@ -1945,7 +2173,7 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
string filePath = GetFilePath(trade);
|
string filePath = GetTradeFilePath(trade);
|
||||||
result = IsValid(filePath);
|
result = IsValid(filePath);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
@@ -1969,6 +2197,139 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save Signals ...
|
||||||
|
bool SaveSignal(XSignal &signal)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check Signal Save is Enabled ...
|
||||||
|
if (!mSaveSignals)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check Signal Validation ...
|
||||||
|
if (!signal.IsValid())
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Retrieve Signal File Name ...
|
||||||
|
string signalFileName = signal.GetFileName();
|
||||||
|
result = IsValid(signalFileName);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Retriev and Validate File Name ...
|
||||||
|
string filePath = GetSignalFilePath(signalFileName);
|
||||||
|
result = IsValid(filePath);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate Content ...
|
||||||
|
string content = "";
|
||||||
|
content +=
|
||||||
|
ToString("----------------") + "\n" +
|
||||||
|
ToString("Signal: ") + "\n" +
|
||||||
|
ToString("----------------") + "\n" +
|
||||||
|
signal.ToString() + "\n";
|
||||||
|
content +=
|
||||||
|
ToString("----------------") + "\n" +
|
||||||
|
ToString("Conditions: ") + "\n" +
|
||||||
|
ToString("----------------") + "\n" +
|
||||||
|
signal.conditions + "\n";
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save Content to File ...
|
||||||
|
result = collector.Save(
|
||||||
|
filePath,
|
||||||
|
content //
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return Result ...
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
bool SaveWin(XCATBEATrade &trade)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
if (!mSaveWins)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
string filePath = GetWinsFilePath(trade);
|
||||||
|
result = IsValid(filePath);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Preparing Conditions Content ...
|
||||||
|
string content = trade.GetConditionsString();
|
||||||
|
|
||||||
|
//
|
||||||
|
result = collector.Append(
|
||||||
|
filePath,
|
||||||
|
content //
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
bool SaveLost(XCATBEATrade &trade)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
//
|
||||||
|
if (!mSaveLosts)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
string filePath = GetLostsFilePath(trade);
|
||||||
|
result = IsValid(filePath);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Preparing Conditions Content ...
|
||||||
|
string content = trade.GetConditionsString();
|
||||||
|
|
||||||
|
//
|
||||||
|
result = collector.Append(
|
||||||
|
filePath,
|
||||||
|
content //
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Symbol Info ...
|
// Symbol Info ...
|
||||||
|
|
||||||
@@ -2277,7 +2638,10 @@ class XCXCATBEATradeManager : public XCBaseAlert
|
|||||||
ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD restrictionsPeriod;
|
ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD restrictionsPeriod;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
bool mSaveWins;
|
||||||
|
bool mSaveLosts;
|
||||||
bool mSaveTrades;
|
bool mSaveTrades;
|
||||||
|
bool mSaveSignals;
|
||||||
|
|
||||||
//
|
//
|
||||||
bool reportTrades;
|
bool reportTrades;
|
||||||
|
|||||||
Reference in New Issue
Block a user