Skip to content

Instantly share code, notes, and snippets.

@Swoorup
Last active March 1, 2023 16:27
Show Gist options
  • Save Swoorup/e02874cd5a034b3f8b17bb71bca2056e to your computer and use it in GitHub Desktop.
Save Swoorup/e02874cd5a034b3f8b17bb71bca2056e to your computer and use it in GitHub Desktop.

Revisions

  1. Swoorup revised this gist Mar 1, 2023. 1 changed file with 35 additions and 42 deletions.
    77 changes: 35 additions & 42 deletions ViperAppDemo.tsx
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,8 @@
    import { Ref, useEffect, useRef } from 'react';
    import { useEffect, useRef } from 'react';
    import './App.css';

    import ViperCharts from "@viper-charts/viper-charts";
    import type { HistoricalDataRequest } from "@viper-charts/viper-charts/state/classes/data";
    import { DataUpdates, HistoricalDataRequest, Price, UTCTimestamp, Viper as ViperCharts } from "@viper-charts/viper-charts";
    // import "@viper-charts/viper-charts/dist/style.css";
    import { ViperDatabase } from "./ViperDatabase";

    const db = createDB();
    @@ -54,10 +54,9 @@ async function getSourcesFromBinance() {
    name: item.symbol,
    maxItemsPerRequest: 500,
    models: {
    price: {
    id: "price",
    model: "ohlc",
    name: "Price",
    candle: {
    model_id: "candle",
    name: "Candle",
    label: `Binance:${item.symbol}`,
    },
    },
    @@ -68,10 +67,7 @@ async function getSourcesFromBinance() {
    }


    type OnRequestHistoricalDataParams = {
    requests: HistoricalDataRequest[];
    }
    const onRequestHistoricalData = (viper: React.RefObject<ViperCharts | null>) => async ({ requests, }: OnRequestHistoricalDataParams) => {
    const onRequestHistoricalData = async (requests: HistoricalDataRequest[], api: ViperCharts) => {
    for (const {
    source,
    name,
    @@ -81,39 +77,36 @@ const onRequestHistoricalData = (viper: React.RefObject<ViperCharts | null>) =>
    end,
    } of requests) {
    if (source === "BINANCE") {
    const tf = {
    1000: "1s",
    60000: "1m",
    [60000 * 5]: "5m",
    [60000 * 15]: "15m",
    [60000 * 60]: "1h",
    [60000 * 60 * 4]: "4h",
    [60000 * 60 * 24]: "1d",
    }[timeframe];
    const res = await fetch(`https://www.binance.com/api/v3/klines?symbol=${name}&interval=${tf}&startTime=${start}&endTime=${end}`);
    const json = await res.json();

    for (const dataModel of dataModels) {
    const tf = {
    1000: "1s",
    60000: "1m",
    [60000 * 5]: "5m",
    [60000 * 15]: "15m",
    [60000 * 60]: "1h",
    [60000 * 60 * 4]: "4h",
    [60000 * 60 * 24]: "1d",
    }[timeframe];

    const res = await fetch(
    `https://www.binance.com/api/v3/klines?symbol=${name}&interval=${tf}&startTime=${start}&endTime=${end}`,
    );
    const json = await res.json();

    const data: any = {};

    for (const item of json) {
    const [timestamp, open, high, low, close] = item;

    const isoString = new Date(timestamp).toISOString();

    data[isoString] = {
    open: +open,
    high: +high,
    low: +low,
    close: +close,
    };
    if (dataModel === "candle") {
    const data = new Map() as DataUpdates;
    for (const item of json) {
    const [timestamp, open, high, low, close, volume] = item;
    const time = new Date(timestamp).getTime();
    data.set(time as UTCTimestamp, {
    open: +open as Price,
    high: +high as Price,
    low: +low as Price,
    close: +close as Price,
    volume: +volume
    });
    }
    api.addData({ source, name, timeframe, dataModel }, data);
    }

    viper.current?.addData({ source, name, timeframe, dataModel }, data);
    }

    }
    }
    }
    @@ -143,7 +136,7 @@ function App() {
    element: htmlRef.current,
    sources,
    settings: JSON.parse(localStorage.getItem("settings")!) || {},
    onRequestHistoricalData: onRequestHistoricalData(viperChartRef),
    onRequestHistoricalData,
    onSaveViperSettings,
    onRequestTemplates,
    onSaveTemplate,
  2. Swoorup created this gist Feb 25, 2023.
    169 changes: 169 additions & 0 deletions ViperAppDemo.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,169 @@
    import { Ref, useEffect, useRef } from 'react';
    import './App.css';

    import ViperCharts from "@viper-charts/viper-charts";
    import type { HistoricalDataRequest } from "@viper-charts/viper-charts/state/classes/data";
    import { ViperDatabase } from "./ViperDatabase";

    const db = createDB();

    function onSaveViperSettings(settings: any) {
    localStorage.setItem("settings", JSON.stringify(settings));
    }

    async function onRequestTemplates() {
    return await db.templates.where("id").above(0).toArray();
    }

    async function onSaveTemplate(id: number, { name, config }: any) {
    // Check if template exists at id
    const rows = await db.templates.where("id").equals(id).toArray();
    const row = rows[0];

    if (row) {
    // If so, update it
    await db.templates.update(id, { name, config });
    } else {
    // If not, create it
    await db.templates.add({ name, config });
    }

    return await db.templates.orderBy("id").last();
    }

    async function onDeleteTemplate(id: number) {
    await db.templates.delete(id);
    }

    function createDB() {
    const db = new ViperDatabase();
    return db;
    }

    async function getSourcesFromBinance() {
    const res = await fetch(
    "https://www.binance.com/api/v3/exchangeInfo"
    );
    const json = await res.json();

    const sources: any = {};

    for (const item of json.symbols) {
    sources[item.symbol] = {
    source: "BINANCE",
    name: item.symbol,
    maxItemsPerRequest: 500,
    models: {
    price: {
    id: "price",
    model: "ohlc",
    name: "Price",
    label: `Binance:${item.symbol}`,
    },
    },
    };
    }

    return sources;
    }


    type OnRequestHistoricalDataParams = {
    requests: HistoricalDataRequest[];
    }
    const onRequestHistoricalData = (viper: React.RefObject<ViperCharts | null>) => async ({ requests, }: OnRequestHistoricalDataParams) => {
    for (const {
    source,
    name,
    timeframe,
    dataModels,
    start,
    end,
    } of requests) {
    if (source === "BINANCE") {
    for (const dataModel of dataModels) {
    const tf = {
    1000: "1s",
    60000: "1m",
    [60000 * 5]: "5m",
    [60000 * 15]: "15m",
    [60000 * 60]: "1h",
    [60000 * 60 * 4]: "4h",
    [60000 * 60 * 24]: "1d",
    }[timeframe];

    const res = await fetch(
    `https://www.binance.com/api/v3/klines?symbol=${name}&interval=${tf}&startTime=${start}&endTime=${end}`,
    );
    const json = await res.json();

    const data: any = {};

    for (const item of json) {
    const [timestamp, open, high, low, close] = item;

    const isoString = new Date(timestamp).toISOString();

    data[isoString] = {
    open: +open,
    high: +high,
    low: +low,
    close: +close,
    };
    }

    viper.current?.addData({ source, name, timeframe, dataModel }, data);
    }
    }
    }
    }


    function App() {
    const viperChartRef = useRef<ViperCharts | null>(null);
    const htmlRef = useRef<HTMLDivElement | null>(null);

    useEffect(() => {
    console.log("Initializing...");
    async function initializeViper() {
    // The sources available to ViperCharts
    const sources = {
    BINANCE: await getSourcesFromBinance(),
    };

    if (!htmlRef.current) return;

    if (viperChartRef.current) {
    // destroy if already initializing. In some instances useEffect is called twice.
    viperChartRef.current.destroy();
    };

    // document.getElementById("chart")!,
    viperChartRef.current = new ViperCharts({
    element: htmlRef.current,
    sources,
    settings: JSON.parse(localStorage.getItem("settings")!) || {},
    onRequestHistoricalData: onRequestHistoricalData(viperChartRef),
    onSaveViperSettings,
    onRequestTemplates,
    onSaveTemplate,
    onDeleteTemplate,
    });
    }

    initializeViper();

    return () => {
    viperChartRef.current?.destroy();
    viperChartRef.current = null;
    }
    }, [htmlRef])

    return (
    <div className="App">
    <div ref={htmlRef} id="chart" style={{ width: "100%", height: "100vh" }}></div>
    </div>
    );
    }

    export default App;