@ -2,67 +2,67 @@ import type { CalendarDatabase } from "./interfaces.js";
import { open } from "lmdbx" ;
import { open } from "lmdbx" ;
const calendarAggregatesDb = open ( {
const calendarAggregatesDb = open ( {
path : "./calendar-aggregates.db" ,
path : "./calendar-aggregates.db" ,
compression : true ,
compression : true ,
} ) ;
} ) ;
const calendarExistenceDb = open ( {
const calendarExistenceDb = open ( {
path : "./calendar-existence.db" ,
path : "./calendar-existence.db" ,
compression : true ,
compression : true ,
} ) ;
} ) ;
/** Largest possible key according to the `ordered-binary` (used by lmdbx) docs. */
/** Largest possible key according to the `ordered-binary` (used by lmdbx) docs. */
const MAXIMUM_KEY = Buffer . from ( [ 0xff ] ) ;
const MAXIMUM_KEY = Buffer . from ( [ 0xff ] ) ;
function makeCalendarDatabase ( ) : CalendarDatabase {
function makeCalendarDatabase ( ) : CalendarDatabase {
const calendarDatabase : Omit < CalendarDatabase , " getCalendars " > = {
const calendarDatabase : Omit < CalendarDatabase , " getCalendars " > = {
getKeys : async ( { key : { symbol } , date } ) = > {
getKeys : async ( { key : { symbol } , date } ) = > {
return calendarExistenceDb
return calendarExistenceDb
. getRange ( {
. getRange ( {
start : [ date , symbol ] ,
start : [ date , symbol ] ,
end : [ date , symbol , MAXIMUM_KEY ] ,
end : [ date , symbol , MAXIMUM_KEY ] ,
} )
} )
. map ( ( { key } ) = > ( {
. map ( ( { key } ) = > ( {
symbol ,
symbol ,
frontExpirationDate : key [ 2 ] ,
frontExpirationDate : key [ 2 ] ,
backExpirationDate : key [ 3 ] ,
backExpirationDate : key [ 3 ] ,
strike : key [ 4 ] ,
strike : key [ 4 ] ,
type : key [ 5 ] ,
type : key [ 5 ] ,
} ) ) . asArray ;
} ) ) . asArray ;
} ,
} ,
getAggregates : async ( {
getAggregates : async ( {
key : { symbol , frontExpirationDate , backExpirationDate , strike , type } ,
key : { symbol , frontExpirationDate , backExpirationDate , strike , type } ,
date ,
date ,
} ) = > {
} ) = > {
const startOfDayUnix = new Date ( ` ${ date } T00:00:00Z ` ) . valueOf ( ) ;
const startOfDayUnix = new Date ( ` ${ date } T00:00:00Z ` ) . valueOf ( ) ;
const endOfDayUnix = startOfDayUnix + 3600 * 24 * 1000 ;
const endOfDayUnix = startOfDayUnix + 3600 * 24 * 1000 ;
return calendarAggregatesDb
return calendarAggregatesDb
. getRange ( {
. getRange ( {
start : [
start : [
symbol ,
symbol ,
frontExpirationDate ,
frontExpirationDate ,
backExpirationDate ,
backExpirationDate ,
strike ,
strike ,
type ,
type ,
startOfDayUnix ,
startOfDayUnix ,
] ,
] ,
end : [
end : [
symbol ,
symbol ,
frontExpirationDate ,
frontExpirationDate ,
backExpirationDate ,
backExpirationDate ,
strike ,
strike ,
type ,
type ,
endOfDayUnix ,
endOfDayUnix ,
] ,
] ,
} )
} )
. map ( ( { value } ) = > ( {
. map ( ( { value } ) = > ( {
tsStart : value.tsStart ,
tsStart : value.tsStart ,
open : value.open ,
open : value.open ,
close : value.close ,
close : value.close ,
high : value.high ,
high : value.high ,
low : value.low ,
low : value.low ,
} ) ) . asArray ;
} ) ) . asArray ;
} ,
} ,
getAggregate : async ( {
getAggregate : async ( {
key : { symbol , frontExpirationDate , backExpirationDate , strike , type } ,
key : { symbol , frontExpirationDate , backExpirationDate , strike , type } ,
tsStart ,
tsStart ,
@ -76,89 +76,91 @@ function makeCalendarDatabase(): CalendarDatabase {
tsStart ,
tsStart ,
] ) ;
] ) ;
} ,
} ,
insertAggregates : async ( aggregates ) = > {
insertAggregates : async ( aggregates ) = > {
await calendarExistenceDb . batch ( ( ) = > {
await calendarExistenceDb . batch ( ( ) = > {
for ( const aggregate of aggregates ) {
for ( const aggregate of aggregates ) {
calendarExistenceDb . put (
calendarExistenceDb . put (
[
[
new Date ( aggregate . tsStart ) . toISOString ( ) . substring ( 0 , 10 ) ,
new Date ( aggregate . tsStart ) . toISOString ( ) . substring ( 0 , 10 ) ,
aggregate . key . symbol ,
aggregate . key . symbol ,
aggregate . key . frontExpirationDate ,
aggregate . key . frontExpirationDate ,
aggregate . key . backExpirationDate ,
aggregate . key . backExpirationDate ,
aggregate . key . strike ,
aggregate . key . strike ,
aggregate . key . type ,
aggregate . key . type ,
] ,
] ,
null
null
) ;
) ;
}
}
} ) ;
} ) ;
await calendarAggregatesDb . batch ( ( ) = > {
await calendarAggregatesDb . batch ( ( ) = > {
for ( const aggregate of aggregates ) {
for ( const aggregate of aggregates ) {
calendarAggregatesDb . put (
calendarAggregatesDb . put (
[
[
aggregate . key . symbol ,
aggregate . key . symbol ,
aggregate . key . frontExpirationDate ,
aggregate . key . frontExpirationDate ,
aggregate . key . backExpirationDate ,
aggregate . key . backExpirationDate ,
aggregate . key . strike ,
aggregate . key . strike ,
aggregate . key . type ,
aggregate . key . type ,
aggregate . tsStart ,
aggregate . tsStart ,
] ,
] ,
{
{
open : aggregate.open ,
open : aggregate.open ,
close : aggregate.close ,
close : aggregate.close ,
high : aggregate.high ,
high : aggregate.high ,
low : aggregate.low ,
low : aggregate.low ,
}
}
) ;
) ;
}
}
} ) ;
} ) ;
} ,
} ,
getClosingPrice : async ( {
getClosingPrice : async ( {
key : { symbol , strike , type , frontExpirationDate , backExpirationDate } ,
key : { symbol , strike , type , frontExpirationDate , backExpirationDate } ,
} ) = > {
} ) = > {
const startOfLastHourUnix = new Date (
const startOfExpirationDateUnix = new Date (
` ${ frontExpirationDate } T00:00:00Z ` ,
` ${ frontExpirationDate } T23:59:59Z `
) . valueOf ( ) ;
) . valueOf ( ) ;
const endOfLastHourUnix = startOfLastHourUnix + 3600 * 1000 ;
const endOfExpirationDateUnix = new Date (
let minPrice = 0 ;
` ${ frontExpirationDate } T00:00:00Z `
for ( const { value } of calendarAggregatesDb . getRange ( {
) . valueOf ( ) ;
start : [
for ( const { value } of calendarAggregatesDb . getRange ( {
symbol ,
start : [
frontExpirationDate ,
symbol ,
backExpirationDate ,
frontExpirationDate ,
strike ,
backExpirationDate ,
type ,
strike ,
startOfLastHourUnix ,
type ,
] ,
startOfExpirationDateUnix ,
end : [
] ,
symbol ,
end : [
frontExpirationDate ,
symbol ,
backExpirationDate ,
frontExpirationDate ,
strike ,
backExpirationDate ,
type ,
strike ,
endOfLastHourUnix ,
type ,
] ,
endOfExpirationDateUnix ,
} ) ) {
] ,
if ( value . close < minPrice || minPrice === 0 ) {
reverse : true ,
minPrice = value . close ;
} ) ) {
}
if ( value . close > 0 ) {
}
return value . close ;
return minPrice ;
}
} ,
}
getTargetPriceByProbability : async ( {
return 0 ;
symbol ,
} ,
calendarSpan ,
getTargetPriceByProbability : async ( {
strikePercentageFromTheMoney ,
symbol ,
historicalProbabilityOfSuccess ,
calendarSpan ,
} ) = > {
strikePercentageFromTheMoney ,
return 0.24 ;
historicalProbabilityOfSuccess ,
} ,
} ) = > {
} ;
return 0.24 ;
} ,
} ;
return {
return {
. . . calendarDatabase ,
. . . calendarDatabase ,
getCalendars : calendarDatabase.getKeys ,
getCalendars : calendarDatabase.getKeys ,
} ;
} ;
}
}
export const calendarDatabase : CalendarDatabase = makeCalendarDatabase ( ) ;
export const calendarDatabase : CalendarDatabase = makeCalendarDatabase ( ) ;