Order Flow Analytics Platform (Conceptual Simulator)

Input Mock Order Flow Data

Enter one event per line. 'ask' side means buyer aggressor (traded AT ask price). 'bid' side means seller aggressor (traded AT bid price).

Order Flow Metrics

Process data in Tab 1 to view metrics.

Cumulative Delta Chart (Conceptual)

Chart will appear after processing data.

Volume Profile & Price Level Analysis

Shows total volume traded at each price level based on input data, split by bid/ask aggressor volume.

Volume Profile chart will appear after processing data.

Conceptual Interpretation & Insights

Interpretations based on the processed mock data will appear here.

No data processed. Input data in Tab 1 and click "Process Data".

'; chartContainer.innerHTML = '

Chart will appear after processing data.

'; return; } const res = ofap_analysisResults; let totalAskVolume = 0, totalBidVolume = 0; res.volumeProfile.forEach(vp => { totalAskVolume += vp.askVolume; totalBidVolume += vp.bidVolume; }); container.innerHTML = `
MetricValue
Asset Analyzed${ofap_config.assetName}
Total Trades Processed${ofap_flowEvents.length}
Total Volume Traded${totalAskVolume + totalBidVolume}
Total Volume on Ask (Agg. Buys)${totalAskVolume}
Total Volume on Bid (Agg. Sells)${totalBidVolume}
Overall Net Delta${res.overallDelta > 0 ? '+' : ''}${res.overallDelta}
Final Cumulative Delta${res.cumulativeDeltaPoints[res.cumulativeDeltaPoints.length-1].y > 0 ? '+' : ''}${res.cumulativeDeltaPoints[res.cumulativeDeltaPoints.length-1].y}
`; const points = res.cumulativeDeltaPoints; const svgWidth = Math.min(600, (ofap_getEl('ofapContainer_main').offsetWidth || 400) - 60); // Responsive width const svgHeight = 220; const m = {top: 20, right: 20, bottom: 30, left: 40}; // margins const w = svgWidth - m.left - m.right; const h = svgHeight - m.top - m.bottom; const xMax = points.length -1; const yVals = points.map(p => p.y); const yMin = Math.min(0, ...yVals); const yMax = Math.max(0, ...yVals); const xScale = x => (x / (xMax === 0 ? 1: xMax)) * w; const yScale = y => h - ((y - yMin) / (yMax - yMin === 0 ? 1 : yMax - yMin)) * h; let pathData = "M" + points.map(p => `${xScale(p.x).toFixed(2)},${yScale(p.y).toFixed(2)}`).join(" L"); chartContainer.innerHTML = ` {/* X-axis (zero line for delta) */} {/* Y-axis */} {/* X-axis */} Number of Trades/Events (${xMax}) Cumulative Delta ${yMax} ${yMin} ${yMin < 0 && yMax > 0 ? `0` : ''} `; } function ofap_displayVolumeProfile() { const chartContainer = ofap_getEl('ofap_volumeProfileChartContainer'); const keyLevelsContainer = ofap_getEl('ofap_volumeProfileKeyLevels'); if (!chartContainer || !keyLevelsContainer) return; if (!ofap_analysisResults || ofap_analysisResults.volumeProfile.length === 0) { chartContainer.innerHTML = '

No data processed. Input data in Tab 1.

'; keyLevelsContainer.innerHTML = ''; return; } const vpData = ofap_analysisResults.volumeProfile; // Assumed sorted by price desc const maxTotalVolumeAtPrice = Math.max(...vpData.map(p => p.totalVolume), 0); chartContainer.innerHTML = ''; // Clear previous const precision = ofap_config.tickSizePrecision(); vpData.forEach(level => { const bidWidthPercent = maxTotalVolumeAtPrice > 0 ? (level.bidVolume / maxTotalVolumeAtPrice) * 100 : 0; const askWidthPercent = maxTotalVolumeAtPrice > 0 ? (level.askVolume / maxTotalVolumeAtPrice) * 100 : 0; const barDiv = document.createElement('div'); barDiv.className = 'ofap_vp_bar_container'; let isPoc = ofap_analysisResults.poc && ofap_analysisResults.poc.price === level.price; // To make bid volumes appear on left and ask on right relative to a "center" (not implemented here, just stacked L-R) // A more traditional VP would draw from center, or bids left, asks right aligned to price. // This is simplified: bids first, then asks, inside a wrapper. barDiv.innerHTML = ` ${level.price.toFixed(precision)}
${level.totalVolume}
`; chartContainer.appendChild(barDiv); }); keyLevelsContainer.innerHTML = `

