"<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>BTCUSDC Moving Average and Derivatives with Trading Simulation</title>
    <!-- Include Chart.js (Latest Version) -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <!-- Include Chart.js Zoom Plugin (Latest Version) -->
    <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom"></script>
</head>
<body>
    <h1>BTCUSDC Moving Average and Derivatives with Trading Simulation</h1>
    <label for="startDate">Start Date:</label>
    <input type="date" id="startDate" value="2023-11-01">
    <label for="endDate">End Date:</label>
    <input type="date" id="endDate" value="2023-11-05">
    <button id="fetchData">Fetch Data</button>
    <canvas id="chart" width="800" height="400"></canvas>

    <script>
        // Function to initialize the default behavior on page load
        window.onload = function() {
            main();
        };

        document.getElementById('fetchData').addEventListener('click', function() {
            main();
        });

        async function main() {
            const startDateInput = document.getElementById('startDate').value;
            const endDateInput = document.getElementById('endDate').value;

            // Convert dates to Unix timestamps in milliseconds
            const startTime = new Date(startDateInput).getTime();
            const endTime = new Date(endDateInput).getTime();

            // Fetch BTCUSDC 1-minute prices from Binance API
            const symbol = 'BTCUSDC';
            const interval = '1m';

            const klines = await fetchKlines(symbol, interval, startTime, endTime);

            if (klines.length === 0) {
                alert('No data available for the selected date range.');
                return;
            }

            // Extract closing prices and timestamps
            const timestamps = klines.map(k => k[0]); // Open time
            const closePrices = klines.map(k => parseFloat(k[4])); // Close price

            // Calculate 99-point moving average
            const ma99 = movingAverage(closePrices, 99);

            // Calculate first derivative of MA99
            const derivative = firstDerivative(ma99);

            // Calculate second derivative of MA99
            const secondDerivative = firstDerivative(derivative);

            // Calculate MA20 of the derivative
            const ma20Derivative = movingAverage(derivative, 99);

            // Calculate derivative of MA20 derivative
            const derivativeOfMA20Derivative = firstDerivative(ma20Derivative);

            // The earliest index where all data arrays have valid data
            const startingIndex = 119;

            // Prepare data for plotting
            const labels = timestamps.slice(startingIndex).map(ts => new Date(ts).toLocaleString());
            const priceData = closePrices.slice(startingIndex);
            const ma99Data = ma99.slice(startingIndex);
            const derivativeData = derivative.slice(startingIndex);
            const secondDerivativeData = secondDerivative.slice(startingIndex);
            const ma20DerivativeData = ma20Derivative.slice(startingIndex);
            const derivativeOfMA20DerivativeData = derivativeOfMA20Derivative.slice(startingIndex);

            // Simulate trading strategy
            const {specialPointsData, tradeSignals, totalAssetValueData} = simulateTrading(
                priceData,
                derivativeData,
                secondDerivativeData,
                derivativeOfMA20DerivativeData,ma99Data
            );

            // Plot the data
            plotData(
                labels,
                priceData,
                ma99Data,
                derivativeData,
                secondDerivativeData,
                ma20DerivativeData,
                derivativeOfMA20DerivativeData,
                specialPointsData,
                totalAssetValueData
            );
        }

        async function fetchKlines(symbol, interval, startTime, endTime) {
            const limit = 1000; // Max limit per request
            let klines = [];
            let fetchTime = startTime;

            while (fetchTime < endTime) {
                const url = `https://fapi.binance.com/fapi/v1/klines?symbol=${symbol}&interval=${interval}&startTime=${fetchTime}&endTime=${endTime}&limit=${limit}`;
        
                const response = await fetch(url);
                const data = await response.json();

                if (data.code) {
                    // Handle error
                    alert('Error fetching data: ' + data.msg);
                    break;
                }

                if (data.length === 0) {
                    break;
                }

                klines = klines.concat(data);
                fetchTime = data[data.length - 1][0] + 60000; // Next minute
            }

            return klines;
        }

        function movingAverage(data, windowSize) {
            let ma = [];
            for (let i = 0; i < data.length; i++) {
                if (i < windowSize - 1 || data[i] === null) {
                    ma.push(null); // Not enough data to calculate MA
                } else {
                    const windowData = data.slice(i - windowSize + 1, i + 1);
                    if (windowData.includes(null)) {
                        ma.push(null); // Moving average cannot be calculated with null values
                    } else {
                        const sum = windowData.reduce((acc, val) => acc + val, 0);
                        ma.push(sum / windowSize);
                    }
                }
            }
            return ma;
        }

        function firstDerivative(data) {
            let derivative = [];
            for (let i = 0; i < data.length; i++) {
                if (i === 0 || data[i - 1] === null || data[i] === null) {
                    derivative.push(null); // Cannot calculate derivative
                } else {
                    derivative.push(data[i] - data[i - 1]);
                }
            }
            return derivative;
        }

        function simulateTrading(priceData, derivativeData, secondDerivativeData, derivativeOfMA20DerivativeData,ma99) {
            let specialPointsData = [];
            let tradeSignals = [];
            let position = 0; // BTC holdings
            let cash = 500; // USDC balance (we start with 500 USDC)
            let totalAssetValueData = []; // Total value of assets over time in USDC

            for (let i = 0; i < priceData.length; i++) {
                // Buy condition with new criterion
                if (
                    derivativeData[i] !== null &&
                    secondDerivativeData[i] !== null &&
                    derivativeOfMA20DerivativeData[i] !== null &&
                    derivativeData[i] < -5 &&
                    secondDerivativeData[i] > 0 &&
                    derivativeOfMA20DerivativeData[i] < -0.1 &&
                    ma99[i] > priceData[i]
                ) {
                    // Buy signal
                    if (position === 0 && cash >= 50) {
                        // Buy BTC worth 50 USDC
                        let btcBought = 50 / (priceData[i]*100.06/100);
                        position += btcBought;
                        cash -= 50; // We spend 50 USDC
                        tradeSignals.push({type: 'buy', index: i, price: priceData[i]});
                    }
                    specialPointsData.push(priceData[i]); // Mark special point
                } else {
                    specialPointsData.push(null);
                }

                // Sell condition
                if (position > 0 && priceData[i] > ma99[i]) {
                    // Sell all BTC holdings
                    let proceeds = position *(
                    priceData[i]*99.94/100);
                    cash += proceeds;
                    position = 0; // Reset position

                    tradeSignals.push({type: 'sell', index: i, price: priceData[i]});
                }

                // Update total asset value
                let totalAssetValue = cash + position * priceData[i];
                totalAssetValueData.push(totalAssetValue);
            }

            return {specialPointsData, tradeSignals, totalAssetValueData};
        }

        function plotData(labels, priceData, ma99Data, derivativeData, secondDerivativeData, ma20DerivativeData, derivativeOfMA20DerivativeData, specialPointsData, totalAssetValueData) {
            const ctx = document.getElementById('chart').getContext('2d');

            // Create an array of zeros for the zero line
            const zeroData = labels.map(() => 0);

            // Clear existing chart if any
            if (window.myChart instanceof Chart) {
                window.myChart.destroy();
            }

            // Register the zoom plugin (necessary in Chart.js v4)
            Chart.register(ChartZoom);

            window.myChart = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: labels,
                    datasets: [
                        {
                            label: 'Actual Price',
                            data: priceData,
                            borderColor: 'black',
                            fill: false,
                            yAxisID: 'y',
                            pointRadius: 0, // Prevent default points
                        },
                        {
                            label: 'Moving Average (99)',
                            data: ma99Data,
                            borderColor: 'blue',
                            fill: false,
                            yAxisID: 'y',
                            pointRadius: 0,
                        },
                        {
                            label: 'First Derivative',
                            data: derivativeData,
                            borderColor: 'green',
                            fill: false,
                            yAxisID: 'y1',
                            pointRadius: 0,
                        },
                        {
                            label: 'Second Derivative',
                            data: secondDerivativeData,
                            borderColor: 'red',
                            fill: false,
                            yAxisID: 'y1',
                            pointRadius: 0,
                        },
                        // Add the zero line for derivative axis
                        {
                            label: 'Derivative Zero Line',
                            data: zeroData,
                            borderColor: 'gray',
                            borderDash: [5, 5],
                            pointRadius: 0,
                            borderWidth: 1,
                            fill: false,
                            yAxisID: 'y1',
                        },
                        // New datasets for MA20 of derivative and its derivative
                        {
                            label: 'MA20 of Derivative',
                            data: ma20DerivativeData,
                            borderColor: 'magenta',
                            fill: false,
                            yAxisID: 'y1',
                            pointRadius: 0,
                        },
                        {
                            label: 'Derivative of MA20 of Derivative',
                            data: derivativeOfMA20DerivativeData,
                            borderColor: 'cyan',
                            fill: false,
                            yAxisID: 'y1',
                            pointRadius: 0,
                        },
                        // New dataset for special points
                        {
                            label: 'Special Points (Buy Signal)',
                            data: specialPointsData,
                            borderColor: 'purple',
                            backgroundColor: 'purple',
                            pointRadius: 5, // Size of the dot
                            pointHoverRadius: 7,
                            showLine: false,
                            yAxisID: 'y',
                            type: 'line', // Ensure it aligns with the chart type
                        },
                        // Dataset for total asset value
                        {
                            label: 'Total Asset Value',
                            data: totalAssetValueData,
                            borderColor: 'orange',
                            fill: false,
                            yAxisID: 'y2',
                            pointRadius: 0,
                            borderWidth: 2,
                            tension: 0.1,
                        },
                    ]
                },
                options: {
                    responsive: true,
                    interaction: {
                        mode: 'index',
                        intersect: false,
                    },
                    stacked: false,
                    plugins: {
                        zoom: {
                            pan: {
                                enabled: true,
                                mode: 'x',
                                modifierKey: null, // Allows panning without modifier key
                            },
                            zoom: {
                                wheel: {
                                    enabled: true,
                                },
                                pinch: {
                                    enabled: true,
                                },
                                mode: 'x',
                            },
                        },
                    },
                    scales: {
                        x: {
                            display: true,
                            ticks: {
                                maxRotation: 90,
                                minRotation: 90,
                                maxTicksLimit: 20,
                            }
                        },
                        y: {
                            type: 'linear',
                            display: true,
                            position: 'left',
                            title: {
                                display: true,
                                text: 'Price / Moving Average'
                            }
                        },
                        y1: {
                            type: 'linear',
                            display: true,
                            position: 'right',
                            grid: {
                                drawOnChartArea: false,
                            },
                            title: {
                                display: true,
                                text: 'Derivatives'
                            }
                        },
                        y2: {
                            type: 'linear',
                            display: true,
                            position: 'right',
                            grid: {
                                drawOnChartArea: false,
                            },
                            title: {
                                display: true,
                                text: 'Total Asset Value (USDC)'
                            },
                            ticks: {
                                // Include USDC symbol
                                callback: function(value, index, ticks) {
                                    return '$' + value.toFixed(2);
                                }
                            },
                            // Offset the scale to the right
                            offset: true,
                        },
                    }
                }
            });

            // Add double-click event listener to reset zoom
            const canvas = document.getElementById('chart');
            canvas.addEventListener('dblclick', function(){
                window.myChart.resetZoom();
            });
        }

        // Automatically fetch data on page load
        // (Already called inside window.onload)
    </script>
</body>
</html>" this is my btcusdc strategy testing app. it takes start and end dates and shows graphs. i want that it is live. it will show graph for last 5 hours and get new data to update it every minute.