fix: getClosingPrice() for two calendardb modules
This commit is contained in:
+134
-132
@@ -2,67 +2,67 @@ import type { CalendarDatabase } from "./interfaces.js";
|
||||
import { open } from "lmdbx";
|
||||
|
||||
const calendarAggregatesDb = open({
|
||||
path: "./calendar-aggregates.db",
|
||||
compression: true,
|
||||
path: "./calendar-aggregates.db",
|
||||
compression: true,
|
||||
});
|
||||
|
||||
const calendarExistenceDb = open({
|
||||
path: "./calendar-existence.db",
|
||||
compression: true,
|
||||
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;
|
||||
},
|
||||
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,
|
||||
@@ -76,89 +76,91 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
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,
|
||||
],
|
||||
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,
|
||||
);
|
||||
}
|
||||
});
|
||||
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 startOfLastHourUnix = new Date(
|
||||
`${frontExpirationDate}T00:00:00Z`,
|
||||
).valueOf();
|
||||
const endOfLastHourUnix = startOfLastHourUnix + 3600 * 1000;
|
||||
let minPrice = 0;
|
||||
for (const { value } of calendarAggregatesDb.getRange({
|
||||
start: [
|
||||
symbol,
|
||||
frontExpirationDate,
|
||||
backExpirationDate,
|
||||
strike,
|
||||
type,
|
||||
startOfLastHourUnix,
|
||||
],
|
||||
end: [
|
||||
symbol,
|
||||
frontExpirationDate,
|
||||
backExpirationDate,
|
||||
strike,
|
||||
type,
|
||||
endOfLastHourUnix,
|
||||
],
|
||||
})) {
|
||||
if (value.close < minPrice || minPrice === 0) {
|
||||
minPrice = value.close;
|
||||
}
|
||||
}
|
||||
return minPrice;
|
||||
},
|
||||
getTargetPriceByProbability: async ({
|
||||
symbol,
|
||||
calendarSpan,
|
||||
strikePercentageFromTheMoney,
|
||||
historicalProbabilityOfSuccess,
|
||||
}) => {
|
||||
return 0.24;
|
||||
},
|
||||
};
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
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,
|
||||
};
|
||||
return {
|
||||
...calendarDatabase,
|
||||
getCalendars: calendarDatabase.getKeys,
|
||||
};
|
||||
}
|
||||
|
||||
export const calendarDatabase: CalendarDatabase = makeCalendarDatabase();
|
||||
|
||||
@@ -93,9 +93,10 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
getClosingPrice: async ({
|
||||
key: { symbol, strike, type, frontExpirationDate, backExpirationDate },
|
||||
}) => {
|
||||
// get unix timestamp, in milliseconds, of the start of the last hour, which is 03:30PM in the `America/New_York` timezone on the front expiration date:
|
||||
const startOfLastHourUnix = new Date(
|
||||
`${frontExpirationDate}T00:00:00Z`,
|
||||
).valueOf();
|
||||
`${frontExpirationDate}T19:30:00Z`
|
||||
).getTime();
|
||||
const endOfLastHourUnix = startOfLastHourUnix + 3600 * 1000;
|
||||
const frontOptionContractAggregates = (
|
||||
await optionContractDatabase.getAggregates({
|
||||
@@ -104,7 +105,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
})
|
||||
).filter(
|
||||
({ tsStart }) =>
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix,
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix
|
||||
);
|
||||
const backOptionContractAggregates = (
|
||||
await optionContractDatabase.getAggregates({
|
||||
@@ -113,7 +114,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
})
|
||||
).filter(
|
||||
({ tsStart }) =>
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix,
|
||||
tsStart >= startOfLastHourUnix && tsStart < endOfLastHourUnix
|
||||
);
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
@@ -128,7 +129,7 @@ function makeCalendarDatabase(): CalendarDatabase {
|
||||
) {
|
||||
const calendarClosePrice =
|
||||
backOptionContractAggregates[j].close -
|
||||
frontOptionContractAggregates[j].close;
|
||||
frontOptionContractAggregates[i].close;
|
||||
if (calendarClosePrice < minPrice || minPrice === 0) {
|
||||
minPrice = calendarClosePrice;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user