Key Volume Profile Levels:

`; if (ofap_analysisResults.poc) { keyLevelsContainer.innerHTML += `

Point of Control (POC): ${ofap_analysisResults.poc.price.toFixed(precision)} (Volume: ${ofap_analysisResults.poc.totalVolume})

`; } if (ofap_analysisResults.hvn.length > 0) { keyLevelsContainer.innerHTML += `

High Volume Node(s) (examples): ${ofap_analysisResults.hvn.slice(0,3).map(n=>n.price.toFixed(precision)).join(', ')}

`; } } function ofap_displayInterpretations() { const container = ofap_getEl('ofap_interpretationText'); if (!container) return; if (!ofap_analysisResults || ofap_analysisResults.interpretations.length === 0) { container.innerHTML = '

No data processed or specific interpretations generated. Process data in Tab 1.

'; return; } container.innerHTML = '
    ' + ofap_analysisResults.interpretations.map(interp => `
  • ${interp}
  • `).join('') + '
'; } // --- PDF Generation --- function ofap_downloadPDF() { if (!ofap_analysisResults) { alert("Please process data first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF library (jsPDF) is not loaded.'); return; } const { jsPDF: JSPDF } = window.jspdf; const doc = new JSPDF(); let y = 15; const m = 15; const cw = doc.internal.pageSize.getWidth() - (2 * m); const res = ofap_analysisResults; const precision = ofap_config.tickSizePrecision(); function addLine(text, size, style = 'normal', indent = 0, spacing = 2.5) { if (y > 270) { doc.addPage(); y = m; } doc.setFontSize(size); doc.setFont(undefined, style); const lines = doc.splitTextToSize(text, cw - indent); doc.text(lines, m + indent, y); y += (lines.length * (size * 0.35)) + spacing; } addLine(`Order Flow Analysis: ${ofap_config.assetName}`, 16, 'bold', 0, 5); addLine(`Processed ${ofap_flowEvents.length} events. Tick Size: ${ofap_config.tickSize}`, 10); y += 5; addLine("Key Metrics:", 12, 'bold', 0, 3); let totalAskVolume = 0, totalBidVolume = 0; res.volumeProfile.forEach(vp => { totalAskVolume += vp.askVolume; totalBidVolume += vp.bidVolume; }); addLine(`- Total Volume: ${totalAskVolume + totalBidVolume} (Asks: ${totalAskVolume}, Bids: ${totalBidVolume})`, 9, 'normal', 5, 1.5); addLine(`- Overall Net Delta: ${res.overallDelta > 0 ? '+' : ''}${res.overallDelta}`, 9, 'normal', 5, 1.5); addLine(`- Final Cumulative Delta: ${res.cumulativeDeltaPoints[res.cumulativeDeltaPoints.length-1].y > 0 ? '+' : ''}${res.cumulativeDeltaPoints[res.cumulativeDeltaPoints.length-1].y}`, 9, 'normal', 5, 1.5); y += 3; addLine("Volume Profile Summary:", 12, 'bold', 0, 3); if (res.poc) addLine(`- Point of Control (POC): ${res.poc.price.toFixed(precision)} (Vol: ${res.poc.totalVolume})`, 9, 'normal', 5, 1.5); addLine(`Top 5 Volume Levels by Price (Highest Price First):`, 9, 'bold', 5, 2); res.volumeProfile.slice(0,5).forEach(level => { // Displaying top 5 sorted by price as in display addLine(` Price: ${level.price.toFixed(precision)}, Total Vol: ${level.totalVolume}, Delta: ${level.delta > 0 ? '+' : ''}${level.delta} (BidV: ${level.bidVolume}, AskV: ${level.askVolume})`, 8, 'normal', 10, 1); }); y += 5; addLine("Conceptual Interpretations:", 12, 'bold', 0, 3); res.interpretations.forEach(interp => addLine(`- ${interp.replace(/|<\/strong>||<\/span>/gi, '')}`, 9, 'normal', 5, 1.5)); // Basic HTML removal doc.save(`OrderFlow_Analysis_${ofap_config.assetName.replace(/\W+/g, '_')}.pdf`); }
Scroll to Top