last works on xom1 ea ...
This commit is contained in:
@@ -24,6 +24,8 @@
|
||||
// Imports ...
|
||||
#include "../../Classes/x-saherelm.base.class.mq5"
|
||||
#include "../../Classes/x-saherelm.x-alert.class.mq5"
|
||||
#include "../../Classes/x-saherelm.x-guard.class.mq5"
|
||||
#include "../../Classes/x-saherelm.x-trade-manager.class.mq5"
|
||||
#include "../../Classes/x-saherelm.x-volume.class.mq5"
|
||||
#include "../Classes/xom1ea.signaller.class.mq5"
|
||||
|
||||
@@ -46,6 +48,22 @@ class XCXOM1EAExpert : public XCBase
|
||||
int eaSlippage; // Slippgae
|
||||
string eaLogSuffix; // Log Suffix
|
||||
|
||||
//
|
||||
// Management ...
|
||||
bool eaAllowGuards; // Allow Guards
|
||||
bool eaAllowTrade; // Allow Trade on Signals
|
||||
bool eaAllowLongs; // Allow Long Trades
|
||||
bool eaAllowShorts; // Allow Short Trades
|
||||
string eaSessions; // Active Sessions
|
||||
ENUM_XTRADE_RESTRICTION_PERIOD eaRestrictionsPeriod; // Restrictions Period
|
||||
int eaMaxAllowedTPs; // Max Allowed TP(s) in Restrictions Period
|
||||
int eaMaxAllowedSLs; // Max Allowed SL(s) in Restrictions Period
|
||||
int eaMaxAllowedTrades; // Max Allowed Trades in Restrictions Period
|
||||
int eaMaxAllowedPositions; // Max Allowed Same Time Trades
|
||||
double eaMaxAllowedSpread; // Max Allowed Spread For Trade
|
||||
double eaMaxAllowedDrawdownFactor; // Max Allowed DrawDown for Trade
|
||||
string eaCloseAllOpenTradesAt; // Close All Open Trades per Day At Specified Time
|
||||
|
||||
//
|
||||
// Volume ...
|
||||
ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect; // Volume Applying Type
|
||||
@@ -65,12 +83,195 @@ class XCXOM1EAExpert : public XCBase
|
||||
bool eaPushAlerts; // Push Alerts
|
||||
bool eaTerminalAlerts; // Terminal Alerts
|
||||
|
||||
//
|
||||
// Reports ...
|
||||
bool eaReportNewMonths; // Report New Month
|
||||
bool eaReportNewWeeks; // Report New Weeks
|
||||
bool eaReportNewDays; // Report New Days
|
||||
bool eaReportNewHours; // Report New Hours
|
||||
bool eaReportTrades; // Report Trades
|
||||
bool eaReportSignals; // Report Signals
|
||||
bool eaReportProtector; // Report Protector Actions
|
||||
bool eaReportRestrictions; // Report Restrictions
|
||||
bool eaReportAfterTradesBalance; // Report Balance after a Trade Finished
|
||||
|
||||
//
|
||||
// Collector ...
|
||||
bool eaSaveTrades; // Save Trades
|
||||
bool eaSaveSignals; // Save Signals
|
||||
bool eaSaveWins; // Save Winning Conditions
|
||||
bool eaSaveLosts; // Save Lost Conditions
|
||||
bool eaSaveRestrictions; // Save Restriction Reports
|
||||
|
||||
//
|
||||
// Requirements ...
|
||||
|
||||
//
|
||||
XCAlert *eaAlert; // EA Scope Alert Handler ...
|
||||
XCVolume *eaVolume; // EA Scope Voluem Handler ...
|
||||
XCAlert *eaAlert; // EA Scope Alert Handler ...
|
||||
XCVolume *eaVolume; // EA Scope Voluem Handler ...
|
||||
XCGuard *eaGuard; // EA Scope Guard Handler ...
|
||||
XCTrade *eaTrade; // EA Scope Trade Handler ...
|
||||
XCTradeManager *eaTradeManager; // EA Scope Trade Handler ...
|
||||
XTimeTracker eaTimeTracker; // EA Scope Time Tracker ...
|
||||
|
||||
//
|
||||
// Tools / Actions / Handlers ...
|
||||
|
||||
//
|
||||
// Trade Event Handlers ...
|
||||
|
||||
//
|
||||
void AddOnStopLossEventHandler(TOnStopLoss handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mStopLossEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnTakeProfitEventHandler(TOnTakeProfit handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mTakeProfitEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnDealsChangedEventHandler(TOnDealsChanged handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mDealsChangedEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mOrdersChangedEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnModifyPositionEventHandler(TOnModify handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mOnModifyEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mPositionsChangedEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mTradeStateChangedEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnForceClosePositionEventHandler(TOnForceClose handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mOnForceCloseEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
void AddOnPartialClosePositionEventHandler(TOnPartialClose handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(
|
||||
handler,
|
||||
mOnPartialCloseEventHandlers
|
||||
//
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Validators ...
|
||||
@@ -114,6 +315,10 @@ class XCXOM1EAExpert : public XCBase
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
int count = 0;
|
||||
bool has = false;
|
||||
|
||||
//
|
||||
// Initialize Alert Handler ...
|
||||
eaAlert = new XCAlert();
|
||||
@@ -127,20 +332,209 @@ class XCXOM1EAExpert : public XCBase
|
||||
|
||||
//
|
||||
// Initialize Volume Manager ...
|
||||
// eaVolume = new XCVolume();
|
||||
// result = eaVolume.Init(
|
||||
// eaVolumeSelect,
|
||||
// eaStaticVoluem,
|
||||
// eaDynamicVolumeStepBalance,
|
||||
// eaDynamicVolumeStepVolume,
|
||||
// eaConstantRiskBalance,
|
||||
// eaConstantPercent,
|
||||
// eaConstantBalance //
|
||||
// );
|
||||
// if (!result)
|
||||
// {
|
||||
// return result;
|
||||
// }
|
||||
eaVolume = new XCVolume();
|
||||
result = eaVolume.Init(
|
||||
eaVolumeSelect,
|
||||
eaStaticVoluem,
|
||||
eaDynamicVolumeStepBalance,
|
||||
eaDynamicVolumeStepVolume,
|
||||
eaConstantRiskBalance,
|
||||
eaConstantPercent,
|
||||
eaConstantBalance //
|
||||
);
|
||||
if (!result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Trader ...
|
||||
eaTrade = new XCTrade(
|
||||
eaSlippage,
|
||||
eaMagicNumber,
|
||||
eaMaxAllowedSpread,
|
||||
eaMaxAllowedPositions,
|
||||
eaMaxAllowedDrawdownFactor //
|
||||
);
|
||||
|
||||
//
|
||||
// Trade Handler Attachments ...
|
||||
|
||||
//
|
||||
// Position Modifiy Event Handlers ...
|
||||
count = ArraySize(mOnModifyEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnModifyPositionEventHandler(mOnModifyEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Position Stop Loss Event Handlers ...
|
||||
count = ArraySize(mStopLossEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnStopLossEventHandler(mStopLossEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Position Take Profit Event Handlers ...
|
||||
count = ArraySize(mTakeProfitEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnTakeProfitEventHandler(mTakeProfitEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Position Force Close Event Handlers ...
|
||||
count = ArraySize(mOnForceCloseEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnForceClosePositionEventHandler(mOnForceCloseEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Deals Changed Event Handlers ...
|
||||
count = ArraySize(mDealsChangedEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnDealsChangedEventHandler(mDealsChangedEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Orders Changed Event Handlers ...
|
||||
count = ArraySize(mOrdersChangedEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnOrdersChangedEventHandler(mOrdersChangedEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Positions Changed Event Handlers ...
|
||||
count = ArraySize(mPositionsChangedEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnPositionsChangedEventHandler(mPositionsChangedEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Trade Changed Event Handlers ...
|
||||
count = ArraySize(mTradeStateChangedEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnTradeStateChangedEventHandler(mTradeStateChangedEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Postion Partially Close Event Handlers ...
|
||||
count = ArraySize(mOnPartialCloseEventHandlers);
|
||||
has = IsValidSize(count);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
eaTrade.AddOnPartialClosePositionEventHandler(mOnPartialCloseEventHandlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Guard Handler ...
|
||||
eaGuard = new XCGuard(
|
||||
eaAlert,
|
||||
eaTrade //
|
||||
);
|
||||
|
||||
//
|
||||
// Initialize Trae Manager ...
|
||||
eaTradeManager = new XCTradeManager(
|
||||
eaAlert,
|
||||
eaTrade,
|
||||
eaGuard //
|
||||
);
|
||||
|
||||
//
|
||||
// Configuring Trade Manager ...
|
||||
|
||||
//
|
||||
eaTradeManager.SaveWins(eaSaveWins);
|
||||
eaTradeManager.SaveLosts(eaSaveLosts);
|
||||
eaTradeManager.SaveTrades(eaSaveTrades);
|
||||
eaTradeManager.SaveSignals(eaSaveSignals);
|
||||
eaTradeManager.SaveRestrictions(eaSaveRestrictions);
|
||||
|
||||
//
|
||||
// Enable Force Close At ...
|
||||
eaTradeManager.SetForceCloseTradesAt(eaCloseAllOpenTradesAt);
|
||||
|
||||
//
|
||||
// Setting Trade Reports ...
|
||||
eaTradeManager
|
||||
.SetTradeReports(
|
||||
eaReportTrades,
|
||||
eaReportSignals,
|
||||
eaReportProtector,
|
||||
eaReportRestrictions,
|
||||
eaReportAfterTradesBalance //
|
||||
);
|
||||
|
||||
//
|
||||
// Setting Trade Permissions ...
|
||||
eaTradeManager
|
||||
.SetTradePermissions(
|
||||
eaAllowTrade,
|
||||
eaAllowLongs,
|
||||
eaAllowShorts //
|
||||
);
|
||||
|
||||
//
|
||||
// Setting Trade Restrictions ...
|
||||
eaTradeManager
|
||||
.SetTradeRestrictions(
|
||||
eaRestrictionsPeriod,
|
||||
eaMaxAllowedTPs,
|
||||
eaMaxAllowedSLs,
|
||||
eaMaxAllowedTrades //
|
||||
);
|
||||
|
||||
//
|
||||
// Here we Apply Symbols,Periods and Configs ...
|
||||
@@ -171,7 +565,7 @@ class XCXOM1EAExpert : public XCBase
|
||||
// Register Signaller ...
|
||||
Add(
|
||||
iDZoneSignaller,
|
||||
signallers //
|
||||
eaSignallers //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -192,10 +586,28 @@ class XCXOM1EAExpert : public XCBase
|
||||
{
|
||||
//
|
||||
|
||||
//
|
||||
delete eaTrade;
|
||||
ZeroMemory(eaTrade);
|
||||
|
||||
//
|
||||
delete eaGuard;
|
||||
ZeroMemory(eaGuard);
|
||||
|
||||
//
|
||||
delete eaVolume;
|
||||
ZeroMemory(eaVolume);
|
||||
|
||||
//
|
||||
delete eaTradeManager;
|
||||
ZeroMemory(eaTradeManager);
|
||||
|
||||
//
|
||||
eaTimeTracker.Clean();
|
||||
|
||||
//
|
||||
Clean(eaSignallers);
|
||||
|
||||
//
|
||||
string message = "DeInitialized Successfully ...";
|
||||
eaAlert.SendAlert(message);
|
||||
@@ -211,7 +623,7 @@ class XCXOM1EAExpert : public XCBase
|
||||
void HandleOnTick()
|
||||
{
|
||||
//
|
||||
int count = ArraySize(signallers);
|
||||
int count = ArraySize(eaSignallers);
|
||||
bool has = IsValidSize(count);
|
||||
if (!has)
|
||||
{
|
||||
@@ -224,7 +636,7 @@ class XCXOM1EAExpert : public XCBase
|
||||
{
|
||||
//
|
||||
// Calling Process Ticks on Signaller ...
|
||||
signallers[i].ProcessTick(0);
|
||||
eaSignallers[i].ProcessTick(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,9 +674,185 @@ class XCXOM1EAExpert : public XCBase
|
||||
//
|
||||
// Trade Event Handlers ...
|
||||
|
||||
/**
|
||||
* Handle Stop Loss Event Triggered ...
|
||||
*
|
||||
* @param deal: XDeal instance refrence, provides Triggered Deal info ...
|
||||
*/
|
||||
void HandleOnStopLossTriggered(const XDeal &deal)
|
||||
{
|
||||
eaTradeManager.HandleSL(deal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Take Profit Event Triggered ...
|
||||
*
|
||||
* @param deal: XDeal instance refrence, provides Triggered Deal info ...
|
||||
*/
|
||||
void HandleOnTakeProfitTriggered(const XDeal &deal)
|
||||
{
|
||||
eaTradeManager.HandleTP(deal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Position Force Closed Event ...
|
||||
*
|
||||
* @param ticket: ulong, triggered Positions ticket ...
|
||||
* @param position: XPosition instance refrence, Triggered Position ...
|
||||
* @param comment: string, Comment ...
|
||||
*/
|
||||
void HandleOnPositionForceClosed(
|
||||
const ulong ticket,
|
||||
const XPosition &position,
|
||||
const string comment //
|
||||
)
|
||||
{
|
||||
eaTradeManager.HandleForceClose(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Position Partially Closed Event ...
|
||||
*
|
||||
* @param ticket: ulong, triggered Positions ticket ...
|
||||
* @param profit: double, Position Profit ...
|
||||
* @param comment: string, Comment ...
|
||||
*/
|
||||
void HandleOnPositionPartialClosed(
|
||||
const ulong ticket,
|
||||
const double profit,
|
||||
const string comment //
|
||||
)
|
||||
{
|
||||
//
|
||||
eaTradeManager.HandlePartiallyClosed(
|
||||
ticket,
|
||||
profit,
|
||||
comment //
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Deals Changed ...
|
||||
*
|
||||
* @param count: int, number of changes ...
|
||||
* if the count is positive, means new added ...
|
||||
* if the count is negative, means removed ...
|
||||
*/
|
||||
void HandleOnDealsChanged(int count)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Orders Changed ...
|
||||
*
|
||||
* @param count: int, number of changes ...
|
||||
* if the count is positive, means new added ...
|
||||
* if the count is negative, means removed ...
|
||||
*/
|
||||
void HandleOnOrdersChanged(int count)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Positions Changed ...
|
||||
*
|
||||
* @param count: int, number of changes ...
|
||||
* if the count is positive, means new added ...
|
||||
* if the count is negative, means removed ...
|
||||
*/
|
||||
void HandleOnPositionsChanged(int count)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Position Modified Event ...
|
||||
*
|
||||
* @param ticket: ulong, triggered Positions ticket ...
|
||||
* @param profit: double, Position Profit ...
|
||||
* @param comment: string, Comment ...
|
||||
*/
|
||||
void HandleOnPositionModified(
|
||||
const ulong ticket,
|
||||
const double profit,
|
||||
const string comment //
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle all Trades States Changed Event ...
|
||||
*
|
||||
* @param state: XOnTradeHandlerState instance refrence, Changed Trade State data ...
|
||||
*/
|
||||
void HandleOnTradeStateChanged(const XOnTradeHandlerState &state)
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// Protected ...
|
||||
protected:
|
||||
//
|
||||
|
||||
/**
|
||||
* Report Time Changes based on Given Configurations ...
|
||||
*/
|
||||
void HandleTimeReport()
|
||||
{
|
||||
//
|
||||
if (eaAlert == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Monthly Report ....
|
||||
if (eaReportNewMonths &&
|
||||
eaTimeTracker.IsNewMonth())
|
||||
{
|
||||
//
|
||||
string msg = "New Month ...";
|
||||
|
||||
//
|
||||
eaAlert.SendAlert(msg);
|
||||
}
|
||||
|
||||
//
|
||||
// Weekly Report ....
|
||||
if (eaReportNewWeeks &&
|
||||
eaTimeTracker.IsNewWeek())
|
||||
{
|
||||
//
|
||||
string msg = "New Week ...";
|
||||
|
||||
//
|
||||
eaAlert.SendAlert(msg);
|
||||
}
|
||||
|
||||
//
|
||||
// Daily Report ....
|
||||
if (eaReportNewDays &&
|
||||
eaTimeTracker.IsNewDay())
|
||||
{
|
||||
//
|
||||
string msg = "New Day ...";
|
||||
|
||||
//
|
||||
eaAlert.SendAlert(msg);
|
||||
}
|
||||
|
||||
//
|
||||
// Hourly Report ....
|
||||
if (eaReportNewHours &&
|
||||
eaTimeTracker.IsNewHour())
|
||||
{
|
||||
//
|
||||
string msg = "New Hour ...";
|
||||
|
||||
//
|
||||
eaAlert.SendAlert(msg);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Private ...
|
||||
private:
|
||||
@@ -272,7 +860,18 @@ class XCXOM1EAExpert : public XCBase
|
||||
// Props ...
|
||||
|
||||
//
|
||||
XCXOM1SignallerBase *signallers[]; // All Registered Signallers ...
|
||||
TOnModify mOnModifyEventHandlers[];
|
||||
TOnStopLoss mStopLossEventHandlers[];
|
||||
TOnTakeProfit mTakeProfitEventHandlers[];
|
||||
TOnForceClose mOnForceCloseEventHandlers[];
|
||||
TOnDealsChanged mDealsChangedEventHandlers[];
|
||||
TOnOrdersChanged mOrdersChangedEventHandlers[];
|
||||
TOnPartialClose mOnPartialCloseEventHandlers[];
|
||||
TOnPositionsChanged mPositionsChangedEventHandlers[];
|
||||
TOnTradeStateChanged mTradeStateChangedEventHandlers[];
|
||||
|
||||
//
|
||||
XCXOM1SignallerBase *eaSignallers[]; // All Registered Signallers ...
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user