AI-Powered Market Making Strategy Simulator

AI-Powered Market Making Strategy Simulator

Simulate a market-making strategy and analyze its performance under various market conditions with AI insights.

Simulation Parameters

Higher value means more price swings.

Positive for uptrend, negative for downtrend.

Generating AI insights...

`; const initialCapital = parseFloat(initialCapitalInput.value); const bidAskSpreadPct = parseFloat(bidAskSpreadInput.value); const orderSize = parseInt(orderSizeInput.value); const simulationDuration = parseInt(simulationDurationInput.value); const marketVolatility = parseFloat(marketVolatilityInput.value); const marketTrend = parseFloat(marketTrendInput.value); // Input Validation if (isNaN(initialCapital) || initialCapital <= 0) { showMessageBox("Input Error", "Please enter a valid positive initial capital."); resetButtonState(runSimulationBtn, runSimulationBtnText, runSimulationSpinner); return; } if (isNaN(bidAskSpreadPct) || bidAskSpreadPct <= 0) { showMessageBox("Input Error", "Please enter a valid positive bid-ask spread percentage."); resetButtonState(runSimulationBtn, runSimulationBtnText, runSimulationSpinner); return; } if (isNaN(orderSize) || orderSize <= 0) { showMessageBox("Input Error", "Please enter a valid positive order size."); resetButtonState(runSimulationBtn, runSimulationBtnText, runSimulationSpinner); return; } if (isNaN(simulationDuration) || simulationDuration < 10) { showMessageBox("Input Error", "Please enter a simulation duration of at least 10 days."); resetButtonState(runSimulationBtn, runSimulationBtnText, runSimulationSpinner); return; } if (isNaN(marketVolatility) || marketVolatility <= 0) { showMessageBox("Input Error", "Please enter a valid positive market volatility."); resetButtonState(runSimulationBtn, runSimulationBtnText, runSimulationSpinner); return; } if (initialCapital < orderSize * 100) { // Assuming initial price around 100 for a rough check showMessageBox("Capital Warning", "Initial capital might be too low for the chosen order size and market price. Consider increasing capital or reducing order size."); } const initialAssetPrice = 100; // Start asset price at $100 for simulation simplicity const simulatedPrices = generateSimulatedPrices(initialAssetPrice, simulationDuration, marketVolatility, marketTrend); const simulationResults = simulateMarketMaking( initialCapital, bidAskSpreadPct, orderSize, simulatedPrices ); displayPerformanceMetrics(simulationResults); displayPnlTrendChart(simulationResults.pnlHistory, simulationDuration); const resultsSectionElement = document.getElementById('results-section'); if (resultsSectionElement) { resultsSectionElement.classList.remove('hidden'); resultsSectionElement.scrollIntoView({ behavior: 'smooth' }); } if (downloadPdfBtn) downloadPdfBtn.disabled = false; // Generate AI insights await getAIAnalysis(simulationResults, { initialCapital, bidAskSpreadPct, orderSize, simulationDuration, marketVolatility, marketTrend, initialAssetPrice }); resetButtonState(runSimulationBtn, runSimulationBtnText, runSimulationSpinner); }; // --- Display Results --- /** * Populates the performance metrics table. */ function displayPerformanceMetrics(results) { document.getElementById('total-pnl').textContent = `$${results.totalPnl.toFixed(2)}`; document.getElementById('realized-pnl').textContent = `$${results.realizedPnl.toFixed(2)}`; // Unrealized P&L can be derived from final capital - realized P&L - initial capital if inventory is zero. // Otherwise, it's (current price - avg cost) * inventory. For simplicity, we just use the calculated value. document.getElementById('unrealized-pnl').textContent = `$${(results.finalCapital - results.realizedPnl - results.initialCapital).toFixed(2)}`; document.getElementById('max-drawdown').textContent = `$${results.maxDrawdown.toFixed(2)}`; document.getElementById('sharpe-ratio').textContent = results.sharpeRatio.toFixed(2); document.getElementById('final-capital').textContent = `$${results.finalCapital.toFixed(2)}`; } /** * Displays the cumulative P&L trend chart. */ function displayPnlTrendChart(pnlHistory, durationDays) { const ctx = pnlTrendChartCanvas?.getContext('2d'); if (!ctx) return; if (pnlChartInstance) { pnlChartInstance.destroy(); } const labels = Array.from({ length: durationDays }, (_, i) => `Day ${i + 1}`); pnlChartInstance = new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [{ label: 'Cumulative P&L ($)', data: pnlHistory, borderColor: 'rgb(79, 70, 229)', // Indigo backgroundColor: 'rgba(79, 70, 229, 0.2)', fill: true, tension: 0.1, pointRadius: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { tooltip: { callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label) { label += ': '; } if (context.parsed.y !== null) { label += '$' + context.parsed.y.toFixed(2); } return label; } } } }, scales: { x: { title: { display: true, text: 'Simulation Day' } }, y: { title: { display: true, text: 'Cumulative P&L ($)' }, beginAtZero: true // P&L can start at zero } } } }); } // --- AI Integration --- /** * Calls the Gemini API to get AI-powered insights on the simulation results. * @param {Object} results - Simulation results object. * @param {Object} params - Simulation parameters. */ const getAIAnalysis = async (results, params) => { const aiContainer = document.getElementById('ai-insights-content'); if (!aiContainer) return; aiContainer.innerHTML = `

