Files
FxMathQuantWebApp/js/strategy.js
T
2025-12-24 13:07:51 +03:30

153 lines
5.4 KiB
JavaScript

/**
* Strategy Class - Represents a trading strategy with rules and parameters
*/
class Strategy {
constructor() {
this.rules = [];
this.atrPeriod = 20;
this.slMultiplier = 2.0;
this.tpMultiplier = 3.0;
this.closeAtOpposite = false; // Disable to allow independent BUY/SELL signals
this.fitness = 0;
this.metrics = {};
this.id = this.generateId();
}
generateId() {
return 'strategy_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
}
/**
* Generate random trading rules
*/
generateRandomRules(count, shiftRange) {
const minRules = count[0] || 3;
const maxRules = count[1] || 8;
const numRules = Math.floor(Math.random() * (maxRules - minRules + 1)) + minRules;
for (let i = 0; i < numRules; i++) {
this.rules.push(this.generateRule(shiftRange));
}
}
/**
* Generate a single random rule
*/
generateRule(shiftRange) {
const priceTypes = ['open', 'high', 'low', 'close'];
const operators = ['>', '<', '>=', '<='];
const minShift = shiftRange[0] || 1;
const maxShift = shiftRange[1] || 10;
// 70% simple rules, 30% arithmetic rules
if (Math.random() < 0.7) {
// Simple rule: CLOSE[1] > OPEN[2]
return {
type: 'simple',
left: {
price: priceTypes[Math.floor(Math.random() * 4)],
shift: Math.floor(Math.random() * (maxShift - minShift + 1)) + minShift
},
operator: operators[Math.floor(Math.random() * 4)],
right: {
price: priceTypes[Math.floor(Math.random() * 4)],
shift: Math.floor(Math.random() * (maxShift - minShift + 1)) + minShift
}
};
} else {
// Arithmetic rule: (HIGH[1] + LOW[1]) > (CLOSE[2] * 1.01)
const arithmeticOps = ['+', '-', '*'];
const multipliers = [0.99, 1.01, 1.02, 0.98];
return {
type: 'arithmetic',
left: {
price1: priceTypes[Math.floor(Math.random() * 4)],
shift1: Math.floor(Math.random() * (maxShift - minShift + 1)) + minShift,
op: arithmeticOps[Math.floor(Math.random() * 3)],
price2: priceTypes[Math.floor(Math.random() * 4)],
shift2: Math.floor(Math.random() * (maxShift - minShift + 1)) + minShift
},
operator: operators[Math.floor(Math.random() * 4)],
right: {
price: priceTypes[Math.floor(Math.random() * 4)],
shift: Math.floor(Math.random() * (maxShift - minShift + 1)) + minShift,
multiplier: multipliers[Math.floor(Math.random() * 4)]
}
};
}
}
/**
* Randomize ATR and SL/TP parameters
*/
randomizeParameters() {
this.atrPeriod = Math.floor(Math.random() * 31) + 10; // 10-40
this.slMultiplier = (Math.random() * 3) + 1; // 1.0-4.0
this.tpMultiplier = this.slMultiplier + (Math.random() * 5) + 0.5; // SL + 0.5 to 5.5
}
/**
* Create a deep copy of the strategy
*/
copy() {
const newStrategy = new Strategy();
newStrategy.rules = JSON.parse(JSON.stringify(this.rules));
newStrategy.atrPeriod = this.atrPeriod;
newStrategy.slMultiplier = this.slMultiplier;
newStrategy.tpMultiplier = this.tpMultiplier;
newStrategy.closeAtOpposite = this.closeAtOpposite;
newStrategy.metrics = this.metrics ? JSON.parse(JSON.stringify(this.metrics)) : {};
newStrategy.fitness = this.fitness || 0;
return newStrategy;
}
/**
* Convert rules to human-readable format
*/
getRulesText() {
return this.rules.map((rule, index) => {
if (rule.type === 'simple') {
return `${index + 1}. ${rule.left.price.toUpperCase()}[${rule.left.shift}] ${rule.operator} ${rule.right.price.toUpperCase()}[${rule.right.shift}]`;
} else {
return `${index + 1}. (${rule.left.price1.toUpperCase()}[${rule.left.shift1}] ${rule.left.op} ${rule.left.price2.toUpperCase()}[${rule.left.shift2}]) ${rule.operator} (${rule.right.price.toUpperCase()}[${rule.right.shift}] * ${rule.right.multiplier})`;
}
}).join('\n');
}
/**
* Export to JSON
*/
toJSON() {
return {
id: this.id,
rules: this.rules,
parameters: {
atr_period: this.atrPeriod,
sl_multiplier: this.slMultiplier,
tp_multiplier: this.tpMultiplier,
close_at_opposite: this.closeAtOpposite
},
performance: this.metrics,
fitness: this.fitness
};
}
/**
* Import from JSON
*/
static fromJSON(json) {
const strategy = new Strategy();
strategy.id = json.id;
strategy.rules = json.rules;
strategy.atrPeriod = json.parameters.atr_period;
strategy.slMultiplier = json.parameters.sl_multiplier;
strategy.tpMultiplier = json.parameters.tp_multiplier;
strategy.closeAtOpposite = json.parameters.close_at_opposite || false;
strategy.metrics = json.performance || {};
strategy.fitness = json.fitness || 0;
return strategy;
}
}