mirror of
https://github.com/FxPouya/FxMathQuantWebApp.git
synced 2026-08-01 12:37:44 +00:00
Add files via upload
This commit is contained in:
+8
-1
@@ -117,13 +117,19 @@
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 20px;">
|
||||
<label>Data Size Limit (bars)</label>
|
||||
<select id="data-size-limit" class="form-select">
|
||||
<select id="data-size-limit" class="form-select" onchange="toggleCustomBarsInput()">
|
||||
<option value="0">Use All Data</option>
|
||||
<option value="500">Last 500 bars</option>
|
||||
<option value="1000">Last 1,000 bars</option>
|
||||
<option value="2000">Last 2,000 bars</option>
|
||||
<option value="3000">Last 3,000 bars</option>
|
||||
<option value="5000" selected>Last 5,000 bars (Recommended)</option>
|
||||
<option value="10000">Last 10,000 bars</option>
|
||||
<option value="custom">Custom...</option>
|
||||
</select>
|
||||
<input type="number" id="custom-bars-input" class="form-select"
|
||||
placeholder="Enter custom number of bars" min="100" step="100"
|
||||
style="margin-top: 10px; display: none;">
|
||||
<small>Limit data size for faster processing. Recommended: 5,000 bars</small>
|
||||
</div>
|
||||
<button class="btn-success" id="continue-btn">Continue to Configuration →</button>
|
||||
@@ -290,6 +296,7 @@
|
||||
</footer>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/strategy.js"></script>
|
||||
<script src="js/backtester.js"></script>
|
||||
<script src="js/ga-engine.js"></script>
|
||||
|
||||
+14
-8
@@ -2,9 +2,15 @@
|
||||
* Backtester - Fast backtesting engine using typed arrays
|
||||
*/
|
||||
class Backtester {
|
||||
constructor(data, strategy) {
|
||||
constructor(data, strategy, symbol = '') {
|
||||
this.strategy = strategy;
|
||||
this.dataLength = data.length;
|
||||
this.symbol = symbol;
|
||||
|
||||
// Get profit multiplier based on symbol type
|
||||
this.profitMultiplier = typeof getProfitMultiplier === 'function'
|
||||
? getProfitMultiplier(symbol)
|
||||
: 10000; // Default to standard forex
|
||||
|
||||
// Use typed arrays for performance
|
||||
this.open = new Float64Array(data.length);
|
||||
@@ -43,7 +49,7 @@ class Backtester {
|
||||
if (position.type === 'BUY' && this.checkSellSignal(i)) {
|
||||
// Close BUY and open SELL
|
||||
const closePrice = this.close[i];
|
||||
const profit = closePrice - position.entry;
|
||||
const profit = (closePrice - position.entry) * this.profitMultiplier;
|
||||
balance += profit;
|
||||
trades.push({
|
||||
type: 'BUY',
|
||||
@@ -60,7 +66,7 @@ class Backtester {
|
||||
} else if (position.type === 'SELL' && this.checkBuySignal(i)) {
|
||||
// Close SELL and open BUY
|
||||
const closePrice = this.close[i];
|
||||
const profit = position.entry - closePrice;
|
||||
const profit = (position.entry - closePrice) * this.profitMultiplier;
|
||||
balance += profit;
|
||||
trades.push({
|
||||
type: 'SELL',
|
||||
@@ -101,7 +107,7 @@ class Backtester {
|
||||
// Close any open position at the end
|
||||
if (position) {
|
||||
const exitPrice = this.close[this.dataLength - 1];
|
||||
const profit = exitPrice - position.entry;
|
||||
const profit = (exitPrice - position.entry) * this.profitMultiplier;
|
||||
balance += profit;
|
||||
trades.push({
|
||||
type: 'BUY',
|
||||
@@ -266,7 +272,7 @@ class Backtester {
|
||||
type: position.type,
|
||||
entry: position.entry,
|
||||
exit: position.tp,
|
||||
profit: position.tp - position.entry,
|
||||
profit: (position.tp - position.entry) * this.profitMultiplier,
|
||||
reason: 'take_profit',
|
||||
openTime: position.openTime,
|
||||
closeTime: this.time[index]
|
||||
@@ -278,7 +284,7 @@ class Backtester {
|
||||
type: position.type,
|
||||
entry: position.entry,
|
||||
exit: position.sl,
|
||||
profit: position.sl - position.entry,
|
||||
profit: (position.sl - position.entry) * this.profitMultiplier,
|
||||
reason: 'stop_loss',
|
||||
openTime: position.openTime,
|
||||
closeTime: this.time[index]
|
||||
@@ -291,7 +297,7 @@ class Backtester {
|
||||
type: position.type,
|
||||
entry: position.entry,
|
||||
exit: position.tp,
|
||||
profit: position.entry - position.tp,
|
||||
profit: (position.entry - position.tp) * this.profitMultiplier,
|
||||
reason: 'take_profit',
|
||||
openTime: position.openTime,
|
||||
closeTime: this.time[index]
|
||||
@@ -303,7 +309,7 @@ class Backtester {
|
||||
type: position.type,
|
||||
entry: position.entry,
|
||||
exit: position.sl,
|
||||
profit: position.entry - position.sl,
|
||||
profit: (position.entry - position.sl) * this.profitMultiplier,
|
||||
reason: 'stop_loss',
|
||||
openTime: position.openTime,
|
||||
closeTime: this.time[index]
|
||||
|
||||
+3
-2
@@ -2,8 +2,9 @@
|
||||
* Genetic Algorithm Engine - Evolves trading strategies
|
||||
*/
|
||||
class GeneticOptimizer {
|
||||
constructor(data, config) {
|
||||
constructor(data, config, symbol = '') {
|
||||
this.data = data;
|
||||
this.symbol = symbol;
|
||||
this.config = {
|
||||
populationSize: config.populationSize || 100,
|
||||
generations: config.generations || 50,
|
||||
@@ -40,7 +41,7 @@ class GeneticOptimizer {
|
||||
*/
|
||||
evaluatePopulation() {
|
||||
for (const strategy of this.population) {
|
||||
const backtester = new Backtester(this.data, strategy);
|
||||
const backtester = new Backtester(this.data, strategy, this.symbol);
|
||||
strategy.metrics = backtester.run();
|
||||
strategy.fitness = this.calculateFitness(strategy.metrics);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
* Generates comprehensive HTML reports with full trading statement
|
||||
*/
|
||||
|
||||
function generateHTMLReport(strategy, index) {
|
||||
function generateHTMLReport(strategy, index, symbol = '') {
|
||||
const m = strategy.metrics;
|
||||
const name = `FxMath_${String(index + 1).padStart(3, '0')}_PF${(m.profitFactor || 0).toFixed(2).replace('.', '_')}_WR${Math.round(m.winRate || 0)}`;
|
||||
|
||||
// Note: Profits are already multiplied in the backtester, so we can display them directly
|
||||
|
||||
// Generate SELL rules (inverted operators)
|
||||
const sellRulesHTML = strategy.rules.map((rule, i) => {
|
||||
const invertedOp = rule.operator === '>' ? '<=' :
|
||||
@@ -44,8 +46,8 @@ function generateHTMLReport(strategy, index) {
|
||||
<td><span class="badge ${typeClass}">${trade.type}</span></td>
|
||||
<td>${new Date(trade.openTime).toLocaleString()}</td>
|
||||
<td>${new Date(trade.closeTime).toLocaleString()}</td>
|
||||
<td>$${trade.entry.toFixed(2)}</td>
|
||||
<td>$${trade.exit.toFixed(2)}</td>
|
||||
<td>$${trade.entry.toFixed(5)}</td>
|
||||
<td>$${trade.exit.toFixed(5)}</td>
|
||||
<td class="${profitClass}">$${trade.profit.toFixed(2)}</td>
|
||||
<td>${trade.reason.toUpperCase()}</td>
|
||||
</tr>
|
||||
|
||||
+38
-4
@@ -6,6 +6,7 @@
|
||||
let appData = {
|
||||
csvData: null,
|
||||
dataName: '',
|
||||
symbol: '',
|
||||
optimizer: null,
|
||||
foundStrategies: [],
|
||||
selectedStrategies: new Set(),
|
||||
@@ -139,7 +140,14 @@ function handleFileUpload(file) {
|
||||
}));
|
||||
|
||||
appData.dataName = file.name;
|
||||
|
||||
// Extract symbol from filename
|
||||
appData.symbol = typeof extractSymbolFromFilename === 'function'
|
||||
? extractSymbolFromFilename(file.name)
|
||||
: '';
|
||||
|
||||
console.log('✅ Data loaded successfully:', appData.csvData.length, 'bars');
|
||||
console.log('📊 Detected symbol:', appData.symbol || 'Unknown');
|
||||
|
||||
// Apply data size limit
|
||||
applyDataSizeLimit();
|
||||
@@ -189,13 +197,37 @@ function displayDataPreview() {
|
||||
* Apply data size limit
|
||||
*/
|
||||
function applyDataSizeLimit() {
|
||||
const limit = parseInt(document.getElementById('data-size-limit').value);
|
||||
const limitSelect = document.getElementById('data-size-limit');
|
||||
const customInput = document.getElementById('custom-bars-input');
|
||||
|
||||
let limit;
|
||||
if (limitSelect.value === 'custom') {
|
||||
limit = parseInt(customInput.value) || 0;
|
||||
} else {
|
||||
limit = parseInt(limitSelect.value);
|
||||
}
|
||||
|
||||
if (limit > 0 && appData.csvData.length > limit) {
|
||||
console.log(`✂️ Limiting data from ${appData.csvData.length} to ${limit} bars`);
|
||||
appData.csvData = appData.csvData.slice(-limit); // Take last N bars
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle custom bars input visibility
|
||||
*/
|
||||
function toggleCustomBarsInput() {
|
||||
const limitSelect = document.getElementById('data-size-limit');
|
||||
const customInput = document.getElementById('custom-bars-input');
|
||||
|
||||
if (limitSelect.value === 'custom') {
|
||||
customInput.style.display = 'block';
|
||||
customInput.focus();
|
||||
} else {
|
||||
customInput.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect timeframe from data
|
||||
*/
|
||||
@@ -269,7 +301,8 @@ async function startGeneration() {
|
||||
|
||||
// Create optimizer
|
||||
console.log('🧬 Creating GA optimizer with config:', config);
|
||||
appData.optimizer = new GeneticOptimizer(appData.csvData, config);
|
||||
console.log('📊 Using symbol:', appData.symbol || 'Unknown');
|
||||
appData.optimizer = new GeneticOptimizer(appData.csvData, config, appData.symbol);
|
||||
|
||||
// Start time
|
||||
const startTime = Date.now();
|
||||
@@ -520,8 +553,8 @@ function downloadStrategy(index, type) {
|
||||
content = converter.generate();
|
||||
filename = name + '.pine';
|
||||
} else if (type === 'report') {
|
||||
// Use new HTML report generator
|
||||
content = generateHTMLReport(strategy, index);
|
||||
// Use new HTML report generator with symbol
|
||||
content = generateHTMLReport(strategy, index, appData.symbol);
|
||||
filename = name + '_report.html';
|
||||
} else if (type === 'json') {
|
||||
content = JSON.stringify(strategy.toJSON(), null, 2);
|
||||
@@ -723,3 +756,4 @@ window.downloadAllStrategies = downloadAllStrategies;
|
||||
window.toggleStrategySelection = toggleStrategySelection;
|
||||
window.showComparison = showComparison;
|
||||
window.hideComparison = hideComparison;
|
||||
window.toggleCustomBarsInput = toggleCustomBarsInput;
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Utility Functions for FxMath Quant
|
||||
* Helper functions for profit calculations and formatting
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get profit multiplier based on symbol type
|
||||
* @param {string} symbol - Trading symbol (e.g., "EURUSD", "USDJPY", "XAUUSD")
|
||||
* @returns {number} - Multiplier to convert price difference to pips/points
|
||||
*/
|
||||
function getProfitMultiplier(symbol) {
|
||||
if (!symbol) return 10000; // Default to standard forex
|
||||
|
||||
const upperSymbol = symbol.toUpperCase();
|
||||
|
||||
// Check for JPY pairs (2 decimal places)
|
||||
if (upperSymbol.includes('JPY')) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
// Check for XAU (Gold) - already in dollars
|
||||
if (upperSymbol.includes('XAU')) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Default: standard forex pairs (EURUSD, GBPUSD, etc.) - 4 decimal places
|
||||
return 10000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format profit value with appropriate multiplier
|
||||
* @param {number} profit - Raw profit value (price difference)
|
||||
* @param {string} symbol - Trading symbol
|
||||
* @param {number} decimals - Number of decimal places (default: 2)
|
||||
* @returns {string} - Formatted profit string
|
||||
*/
|
||||
function formatProfit(profit, symbol, decimals = 2) {
|
||||
const multiplier = getProfitMultiplier(symbol);
|
||||
return (profit * multiplier).toFixed(decimals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract symbol from filename
|
||||
* @param {string} filename - CSV filename (e.g., "EURUSD_H1.csv")
|
||||
* @returns {string} - Symbol name
|
||||
*/
|
||||
function extractSymbolFromFilename(filename) {
|
||||
if (!filename) return '';
|
||||
|
||||
// Remove path and extension
|
||||
const basename = filename.split('/').pop().split('\\').pop();
|
||||
const nameWithoutExt = basename.replace(/\.(csv|txt)$/i, '');
|
||||
|
||||
// Extract symbol (everything before first underscore or period)
|
||||
const symbol = nameWithoutExt.split(/[_\.]/)[0];
|
||||
|
||||
return symbol || '';
|
||||
}
|
||||
|
||||
// Export functions
|
||||
if (typeof window !== 'undefined') {
|
||||
window.getProfitMultiplier = getProfitMultiplier;
|
||||
window.formatProfit = formatProfit;
|
||||
window.extractSymbolFromFilename = extractSymbolFromFilename;
|
||||
}
|
||||
Reference in New Issue
Block a user