Quick Start

First off

If you haven't installed Depth yet, Install Depth

After installing

The installation already sets up a chart, this will go through setting up your own data adapter

Create a new file

Create a file, you could call it myDataAdapter.ts or whatever you like

Creating the class

Start by importing the types you'll need

myDataAdapter.ts

import type { IDataAdapter, SymbolInfo, OhlcvBar } from '@christtrade/depth';

Then create a class implementing IDataAdapter

myDataAdapter.ts

export class MyAdapter implements IDataAdapter {
}

You'll get errors complaining that some functions aren't implemented, which will be fixed in the next step

Finalizing the class

First, add an array containing all your symbols. If you need to get symbols from some api (or anything else that needs to be prepared), add connect() and do that there - its an optional function, for this guide, we won't need it - but if you want to use it you can

Example:
myDataAdapter.ts

private symbols: SymbolInfo[] = []

async connect():Promise<void> {
    this.symbols = await fetch('/api/symbols')
    //all other preparing you need to do...
}

For this tutorial, we'll keep it simple with a static array.

myDataAdapter.ts

private readonly symbols: SymbolInfo[] = [
    {
        symbol: '/NQ1',
        description: 'Nasdaq 100 E-mini Futures (Front Cont.)',
        exchange: 'CME',
        dataLevel: 'ohlcv',
        type: 'future',
        supportedResolutions: [
            1_000_000_000n, // 1 second in ns
            60n * 1_000_000_000n, // 1 minute
            60n * 60n * 1_000_000_000n, // 1 hour
            24n * 60n * 60n * 1_000_000_000n, // 1 day
        ],
        priceFormat: {
            precision: 2,
            minTick: 0.25,
        },
        contract: {
            multiplier: 20,
            currency: 'USD',
            continuous: true,
        },
        session: {
            hours: '1800-1700',
            timezone: 'America/New_York',
            days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu'],
            holidays: [],
            corrections: [],
        }
    }
];

If you're thinking this might be a lot, you should read SymbolInfo for help setting up the correct config for your symbol!

Then we'll start implementing the IDataAdapter required functions:

Starting off with resolveSymbol():

myDataAdapter.ts

resolveSymbol(symbol: string): SymbolInfo | Promise<SymbolInfo> {
    return this.symbols.find((s) => s.symbol.toLowerCase() === symbol.toLowerCase());
}

Then searchSymbols(), which fills the symbol picker:

myDataAdapter.ts

async searchSymbols(): Promise<SymbolInfo[]> {
    return this.symbols;
}

Hand back the list and the chart will match, rank, and page it for you. You can also add a list of keywords to a symbol's SymbolInfo (for example: keywords: ['gold', 'bullion']) and it becomes findable by those words too.

Matching is word-anchored and fuzzy. A query matches the start of the ticker, the start of any word in the name or keywords, or as a run of characters anchored to one of those starts (ehusdt finds ethusdt, crdano, finds Cardano etc). You can read more about how it works in the source code. Just know that it will find the symbol you're searching for.

If the amount of symbols you got is too big to ship to the browser, or you just want to take control, take the request argument and search it yourself. Make sure to say so in getCapabilities():

myDataAdapter.ts

async searchSymbols(request: SymbolSearchRequest): Promise<SymbolSearchResponse> {
    const res = await fetch(
        `/api/symbols?q=${encodeURIComponent(request.query)}&limit=${request.limit ?? 50}`,
        { signal: request.signal },
    );
    const { symbols, nextCursor } = await res.json();
    return { symbols, hasMore: !!nextCursor, cursor: nextCursor };
}

getCapabilities(): AdapterCapabilities {
    return { symbolSearch: 'server' };
}

The chart then debounces keystrokes, aborts superseded requests, and drops any answer that arrives after a newer one.

The debounce defaults to 200ms for 'server' and 0 for 'none'. If you declare 'server' only to do your own matching over a list you already hold in memory, turn the wait off.. it buys nothing and the picker feels slow with it:

getCapabilities(): AdapterCapabilities {
    return { symbolSearch: 'server', symbolSearchDebounceMs: 0 };
}

