/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- // Name: XCXTradeManager // Description: provides all Trade Management requirements ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Imports ... #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-data.collector.class.mq5" #include "../Classes/x-saherelm.x-guard.class.mq5" #include "../Classes/x-saherelm.x-target.class.mq5" #include "../Classes/x-saherelm.x-poi.drawer.class.mq5" #include "../Classes/x-saherelm.x-trade.class.mq5" #include "../Classes/x-saherelm.x-volume.class.mq5" // // Implementation ... class XCTradeManager : public XCBase { // // Public ... public: // // Props ... XCAlert *alert; XCGuard *guard; XCTrade *trader; XCTarget *target; XCVolume *volume; XTimeTracker timeTracker; XCDataCollector *collector; // XCPOIDrawer *drawer; // TCheckForGuard checkForGuardEventListener; // // Constructor ... XCTradeManager( XCAlert *_alert, XCTrade *_trader, XCVolume *_volume, XCGuard *_guard, XCTarget *_target // ) { // alert = _alert; guard = _guard; volume = _volume; trader = _trader; target = _target; // drawer = new XCPOIDrawer(); // allowTrade = true; allowLongs = true; allowShorts = true; // reportTrades = true; reportSignals = true; reportProtector = true; reportAfterTradesBalance = true; // SaveTrades(false); // collector = new XCDataCollector(); // // Setting Collector Path ... string mPath = (IsValid(alert.GetPrefix()) ? alert.GetPrefix() + "\\" : "") + trader.mAccount.GetCompany(); collector.Path(mPath); } // // Deconstructor ... ~XCTradeManager() { // Clean(trades); // timeTracker.Clean(); // delete drawer; ZeroMemory(drawer); // delete collector; ZeroMemory(collector); } // // Properties ... // bool SaveTrades() { return mSaveTrades; } // void SaveTrades(bool 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; } // bool SaveRestrictions() { return mSaveRestrictions; } // void SaveRestrictions(bool value) { mSaveRestrictions = value; } // // Setter(s) ... // void SetSymbolConfigurations(string symbolConfiguration) { // int count = 0; bool has = false; // // If Not Provided ... has = IsSpecifiedValid(symbolConfiguration); if (!has) { // AddDefaultSymbolConfiguration(); return; } // // Try to Parse Data ... string symbolData[]; count = SplitContent( symbolData, symbolConfiguration, "]" // ); has = IsValidSize(count); if (!has) { // AddDefaultSymbolConfiguration(); // SpecifiedClean(symbolData); return; } // // Loop through Exists Symbol Data's ... for (int i = 0; i < count; i++) { // string iData = symbolData[i]; // // Extract Data Parts ... string iParts[]; int iPartsCount = SplitContent( iParts, iData, "|" // ); has = IsValidSize(iPartsCount); if (has) { // // Determines Required Parts ... bool hasName = iPartsCount >= 1; bool hasSymbol = iPartsCount >= 2; bool hasPeriod = iPartsCount >= 3; bool hasSessionsDescriptor = iPartsCount >= 4; bool hasMaxAllowedSpred = iPartsCount >= 5; bool hasMaxAllowedPositios = iPartsCount >= 6; bool hasRestrictionDescriptor = iPartsCount >= 7; // // Parts IDX ... int partsIDX = 0; // // Extract Name ... string iName = hasName ? iParts[partsIDX] : ""; iName = EscapeString(iName); partsIDX++; // // Extract Symbol ... string iSymbol = hasSymbol ? iParts[partsIDX] : _Symbol; iSymbol = EscapeString(iSymbol); iSymbol = NormalizeSymbol(iSymbol); partsIDX++; // // Extract Period ... ENUM_TIMEFRAMES iPeriod = hasPeriod ? ToPeriod(EscapeString(iParts[partsIDX])) : _Period; iPeriod = NormalizePeriod(iPeriod); partsIDX++; // // Extract Sessions Descriptor ... string iSessionsDescriptor = hasSessionsDescriptor ? iParts[partsIDX] : ""; iSessionsDescriptor = EscapeString(iSessionsDescriptor); partsIDX++; // // Extract Max Allowed Sspread ... double iMaxAllowedSpread = hasMaxAllowedSpred ? (double)(EscapeString(iParts[partsIDX])) : 25; partsIDX++; // // Extract Max Allowedd Positions ... int iMaxAllowedPositions = hasMaxAllowedPositios ? (int)(EscapeString(iParts[partsIDX])) : 5; partsIDX++; // // Extract Restrictions Descriptor ... string iRestrictionsDescriptor = hasRestrictionDescriptor ? iParts[partsIDX] : ""; iRestrictionsDescriptor = EscapeString(iRestrictionsDescriptor); partsIDX++; // XSymbolTradeConfig iConfig; // // Initialize Config ... has = iConfig.Init( iName, iSymbol, iPeriod, iSessionsDescriptor, iMaxAllowedSpread, iMaxAllowedPositions, iRestrictionsDescriptor // ); if (has) { AddOrUpdateSymbolConfiguration(iConfig); } // // Cleanup Resources ... iConfig.Clean(); } // // Cleanup Resources ... SpecifiedClean(iParts); } // // Cleanup Resources ... SpecifiedClean(symbolData); } // int FillSymbolConfigurations(XSymbolTradeConfig &dest[]) { // SpecifiedClean(dest); // Copy( symbolTradeConfigs, dest // ); // int result = ArraySize(dest); // return result; } // void SetTradeReports( bool _reportTrades, bool _reportSignals, bool _reportProtector, bool _reportRestrictions, bool _reportAfterTradesBalance // ) { // reportTrades = _reportTrades; reportSignals = _reportSignals; reportProtector = _reportProtector; reportRestrictions = _reportRestrictions; reportAfterTradesBalance = _reportAfterTradesBalance; } // void SetTradePermissions( bool _allowTrade, bool _allowLongs, bool _allowShorts // ) { // allowTrade = _allowTrade; allowLongs = _allowLongs; allowShorts = _allowShorts; } // // Tools and Helpers ... /** * Do All Position Managing Senaros ... */ void Manage() { // // Handle Restrictions ... HandleRestrictions(); // // Managing Targets ... target.Manage(); // // Check Contains Trades for Managing ... bool has = HasChild(trades); if (!has) { return; } // // Update Required Infos of Trades ... int count = ArraySize(trades); for (int i = 0; i < count; i++) { // has = trades[i].IsExecuted() && !trades[i].IsFinalized(); if (!has) { continue; } // XPosition iPosition; has = trader.GetPosition( trades[i].positionID, iPosition // ); if (!has) { continue; } // // Update Trade Data ... trades[i].swap = iPosition.swap; trades[i].profit = iPosition.profit; } // // Do Trade Protection ... Protect(); } /** * Do All Position Protection Here ... */ void Protect() { // string prefix = "Protector: "; int targetDistance = 5; // bool has = HasChild(trades); if (!has) { return; } // XPosition ownPosition[]; XPosition ownLongPosition[]; XPosition ownShortPosition[]; // int count = ArraySize(trades); for (int i = 0; i < count; i++) { // has = trades[i].IsExecuted() && !trades[i].IsFinalized(); if (!has) { continue; } // XPosition iPosition; has = trader.GetPosition( trades[i].positionID, iPosition // ); if (!has) { continue; } // AddRef( iPosition, ownPosition // ); // if (IsLong(iPosition.type)) { // AddRef( iPosition, ownLongPosition // ); } else { // AddRef( iPosition, ownShortPosition // ); } } // has = HasChild(ownPosition); if (!has) { // Clean(ownPosition); Clean(ownLongPosition); Clean(ownShortPosition); // return; } // XGuard guards[]; int guardsCount = CheckForGuard(guards); bool hasGuard = IsValidSize(guardsCount); if (hasGuard) { // guard.DoGuards(guards); } // double swapSum = 0; double profitSum = 0; double commissionSum = 0; // // Calculate Required Data On Collection ... count = ArraySize(ownPosition); for (int i = 0; i < count; i++) { // XPosition iPosition = ownPosition[i]; // swapSum += iPosition.swap; profitSum += iPosition.profit; commissionSum += iPosition.commission; } // // Do Collection Protectiong ... // // Handle Force Close At Time ... has = HandleForceCloseAtTime(); if (has) { // Clean(ownPosition); Clean(ownLongPosition); Clean(ownShortPosition); // return; } // // Do Signle Protections ... for (int i = 0; i < count; i++) { // // Select Position ... XPosition iPosition = ownPosition[i]; int idx = -1; has = HasTrade( idx, iPosition.ticket // ); if (!has) { continue; } // bool isLong = IsLong(iPosition.type); double points = GetPoints(iPosition.symbol); // // Handle RF On Targets ... if (iPosition.profit > 0) { // // Handle Risk Free On Targets ... XTarget targets[]; Copy( trades[idx].signal.targets, targets // ); int targetsCount = ArraySize(targets); has = IsValidSize(targetsCount); if (has) { // for (int j = 0; j < targetsCount; j++) { // XTarget jTarget = targets[j]; // int appliedTargetIDX = -1; // // Check Target is Applied Before or Not ... has = !trades[idx].signal.isTargetApplied ? true : trades[idx].signal.appliedTargetIDX < j; if (!has) { continue; } // // Check Traget Validation ... has = iPosition.sl == 0 ? true : isLong ? iPosition.sl < jTarget.target : iPosition.sl > jTarget.target; if (!has) { continue; } // double targetDelta = isLong ? jTarget.target + (targetDistance * points) : jTarget.target - (targetDistance * points); // // Can Risk Free ... bool canRF = jTarget.doRF && jTarget.target > 0 && (isLong ? jTarget.target > iPosition.entry : jTarget.target < iPosition.entry) && (isLong ? iPosition.price > targetDelta : iPosition.price < targetDelta); // // Can Partial Close ... bool canPC = jTarget.volumeMultiplier > 0 && jTarget.target > 0 && (isLong ? jTarget.target > iPosition.entry : jTarget.target < iPosition.entry) && (isLong ? iPosition.price > targetDelta : iPosition.price < targetDelta); bool canRFPC = canRF || canPC; if (canRFPC) { // // Handle Risk Free ... bool isRFDone = false; if (canRF) { // double tp = iPosition.tp; double sl = jTarget.target; string comment = "RF On Target ..."; isRFDone = trader.Modify( iPosition.ticket, sl, tp, comment // ); } // // Handle Partail Close ... bool isPCDone = false; if (canPC) { // double _volume = jTarget.volumeMultiplier * iPosition.volume; _volume = NormalizeVolume(_volume, iPosition.symbol); string comment = "RF On Target ..."; isPCDone = trader.ClosePartial( iPosition.ticket, _volume, comment // ); } // // Handle Report Action ... bool isRFPCDone = isRFDone || isPCDone; if (isRFPCDone) { // trades[idx].signal.appliedTargetIDX = j; trades[idx].signal.isTargetApplied = true; // string message = prefix + ToXString(iPosition.type) + " Position: " + ToXString(iPosition.ticket) + (isRFDone ? " RF" : "") + (isPCDone ? " PC" : "") + " On Traget: " + ToXString(jTarget.target) + " Successfully ..."; HandleReportProtector(message); } } } } } } } /** * Check Can Analyse Market based on Configurations ... * * @param symbol: Symbol * @param period: Period * @param time: Analysing Time * * @return ( bool ) */ bool CanAnalyse( string symbol, ENUM_TIMEFRAMES period, datetime time // ) { // bool result = false; // // Finding Symbol Configuration Index ... int idx = FindSymbolConfigurationIndex( symbol, period // ); // // If Not Exists ... if (!IsValidIndex(idx)) { // result = true; return result; } // // If Exists ... // // Check Session is Active ... result = symbolTradeConfigs[idx].CanTrade(time); if (!result) { return result; } // // Check Symbol Restrictions ... result = symbolTradeConfigs[idx].IsRestricted(time); if (!result) { return result; } // return result; } /** * Check Signal Execution Conditions ... * * @param signal: XSignal instance reference ... * @param executionResult: ENUM_X_SIGNAL_EXECUTION_RESULT member reference ... * * @return ( bool ) */ bool CheckSignal( XSignal &signal, ENUM_X_SIGNAL_EXECUTION_RESULT &executionResult // ) { // bool result = false; // // Cleanup ... executionResult = X_SIGNAL_EXECUTION_UNKNOWN; // // Validate Signal ... result = signal.IsValid(); if (!result) { return result; } // // Reporting Signal ... if (reportSignals) { // string message = signal.GetMessage("Provided"); alert.SendAlert(message); } // SaveSignal(signal); // // Check Trade Permission ... result = AllowTrade(signal.type); if (!result) { // result = false; executionResult = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; // return result; } // // Check Sessions and Restrictions ... result = CanAnalyse( signal.symbol, signal.period, signal.time // ); if (!result) { // executionResult = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; // return result; } // // Check Signal Spread ... int idx = FindSymbolConfigurationIndex( signal.symbol, signal.period // ); if (IsValidIndex(idx)) { // double spread = GetSpread(signal.symbol); result = symbolTradeConfigs[idx].maxAllowedSpread > 0 ? spread <= symbolTradeConfigs[idx].maxAllowedSpread : true; if (!result) { // executionResult = X_SIGNAL_EXECUTION_FAILED_SPREAD; // return result; } // // Checking Max Allowed Positions ... if (symbolTradeConfigs[idx].maxAllowedPositions > 0) { // XPosition positions[]; ENUM_X_POSITION_TYPES mType = IsLong(signal.type) ? X_POSITION_TYPE_LONG : X_POSITION_TYPE_SHORT; int positionsCount = trader.GetPositions( positions, symbolTradeConfigs[idx].symbol, NULL, // All Providers ... symbolTradeConfigs[idx].period, mType, true, // Filter By Magic ... true // Force Clean ... ); result = !IsValidSize(positionsCount) || (IsValidSize(positionsCount) && positionsCount < symbolTradeConfigs[idx].maxAllowedPositions); // // Cleanup Resources ... SpecifiedClean(positions); } } // return result; } /** * Check Allow Trade or not .. * * @param type: ENUM_POSITIO_TYPE * * @return ( bool ) */ bool AllowTrade(ENUM_POSITION_TYPE type) { // bool result = false; // result = allowTrade; if (!result) { return result; } // result = (IsLong(type) && allowLongs) || (IsShort(type) && allowShorts); // return result; } /** * Execute Specified Signal ... * * @param signal: XSignal instance reference ... * @param conditions: XCATBEAStrategyConditions instance reference ... * * @return ( bool ) */ bool Execute(XSignal &signal) { // bool result = false; // result = signal.IsValid(); if (!result) { return result; } // int idx = -1; bool isExists = HasTrade( idx, signal // ); result = !isExists; if (!result) { return result; } // ENUM_X_SIGNAL_EXECUTION_RESULT executionResult; // // Checking Signal For Execution ... result = CheckSignal( signal, executionResult // ); if (result) { // result = trader.ExecuteSignal( signal, executionResult // ); } // // Alert Signal Execution ... if (reportTrades) { // string executionMessage = ToString(executionResult); // string message = NULL; if (result) { message = signal.GetMessage("Executed"); } else { message = signal.GetMessage("Failed due (" + executionMessage + ")"); } // alert.SendAlert(message); } // if (result) { // // Create Trade Struct ... XTradeInfo iTrade; // ulong positionID = trader.GetLastOpenPositionTicket(); double commission = trader.GetPositionCommission(positionID); // iTrade.signal = signal; iTrade.positionID = positionID; iTrade.commission = commission; iTrade.signaledAt = signal.time; iTrade.executedAt = TimeCurrent(); iTrade.conditions = signal.conditions; // AddRef( iTrade, trades // ); } // return result; } /** * Retrieve Specified Positions ... * * @param positions: XPosition instance Reference Array, which holds Founded Positions ... * @param symbol: string, Specified Symbol Name ... * @param provider: string, Specified Provider Name ... * @param period: ENUM_TIMEFRAMES, Specified Period ... * * @return ( int ) */ int GetPositions( XPosition &positions[], string symbol, string provider, ENUM_TIMEFRAMES period // ) { // int result = 0; // Clean(positions); // bool has = IsValid(symbol) && IsValid(period) && IsValid(provider); if (!has) { return result; } // result = trader.GetPositions( positions, symbol, provider, period, NULL, // All Types ... true, // Filter By Magic ... true // Force Clean ... ); // result = ArraySize(positions); // return result; } /** * Handle Signal Recieved ... * * @param signal: XSignal */ void HandleSignal(XSignal &signal) { // // Validate Signal ... if (!signal.IsValid()) { return; } // // Check Signal ... bool isExecuted = false; ENUM_X_SIGNAL_EXECUTION_RESULT signalExecutionResult; bool canExecute = CheckSignal( signal, signalExecutionResult // ); if (canExecute) { // HandleSignalVolume(signal); isExecuted = Execute(signal); } // // Draw Signal Object ... XCSignalObject *signalObj; bool has = drawer.DrawSignal( signal, signalObj, 4 // ); if (has) { mObjects.Add(signalObj); } } /** * Handle Position Take Profit ... * * @param deal: XDeal instance reference ... */ void HandleTP(const XDeal &deal) { // // Check Ticket Exists or not ... int idx = -1; bool isExists = HasTrade( idx, deal.positionId // ); if (!isExists) { return; } // // Apply Required Data ... trades[idx].swap = deal.swap; trades[idx].profit = deal.profit; trades[idx].finalizedAt = TimeCurrent(); trades[idx].finalize = XTRADE_FINAL_TP; // // Save Trade ... SaveWin(trades[idx]); SaveTrade(trades[idx]); // // Handle Balance Reporting ... string prefix = "TP: " + ToXString(trades[idx].profit); HandleReportBalance(prefix); // // Handle Symbol Config ... // int configIdx = FindSymbolConfigurationIndex( trades[idx].signal.symbol, trades[idx].signal.period // ); isExists = IsValidIndex(configIdx); if (isExists) { // symbolTradeConfigs[configIdx].profits += 1; symbolTradeConfigs[configIdx].managedTPs += 1; symbolTradeConfigs[configIdx].managedProfits += trades[idx].profit; } // RemoveTrade(idx); // target.HandleOnTakeProfitTriggered(deal); } /** * Handle Position Stop Loss ... * * @param deal: XDeal instance reference ... */ void HandleSL(const XDeal &deal) { // // Check Ticket Exists or not ... int idx = -1; bool isExists = HasTrade( idx, deal.positionId // ); if (!isExists) { return; } // // Apply Required Data ... trades[idx].swap = deal.swap; trades[idx].profit = deal.profit; trades[idx].finalizedAt = TimeCurrent(); trades[idx].finalize = XTRADE_FINAL_SL; // // Save Trade ... SaveTrade(trades[idx]); // // Handle Balance Reporting ... string prefix = "SL: " + ToXString(trades[idx].profit); HandleReportBalance(prefix); // // Handle Symbol Info ... // bool isInProfit = trades[idx].profit > 0; if (isInProfit) { SaveWin(trades[idx]); } else { SaveLost(trades[idx]); } // // Handle Symbol Config ... // int configIdx = FindSymbolConfigurationIndex( trades[idx].signal.symbol, trades[idx].signal.period // ); isExists = IsValidIndex(configIdx); if (isExists) { // if (isInProfit) { // symbolTradeConfigs[configIdx].profits += 1; symbolTradeConfigs[configIdx].managedTPs += 1; } else { // symbolTradeConfigs[configIdx].losses += 1; symbolTradeConfigs[configIdx].managedSLs += 1; } // symbolTradeConfigs[configIdx].managedProfits += trades[idx].profit; } // RemoveTrade(idx); // target.HandleOnStopLossTriggered(deal); } /** * Handle Position Force Close ... * * @param deal: XDeal instance reference ... */ void HandleForceClose(const XPosition &position) { // // Check Ticket Exists or not ... int idx = -1; bool isExists = HasTrade( idx, position.ticket // ); if (!isExists) { return; } // bool isInProfit = position.profit > 0; // // Apply Required Data ... trades[idx].swap = position.swap; trades[idx].profit = position.profit; trades[idx].finalizedAt = TimeCurrent(); trades[idx].commission = position.commission; trades[idx].finalize = isInProfit ? XTRADE_FINAL_CLOSE_IN_PROFIT : XTRADE_FINAL_CLOSE_IN_LOSE; // // Save Trade ... SaveTrade(trades[idx]); if (isInProfit) { SaveWin(trades[idx]); } else { SaveLost(trades[idx]); } // // Handle Balance Reporting ... string prefix = "Force Close " + (isInProfit ? "Profit" : "Loss") + ": " + ToXString(trades[idx].profit); HandleReportBalance(prefix); // // Handle Symbol Config ... // int configIdx = FindSymbolConfigurationIndex( trades[idx].signal.symbol, trades[idx].signal.period // ); isExists = IsValidIndex(configIdx); if (isExists) { // if (isInProfit) { // symbolTradeConfigs[configIdx].profits += 1; symbolTradeConfigs[configIdx].managedTPs += 1; } else { // symbolTradeConfigs[configIdx].losses += 1; symbolTradeConfigs[configIdx].managedSLs += 1; } // symbolTradeConfigs[configIdx].managedProfits += trades[idx].profit; } // RemoveTrade(idx); // target.HandleOnPositionForceClosed( position.ticket, position, position.comment // ); } /** * Handle All Symbols Config Force Close At Time ... * * @return ( bool ) */ bool HandleForceCloseAtTime() { // bool result = false; // // Check Symbol Config Exists ... result = HasChild(symbolTradeConfigs); if (!result) { return result; } // result = false; int count = ArraySize(symbolTradeConfigs); for (int i = 0; i < count; i++) { // // Check Can Force Closed At ... bool has = IsSpecifiedValid(symbolTradeConfigs[i].closeAllOpenTradesAt); if (!has) { continue; } // // Parse Date ... datetime forceCloseTime = ParseDateTimeFromTimeString(symbolTradeConfigs[i].closeAllOpenTradesAt); has = IsTimeInRange( TimeCurrent(), forceCloseTime // ) && !symbolTradeConfigs[i].isForceCloseAtTime; if (!has) { continue; } // // Selecting Positions ... XTradeInfo iTrades[]; int iTradesCount = FillSymbolConfigurationTrades( symbolTradeConfigs[i], iTrades // ); has = IsValidSize(iTradesCount); if (!has) { // SpecifiedClean(iTrades); continue; } // // Converts Trades to Positions ... XPosition iPositions[]; int iPositionsCount = ToXPositions( iTrades, iPositions // ); has = IsValidSize(iPositionsCount); if (!has) { // SpecifiedClean(iTrades); SpecifiedClean(iPositions); continue; } // // Do Force Closing ... has = HandleForceCloseTrades(iPositions); if (has && !result) { result = true; } // // Cleanup Resources ... SpecifiedClean(iTrades); SpecifiedClean(iPositions); } // return result; } /** * Handle Position Partially Closed Event ... * * @param ticket: ULONG ... * @param profit: double ... * @param comment: string ... */ void HandlePartiallyClosed( const ulong ticket, const double profit, const string comment // ) { // // Handle Balance Reporting ... string prefix = "Partially Closed: " + ToXString(ticket); // // Handle Balance Reporting ... HandleReportBalance(prefix); } /** * Handle Guard Events ... * * @param action: ENUM_X_GUARD_ACTIONS * @param positions: XPosition[] */ void HandleGuardEvent( ENUM_X_GUARD_ACTIONS action, XPosition &positions[] // ) { } /** * Handle Signal Executed Event ... * * @param signal: XSignal, reference to Executed Signal ... */ void HandleSignalExecuted(XSignal &signal) { target.AddExecutedSignal(signal); } // // Protected ... protected: // // Tools ... // string GetTradeFilePath(XTradeInfo &trade) { // string fileName = trade.GetFileName(); // return GetTradeFilePath(fileName); } // string GetTradeFilePath(string fileName) { // string result = NULL; // result = collector .GetFilePath("Trades" + "\\" + fileName); // return result; } // string GetSignalFilePath(string fileName) { // string result = NULL; // result = collector .GetFilePath("Signals" + "\\" + fileName); // return result; } // string GetWinsFilePath(XTradeInfo &trade) { // string result = NULL; // result = collector .GetFilePath("Conditions" + "\\" + trade.signal.symbol + "\\" + ToXString(trade.signal.period) + "_wins"); // return result; } // string GetLostsFilePath(XTradeInfo &trade) { // string result = NULL; // result = collector .GetFilePath("Conditions" + "\\" + trade.signal.symbol + "\\" + ToXString(trade.signal.period) + "_losts"); // return result; } // string GetRestrictionsFilePath(string symbol) { // string result = NULL; // if (!IsValid(symbol)) { return result; } // result = collector .GetFilePath("Restrictions" + "\\" + symbol); // return result; } // void HandleReportBalance(string prefix = NULL) { // if (!reportAfterTradesBalance) { return; } // double balance = trader.mAccount.GetBalance(); string currency = trader.mAccount.GetCurrency(); // string message = (IsValid(prefix) ? prefix + " | " : "") + "Account Balance: " + ToXString(balance) + currency; alert.SendAlert(message); } // void HandleReportProtector(string message = NULL) { // if (!reportProtector) { return; } // alert.SendAlert(message); } /** * Handle All Exists Symbol Configurations Restrictions ... */ void HandleRestrictions() { // // Count Symbol Configurations ... int count = ArraySize(symbolTradeConfigs); bool has = IsValidSize(count); if (!has) { return; } // // Handle Restrictions ... datetime cTime = TimeCurrent(); bool isNewDay = timeTracker.IsNewDay(); for (int i = 0; i < count; i++) { // // Reset Force Close At Time ... if (isNewDay) { symbolTradeConfigs[i].isForceCloseAtTime = false; } // // Handle Restrictions ... symbolTradeConfigs[i].HandleRestrictions(cTime); } } /** * Apply Signal Volume ... * * @param signal: XSignal */ void HandleSignalVolume(XSignal &signal) { // // Validate ... if (!signal.IsValid()) { return; } // // Handle Volume Management ... double iVolume = volume.CalculateVolume(signal); bool has = iVolume > X_MIN_VOLUME && iVolume != signal.volume; if (has) { signal.volume = iVolume; } // // Here we Can Implement Custom Signalling Volume Management // based on Different Symbol Configurations ... } /** * Handle Force Close Trades ... */ bool HandleForceCloseTrades( XPosition &positions[] // ) { // bool result = false; // result = HasChild(positions); if (!result) { return result; } // string prefix = "Protector: "; string comment = "Force Close ..."; // int count = ArraySize(positions); for (int i = 0; i < count; i++) { HandleForceClose(positions[i]); } // result = IsValidSize(count); if (result) { // string message = prefix + "Force Close (" + ToXString(count) + ") Trades at Specified Time ..."; HandleReportProtector(message); } // return result; } /** * Check For Guards ... * * @param dest: XGuard[] */ int CheckForGuard(XGuard &dest[]) { // int result = 0; // // Cleanup Dest ... SpecifiedClean(dest); // // Check For Guards ... if (checkForGuardEventListener != NULL) { // XPosition positions[]; trader.GetPositions(positions); result = checkForGuardEventListener(dest, positions, 0); } // result = ArraySize(dest); // return result; } // // Save Trades ... bool SaveTrade( XTradeInfo &trade, bool includeSummary = true, bool includeSignal = true, bool includeConditions = true // ) { // bool result = false; // if (!mSaveTrades) { return result; } // string filePath = GetTradeFilePath(trade); result = IsValid(filePath); if (!result) { return result; } // string content = trade.ToString( includeSummary, includeSignal, includeConditions // ); // result = collector.Save( filePath, content // ); // 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 += ToXString("----------------") + "\n" + ToXString("Signal: ") + "\n" + ToXString("----------------") + "\n" + signal.ToString() + "\n"; content += ToXString("----------------") + "\n" + ToXString("Conditions: ") + "\n" + ToXString("----------------") + "\n" + signal.conditions + "\n"; // // Save Content to File ... result = collector.Save( filePath, content // ); // // Return Result ... return result; } // bool SaveWin(XTradeInfo &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(XTradeInfo &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; } // // Private ... private: // // Props ... // CArrayObj mObjects; // bool allowTrade; bool allowLongs; bool allowShorts; // bool mSaveWins; bool mSaveLosts; bool mSaveTrades; bool mSaveSignals; bool mSaveRestrictions; // bool reportTrades; bool reportSignals; bool reportProtector; bool reportRestrictions; bool reportAfterTradesBalance; // XTradeInfo trades[]; XSymbolTradeConfig symbolTradeConfigs[]; /** * Find Executed Trade by Providing Position Ticket ... * * @param index: int reference, holding founded item index ... * @param ticket: ulong, Specified Position Ticket ... * * @return ( bool ) */ bool HasTrade( int &index, ulong ticket // ) { // bool result = false; // index = -1; // result = ticket > 0 && HasChild(trades); if (!result) { return result; } // int count = ArraySize(trades); for (int i = 0; i < count; i++) { // XTradeInfo iTrade = trades[i]; // result = iTrade.HasSignal() && iTrade.IsExecuted() && iTrade.positionID == ticket; if (result) { // index = i; // iTrade.Clean(); break; } // iTrade.Clean(); } // result = IsValidIndex(index); // return result; } /** * Find Trade Item By Signal ... * * @param index: int reference, holding founded item index ... * * @return ( bool ) */ bool HasTrade( int &index, XSignal &signal // ) { // bool result = false; // index = -1; // result = signal.IsValid() && HasChild(trades); if (!result) { return result; } // int count = ArraySize(trades); for (int i = 0; i < count; i++) { // XTradeInfo iTrade = trades[i]; // result = iTrade.HasSignal() && iTrade.signal.IsSameAs(signal); if (result) { // index = i; // iTrade.Clean(); break; } // iTrade.Clean(); } // result = IsValidIndex(index); // return result; } /** * Remove a Trade From List ... * * @param index: int ... */ void RemoveTrade(int index) { // bool has = HasChild(trades) && IsValidIndex(index) && index < ArraySize(trades); if (!has) { return; } // ArrayRemove( trades, index, 1 // ); } // void AddOrUpdateSymbolConfiguration(XSymbolTradeConfig &config) { // // Check Validation ... bool has = config.IsValid(); if (!has) { return; } // // Check Index ... int idx = FindSymbolConfigurationIndex(config); has = IsValidIndex(idx); if (has) { // // Update Exists ... symbolTradeConfigs[idx] = config; } else { // // Add New ... AddRef( config, symbolTradeConfigs // ); } } // void AddDefaultSymbolConfiguration() { // // Define new Configuration ... XSymbolTradeConfig iConfig; // // Check Initialization ... bool has = iConfig.Init( "Default", _Symbol, _Period // ); // // Add Or Update ... if (has) { AddOrUpdateSymbolConfiguration(iConfig); } // // Clean Resources ... iConfig.Clean(); } // int FindSymbolConfigurationIndex(XSymbolTradeConfig &config) { // int result = -1; // if (!config.IsValid() || !SpecifiedHasChild(symbolTradeConfigs)) { return result; } // int count = ArraySize(symbolTradeConfigs); for (int i = 0; i < count; i++) { // if (symbolTradeConfigs[i].IsSame(config)) { // result = i; break; } } // return result; } // int FillSymbolConfigurationTrades( XSymbolTradeConfig &config, XTradeInfo &dest[] // ) { // int result = 0; // SpecifiedClean(dest); // // Check Trades ... int count = ArraySize(trades); if (!IsValidSize(count)) { return result; } // // Validate Config ... if (!config.IsValid()) { return result; } // // Find Config ... int idx = FindSymbolConfigurationIndex(config); if (!IsValidIndex(idx)) { return result; } // bool has = false; string symbol = symbolTradeConfigs[idx].symbol; ENUM_TIMEFRAMES period = symbolTradeConfigs[idx].period; for (int i = 0; i < count; i++) { // has = trades[i].signal.symbol == symbol && trades[i].signal.period == period && trades[i].positionID > 0; if (!has) { continue; } // AddRef( trades[i], dest // ); } // result = ArraySize(dest); // return result; } // int FindSymbolConfigurationIndex( string symbol, ENUM_TIMEFRAMES period // ) { // int result = -1; // // Validate Args ... if ( !IsSpecifiedValid(symbol) || !IsSpecifiedValid(period) || !HasChild(symbolTradeConfigs)) { return result; } // int count = ArraySize(symbolTradeConfigs); for (int i = 0; i < count; i++) { // if (symbolTradeConfigs[i].symbol == symbol && symbolTradeConfigs[i].period == period) { // result = i; break; } } // return result; } // // Tools ... // int ToXPositions( XTradeInfo &source[], XPosition &dest[] // ) { // int result = 0; // SpecifiedClean(dest); // int count = ArraySize(source); bool has = IsValidSize(count); if (!has) { return result; } // for (int i = 0; i < count; i++) { // XPosition iPosition; has = trader.GetPosition( source[i].positionID, iPosition); if (has) { // AddRef( iPosition, dest // ); } // iPosition.Clean(); } // result = ArraySize(dest); // return result; } // string EscapeString(string value) { // string result = value; // if (!IsSpecifiedValid(value)) { return result; } // StringReplace( result, "[", "" // ); // StringReplace( result, "]", "" // ); // StringReplace( result, "|", "" // ); // result = Trim(result); // return result; } };