Generating AI insights...

`; const prompt = ` You are a financial analyst specializing in quantitative trading strategies. A user ran a market-making simulation with the following parameters: - Initial Capital: $${params.initialCapital.toLocaleString()} - Bid-Ask Spread: ${params.bidAskSpreadPct}% - Order Size: ${params.orderSize} units - Simulation Duration: ${params.simulationDuration} days - Market Volatility (Daily): ${params.marketVolatility}% - Market Trend (Daily): ${params.marketTrend}% - Initial Asset Price: $${params.initialAssetPrice} Here are the key simulation results: - Total P&L: $${results.totalPnl.toFixed(2)} - Realized P&L: $${results.realizedPnl.toFixed(2)} - Unrealized P&L: $${(results.finalCapital - results.realizedPnl - params.initialCapital).toFixed(2)} - Max Drawdown: $${results.maxDrawdown.toFixed(2)} - Sharpe Ratio (Annualized): ${results.sharpeRatio.toFixed(2)} - Final Capital: $${results.finalCapital.toFixed(2)} Provide a brief, actionable analysis (around 300-400 words) covering: 1. Strategy Performance: Comment on the overall profitability (or loss), Sharpe Ratio, and drawdown, explaining what these metrics indicate. 2. Impact of Parameters: Discuss how the chosen parameters (e.g., spread, volatility, trend) likely influenced the results. For example, a wider spread typically means higher potential profit per trade but fewer fills, while high volatility can create more opportunities but also higher risk. 3. Potential Improvements/Risks: Suggest adjustments to the strategy parameters or conditions that could be tested for better performance, and highlight key risks of market making (e.g., adverse selection, inventory risk). 4. Caveats: Remind the user that this is a simplified simulation and real-world market making is more complex. Format the response in simple HTML using only

for titles and
  • for lists. `; try { const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }] }; const apiKey = ""; // API key is handled by the Canvas environment at runtime const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); let text = "

    Could not generate AI analysis. Please try again.

    "; if (result.candidates && result.candidates[0] && result.candidates[0].content && result.candidates[0].content.parts[0]) { text = result.candidates[0].content.parts[0].text; } aiContainer.innerHTML = text; } catch (error) { console.error("Error fetching AI insights:", error); aiContainer.innerHTML = `

    Error generating AI insights.

    `; } }; // --- PDF Export Logic --- /** * Exports the visible analysis summary (performance table, chart, and AI insights) to a PDF document. */ window.downloadPDF = async () => { // Make it global for onclick attribute const btn = document.getElementById('pdf-button-container')?.querySelector('button'); if (!btn) return; btn.disabled = true; btn.textContent = 'Generating PDF...'; const content = document.getElementById('summary-for-pdf'); if (!content) { showMessageBox("PDF Error", "Content for PDF not found."); btn.disabled = false; btn.textContent = 'Download Analysis as PDF'; return; } try { // Temporarily adjust chart and table sizes for better PDF rendering const chartCanvas = pnlTrendChartCanvas; const originalChartWidth = chartCanvas.style.width; const originalChartHeight = chartCanvas.style.height; chartCanvas.style.width = '1000px'; // Larger size for better quality capture chartCanvas.style.height = '500px'; if (pnlChartInstance) { pnlChartInstance.resize(); // Trigger Chart.js to redraw with new dimensions } const summaryTable = performanceSummaryTable; const originalTableWidth = summaryTable.style.width; summaryTable.style.width = 'fit-content'; // Allow table to expand naturally for capture const canvas = await html2canvas(content, { scale: 2, // Increase scale for better resolution useCORS: true, logging: false, backgroundColor: '#ffffff' // Ensure the background is white for PDF }); // Restore original chart and table sizes chartCanvas.style.width = originalChartWidth; chartCanvas.style.height = originalChartHeight; if (pnlChartInstance) { pnlChartInstance.resize(); } summaryTable.style.width = originalTableWidth; const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; // Determine orientation based on content width. If the captured canvas is very wide, use landscape. const orientation = canvas.width > canvas.height * 1.5 ? 'landscape' : 'portrait'; const pdf = new jsPDF({ orientation: orientation, unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const imgWidth = pdfWidth - 20; // 10mm margin on each side let imgHeight = (canvas.height * imgWidth) / canvas.width; let finalImgWidth = imgWidth; let finalImgHeight = imgHeight; if (finalImgHeight > pdfHeight - 20) { // If image is taller than page height finalImgHeight = pdfHeight - 20; finalImgWidth = (canvas.width * finalImgHeight) / canvas.height; } const x = (pdfWidth - finalImgWidth) / 2; const y = (pdfHeight - finalImgHeight) / 2; pdf.addImage(imgData, 'PNG', x, y, finalImgWidth, finalImgHeight); pdf.save(`Market_Making_Simulation_Analysis_${new Date().toISOString().slice(0, 10)}.pdf`); showMessageBox("PDF Generated", "Your Market Making Strategy Simulation analysis PDF has been successfully downloaded."); } catch(e) { console.error("PDF Generation Error: ", e); showMessageBox("PDF Error", "An error occurred while generating the PDF. Please ensure all content is visible and try again."); } finally { btn.disabled = false; btn.textContent = 'Download Analysis as PDF'; } }; // --- Initial Setup --- // No initial simulation run, user explicitly clicks. });

Scroll to Top