Lastly fetchBars():

myDataAdapter.ts

async fetchBars(request: FetchRequest): Promise<BarResponse[]> {
    const { symbolInfo, range, timeframe } = request;
    const res = await fetch(
        `/api/bars?symbol=${symbolInfo.symbol}&barNs=${timeframe.barNs}&from=${range.fromNs}&to=${range.toNs}`,
    );

    return {
        ohlcvBars: res.json();
    }
}

This will vary a lot depending on your setup - you could fetch from an api route (like in the example above) or possibly get your data from the public/ folder, this one is up to you. If you want free data, I'd recommend Dukascopy, they got lots of symbols, many go down to second-level

Note

If you need real time data, implement subscribeRealtime() - currenly we only implemented getting historical data. If that's all you need, you don't need to add this

subscribeRealtime() (Optional):

myDataAdapter.ts

subscribeRealtime(onBar: (bar: BarResponse) => void): () => void {
    //TBD
}

So now the full myDataAdapter.ts file should look like this:

import type { IDataAdapter, SymbolInfo, OhlcvBar } from '@christtrade/depth';

export class MyAdapter implements IDataAdapter {
    private readonly symbols: SymbolInfo[] = [
        {
            symbol: '/NQ1',
            description: 'Nasdaq 100 E-mini Futures (Front Cont.)',
            exchange: 'CME',
            dataLevel: 'ohlcv',
            type: 'future',
            supportedResolutions: [
                1_000_000_000n, // 1 second in ns
                60n * 1_000_000_000n, // 1 minute
                60n * 60n * 1_000_000_000n, // 1 hour
                24n * 60n * 60n * 1_000_000_000n, // 1 day
            ],
            priceFormat: {
                precision: 2,
                minTick: 0.25,
            },
            contract: {
                multiplier: 20,
                currency: 'USD',
                continuous: true,
            },
            session: {
                hours: '1800-1700',
                timezone: 'America/New_York',
                days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu'],
                holidays: [],
                corrections: [],
            }
        }
    ];

    async connect():Promise<void> {
        // Nothing needed here for this guide
        // Add stuff here if you need - this runs first and only once
        // set up workers, load symbols, etc...
    }

    resolveSymbol(symbol: string): SymbolInfo | Promise<SymbolInfo> {
        return this.symbols.find((s) => s.symbol.toLowerCase() === symbol.toLowerCase());
    }

    async searchSymbols(): Promise<SymbolInfo[]> {
        return this.symbols
    }

    async fetchBars(request: FetchRequest): Promise<BarResponse[]> {
        const { symbolInfo, range, timeframe } = request
        const res = await fetch(
            `/api/bars?symbol=${symbolInfo.symbol}&barNs=${timeframe.barNs}&from=${range.fromNs}&to=${range.toNs}`,
        );
    
        return {
            ohlcvBars: res.json();
        }
    }

    subscribeRealtime(onBar: (bar: BarResponse) => void): () => void {
        //TBD
    }
}

Connecting the datafeed to the chart

First import the datafeed

chart.tsx

import { MyAdapter } from './myDataAdapter.ts'

Then just replace the mock adapter with this one:

chart.tsx

import { useChristTradeChart } from '@christtrade/depth';
import { MyAdapter } from './myDataAdapter.ts' //add this

export default function MyChart() {
    // replace the mock adapter with the new one
    const adapter = useMemo(() => new MyAdapter(), []);

    const { chart, element } = useChristTradeChart({
        dataAdapter: adapter,
        symbol: '/NQ1', // Make sure to remember to update the symbol!
        horizon: Date.now(),
        initialLoad: {
            start: Date.now() - 1000 * 60 * 60 * 24,
            end: Date.now(),
        },
    });

    return <div style={{ width: '100%', height: '600px' }}>{element}</div>;
}

Done

And now we're done. Simple right?

Just keep in mind to make sure the fetchBars function should return BarResponse[]!

Now you should have a fully functional chart with your own data. You should now go to Configuration to tailor the chart to your site. If you're a pro, you could try getting trading to work with your own Execution Adapter!

Was this page helpful?