"<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>BTCUSDC Moving Average and Derivatives with Zoom and Pan</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</h1>
    <label for="startDate">Start Date:</label>
    <input type="date" id="startDate" value="2024-11-01">
    <label for="endDate">End Date:</label>
    <input type="date" id="endDate" value="2024-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);

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

            // Plot the data
            plotData(labels, priceData, ma99Data, derivativeData, secondDerivativeData);
        }

        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://api.binance.com/api/v3/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) {
                    ma.push(null); // Not enough data to calculate MA
                } else {
                    const windowData = data.slice(i - windowSize + 1, i + 1);
                    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 plotData(labels, priceData, ma99Data, derivativeData, secondDerivativeData) {
            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',
                        },
                        {
                            label: 'Moving Average (99)',
                            data: ma99Data,
                            borderColor: 'blue',
                            fill: false,
                            yAxisID: 'y',
                        },
                        {
                            label: 'First Derivative',
                            data: derivativeData,
                            borderColor: 'green',
                            fill: false,
                            yAxisID: 'y1',
                        },
                        {
                            label: 'Second Derivative',
                            data: secondDerivativeData,
                            borderColor: 'red',
                            fill: false,
                            yAxisID: 'y1',
                        },
                        // 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',
                        }
                    ]
                },
                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'
                            }
                        }
                    }
                }
            });

            // 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 price, moving average, derivative and second derivative drawer. i want that, put a dot on the actual price point if the derivative is smaller than -5 and second derivative is greater than 0.