mirror of
https://github.com/FxPouya/FxMathQuantWebApp.git
synced 2026-07-27 18:27:44 +00:00
153 lines
5.4 KiB
JavaScript
153 lines
5.4 KiB
JavaScript
|
|
/**
|
||
|
|
* MQ4 Code Generator - Generates MetaTrader 4 Expert Advisor code
|
||
|
|
*/
|
||
|
|
class MQ4Generator {
|
||
|
|
constructor(strategy, strategyName) {
|
||
|
|
this.strategy = strategy;
|
||
|
|
this.name = strategyName || this.generateName();
|
||
|
|
}
|
||
|
|
|
||
|
|
generateName() {
|
||
|
|
const pf = this.strategy.metrics.profitFactor.toFixed(2).replace('.', '_');
|
||
|
|
const wr = Math.round(this.strategy.metrics.winRate);
|
||
|
|
const timestamp = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
||
|
|
return `FxMath_PF${pf}_WR${wr}_${timestamp}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
generate() {
|
||
|
|
return `//+------------------------------------------------------------------+
|
||
|
|
//| ${this.name}.mq4 |
|
||
|
|
//| Generated by FxMathQuant Web |
|
||
|
|
//| https://fxmathquant.com |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "FxMathQuant"
|
||
|
|
#property link "https://fxmathquant.com"
|
||
|
|
#property version "1.00"
|
||
|
|
#property strict
|
||
|
|
|
||
|
|
//--- Input Parameters
|
||
|
|
input double LotSize = 0.01; // Lot size
|
||
|
|
input int MagicNumber = ${Math.floor(Math.random() * 9000) + 1000}; // Magic number
|
||
|
|
input int ATR_Period = ${this.strategy.atrPeriod}; // ATR period
|
||
|
|
input double SL_Multiplier = ${this.strategy.slMultiplier.toFixed(2)}; // Stop Loss multiplier
|
||
|
|
input double TP_Multiplier = ${this.strategy.tpMultiplier.toFixed(2)}; // Take Profit multiplier
|
||
|
|
input int Slippage = 3; // Slippage in points
|
||
|
|
|
||
|
|
//--- Global Variables
|
||
|
|
int ticket = 0;
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Expert initialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
int OnInit()
|
||
|
|
{
|
||
|
|
Print("${this.name} initialized");
|
||
|
|
Print("Strategy Performance: PF=${this.strategy.metrics.profitFactor.toFixed(2)}, WR=${this.strategy.metrics.winRate.toFixed(1)}%");
|
||
|
|
return(INIT_SUCCEEDED);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Expert deinitialization function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnDeinit(const int reason)
|
||
|
|
{
|
||
|
|
Print("${this.name} stopped");
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Expert tick function |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnTick()
|
||
|
|
{
|
||
|
|
// Check if we already have an open position
|
||
|
|
if(OrdersTotal() > 0)
|
||
|
|
{
|
||
|
|
for(int i = 0; i < OrdersTotal(); i++)
|
||
|
|
{
|
||
|
|
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
|
||
|
|
{
|
||
|
|
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
|
||
|
|
return; // Position already open
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Calculate ATR
|
||
|
|
double atr = iATR(Symbol(), Period(), ATR_Period, 0);
|
||
|
|
if(atr == 0) return;
|
||
|
|
|
||
|
|
// Check for BUY signal
|
||
|
|
if(CheckBuySignal())
|
||
|
|
{
|
||
|
|
double entry = Ask;
|
||
|
|
double sl = entry - (atr * SL_Multiplier);
|
||
|
|
double tp = entry + (atr * TP_Multiplier);
|
||
|
|
|
||
|
|
// Normalize prices
|
||
|
|
sl = NormalizeDouble(sl, Digits);
|
||
|
|
tp = NormalizeDouble(tp, Digits);
|
||
|
|
|
||
|
|
// Open BUY order
|
||
|
|
ticket = OrderSend(Symbol(), OP_BUY, LotSize, entry, Slippage, sl, tp,
|
||
|
|
"${this.name}", MagicNumber, 0, clrGreen);
|
||
|
|
|
||
|
|
if(ticket > 0)
|
||
|
|
Print("BUY order opened: ", ticket, " @ ", entry, " SL:", sl, " TP:", tp);
|
||
|
|
else
|
||
|
|
Print("Error opening BUY order: ", GetLastError());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Check BUY signal based on strategy rules |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CheckBuySignal()
|
||
|
|
{
|
||
|
|
${this.generateRulesCode()}
|
||
|
|
|
||
|
|
return true; // All rules passed
|
||
|
|
}
|
||
|
|
|
||
|
|
${this.generateHelperFunctions()}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
|
||
|
|
generateRulesCode() {
|
||
|
|
return this.strategy.rules.map((rule, index) => {
|
||
|
|
const condition = this.ruleToMQ4(rule);
|
||
|
|
return ` // Rule ${index + 1}
|
||
|
|
if(!(${condition})) return false;`;
|
||
|
|
}).join('\n');
|
||
|
|
}
|
||
|
|
|
||
|
|
ruleToMQ4(rule) {
|
||
|
|
if (rule.type === 'simple') {
|
||
|
|
const left = this.priceToMQ4(rule.left.price, rule.left.shift);
|
||
|
|
const right = this.priceToMQ4(rule.right.price, rule.right.shift);
|
||
|
|
return `${left} ${rule.operator} ${right}`;
|
||
|
|
} else {
|
||
|
|
// Arithmetic rule
|
||
|
|
const left1 = this.priceToMQ4(rule.left.price1, rule.left.shift1);
|
||
|
|
const left2 = this.priceToMQ4(rule.left.price2, rule.left.shift2);
|
||
|
|
const right = this.priceToMQ4(rule.right.price, rule.right.shift);
|
||
|
|
|
||
|
|
return `(${left1} ${rule.left.op} ${left2}) ${rule.operator} (${right} * ${rule.right.multiplier})`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
priceToMQ4(priceType, shift) {
|
||
|
|
const type = priceType.charAt(0).toUpperCase() + priceType.slice(1);
|
||
|
|
return `i${type}(Symbol(), Period(), ${shift})`;
|
||
|
|
}
|
||
|
|
|
||
|
|
generateHelperFunctions() {
|
||
|
|
return `//+------------------------------------------------------------------+
|
||
|
|
//| Helper Functions |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
// Add any additional helper functions here
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
}
|