You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			TypeScript
		
	
import type { CalendarDatabase } from "./interfaces.js";
 | 
						|
import { open } from "lmdbx";
 | 
						|
 | 
						|
const calendarAggregatesDb = open({
 | 
						|
  path: "./calendar-aggregates.db",
 | 
						|
  compression: true,
 | 
						|
});
 | 
						|
 | 
						|
const calendarExistenceDb = open({
 | 
						|
  path: "./calendar-existence.db",
 | 
						|
  compression: true,
 | 
						|
});
 | 
						|
 | 
						|
/** Largest possible key according to the `ordered-binary` (used by lmdbx) docs. */
 | 
						|
const MAXIMUM_KEY = Buffer.from([0xff]);
 | 
						|
 | 
						|
function makeCalendarDatabase(): CalendarDatabase {
 | 
						|
  const calendarDatabase: Omit<CalendarDatabase, "getCalendars"> = {
 | 
						|
    getKeys: async ({ key: { symbol }, date }) => {
 | 
						|
      return calendarExistenceDb
 | 
						|
        .getRange({
 | 
						|
          start: [date, symbol],
 | 
						|
          end: [date, symbol, MAXIMUM_KEY],
 | 
						|
        })
 | 
						|
        .map(({ key }) => ({
 | 
						|
          symbol,
 | 
						|
          frontExpirationDate: key[2],
 | 
						|
          backExpirationDate: key[3],
 | 
						|
          strike: key[4],
 | 
						|
          type: key[5],
 | 
						|
        })).asArray;
 | 
						|
    },
 | 
						|
    getAggregates: async ({
 | 
						|
      key: { symbol, frontExpirationDate, backExpirationDate, strike, type },
 | 
						|
      date,
 | 
						|
    }) => {
 | 
						|
      const startOfDayUnix = new Date(`${date}T00:00:00Z`).valueOf();
 | 
						|
      const endOfDayUnix = startOfDayUnix + 3600 * 24 * 1000;
 | 
						|
      return calendarAggregatesDb
 | 
						|
        .getRange({
 | 
						|
          start: [
 | 
						|
            symbol,
 | 
						|
            frontExpirationDate,
 | 
						|
            backExpirationDate,
 | 
						|
            strike,
 | 
						|
            type,
 | 
						|
            startOfDayUnix,
 | 
						|
          ],
 | 
						|
          end: [
 | 
						|
            symbol,
 | 
						|
            frontExpirationDate,
 | 
						|
            backExpirationDate,
 | 
						|
            strike,
 | 
						|
            type,
 | 
						|
            endOfDayUnix,
 | 
						|
          ],
 | 
						|
        })
 | 
						|
        .map(({ value }) => ({
 | 
						|
          tsStart: value.tsStart,
 | 
						|
          open: value.open,
 | 
						|
          close: value.close,
 | 
						|
          high: value.high,
 | 
						|
          low: value.low,
 | 
						|
        })).asArray;
 | 
						|
    },
 | 
						|
    getAggregate: async ({
 | 
						|
      key: { symbol, frontExpirationDate, backExpirationDate, strike, type },
 | 
						|
      tsStart,
 | 
						|
    }) => {
 | 
						|
      return await calendarAggregatesDb.get([
 | 
						|
        symbol,
 | 
						|
        frontExpirationDate,
 | 
						|
        backExpirationDate,
 | 
						|
        strike,
 | 
						|
        type,
 | 
						|
        tsStart,
 | 
						|
      ]);
 | 
						|
    },
 | 
						|
    insertAggregates: async (aggregates) => {
 | 
						|
      await calendarExistenceDb.batch(() => {
 | 
						|
        for (const aggregate of aggregates) {
 | 
						|
          calendarExistenceDb.put(
 | 
						|
            [
 | 
						|
              new Date(aggregate.tsStart).toISOString().substring(0, 10),
 | 
						|
              aggregate.key.symbol,
 | 
						|
              aggregate.key.frontExpirationDate,
 | 
						|
              aggregate.key.backExpirationDate,
 | 
						|
              aggregate.key.strike,
 | 
						|
              aggregate.key.type,
 | 
						|
            ],
 | 
						|
            null
 | 
						|
          );
 | 
						|
        }
 | 
						|
      });
 | 
						|
      await calendarAggregatesDb.batch(() => {
 | 
						|
        for (const aggregate of aggregates) {
 | 
						|
          calendarAggregatesDb.put(
 | 
						|
            [
 | 
						|
              aggregate.key.symbol,
 | 
						|
              aggregate.key.frontExpirationDate,
 | 
						|
              aggregate.key.backExpirationDate,
 | 
						|
              aggregate.key.strike,
 | 
						|
              aggregate.key.type,
 | 
						|
              aggregate.tsStart,
 | 
						|
            ],
 | 
						|
            {
 | 
						|
              open: aggregate.open,
 | 
						|
              close: aggregate.close,
 | 
						|
              high: aggregate.high,
 | 
						|
              low: aggregate.low,
 | 
						|
            }
 | 
						|
          );
 | 
						|
        }
 | 
						|
      });
 | 
						|
    },
 | 
						|
    getClosingPrice: async ({
 | 
						|
      key: { symbol, strike, type, frontExpirationDate, backExpirationDate },
 | 
						|
    }) => {
 | 
						|
      const startOfExpirationDateUnix = new Date(
 | 
						|
        `${frontExpirationDate}T23:59:59Z`
 | 
						|
      ).valueOf();
 | 
						|
      const endOfExpirationDateUnix = new Date(
 | 
						|
        `${frontExpirationDate}T00:00:00Z`
 | 
						|
      ).valueOf();
 | 
						|
      for (const { value } of calendarAggregatesDb.getRange({
 | 
						|
        start: [
 | 
						|
          symbol,
 | 
						|
          frontExpirationDate,
 | 
						|
          backExpirationDate,
 | 
						|
          strike,
 | 
						|
          type,
 | 
						|
          startOfExpirationDateUnix,
 | 
						|
        ],
 | 
						|
        end: [
 | 
						|
          symbol,
 | 
						|
          frontExpirationDate,
 | 
						|
          backExpirationDate,
 | 
						|
          strike,
 | 
						|
          type,
 | 
						|
          endOfExpirationDateUnix,
 | 
						|
        ],
 | 
						|
        reverse: true,
 | 
						|
      })) {
 | 
						|
        if (value.close > 0) {
 | 
						|
          return value.close;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return 0;
 | 
						|
    },
 | 
						|
    getTargetPriceByProbability: async ({
 | 
						|
      symbol,
 | 
						|
      calendarSpan,
 | 
						|
      strikePercentageFromTheMoney,
 | 
						|
      historicalProbabilityOfSuccess,
 | 
						|
    }) => {
 | 
						|
      return 0.24;
 | 
						|
    },
 | 
						|
  };
 | 
						|
 | 
						|
  return {
 | 
						|
    ...calendarDatabase,
 | 
						|
    getCalendars: calendarDatabase.getKeys,
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
export const calendarDatabase: CalendarDatabase = makeCalendarDatabase();
 |