@debut/plugin-session
Version:
Trade session time, plugin debut
134 lines • 5.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSessionValidator = exports.sessionPlugin = void 0;
const plugin_utils_1 = require("@debut/plugin-utils");
function sessionPlugin(options, onDayEnd) {
const { from, to, interval, timezone = 'en-US' } = options;
const sessionValidator = createSessionValidator(interval, timezone, from, to);
return {
name: 'session',
api: {
createSessionValidator: createSessionFilter,
},
onBeforeTick(tick) {
const stamp = tick.time;
const result = !!sessionValidator && sessionValidator(stamp);
if (onDayEnd && result.dayChanged) {
onDayEnd();
}
return !result.inSession;
},
};
}
exports.sessionPlugin = sessionPlugin;
/**
* Метод создания валидатора из человеко читаемых дат
*/
function createSessionValidator(interval, timezone, from, to) {
let start = 0;
let end = 86400000;
const intervalMs = plugin_utils_1.date.intervalToMs(interval);
if (from) {
const [fromHour, fromMinute] = from.split(':').map(Number);
start = fromHour * 60 * 60 * 1000 + fromMinute * 60 * 1000;
}
if (to) {
const [toHour, toMinute] = to.split(':').map(Number);
end = toHour * 60 * 60 * 1000 + toMinute * 60 * 1000;
}
return createSessionFilter(intervalMs, timezone, start, end);
}
exports.createSessionValidator = createSessionValidator;
function getTimezoneOffset(d, tz) {
const a = d.toLocaleString('ja', { timeZone: tz }).split(/[/\s:]/);
// @ts-expect-error
a[1]--;
// @ts-expect-error
const t1 = Date.UTC.apply(null, a);
const t2 = new Date(d).setMilliseconds(0);
return (t2 - t1) / 60 / 1000;
}
/**
* Метод создания валидатора сессионного окна по дате, с переходом на зимнее и летнее время
*/
function createSessionFilter(intervalMs, timezone, start, end) {
let currentDayMarker = 0;
let marketStart = 0;
let marketEnd = 0;
let timeMode;
const getDST = getDSTDetector(timezone);
const [summerOffset, winterOffset] = getOffsetMs(timezone);
return (stamp) => {
const dayChanged = stamp > currentDayMarker;
if (dayChanged) {
timeMode = getDST(stamp);
}
if (dayChanged || currentDayMarker === 0) {
// Если еще нет текущей даты или сменился день, перегенерируем дату
// Коррекция дат, для разных часовых поясов, время старта указывается в летнем времени
const dstOffset = timeMode === "Summer" /* TimeMode.Summer */ ? summerOffset : winterOffset;
const currentDay = ~~(stamp / 86400000) * 86400000;
currentDayMarker = currentDay + 86400000 - 1;
// Переводич часы и минуты в stamp и прибавляем к дате
marketStart = currentDay + start + dstOffset;
marketEnd = currentDay + end + dstOffset;
}
const stampEnd = stamp + intervalMs;
return { inSession: marketStart <= stamp && stampEnd <= marketEnd, dayChanged };
};
}
// DST - Daylight saving time
const getDSTDetector = (tz) => {
const summerTimePeriods = [];
switch (tz) {
case 'America/New_York':
savingTimePeriodsForUS(summerTimePeriods);
break;
case 'Europe/Moscow': // <- no dst country
return () => "Summer" /* TimeMode.Summer */;
default:
throw new Error(`${tz} is not supported`);
}
return (stamp) => {
let isSummerDST = false;
for (let i = 0; i < summerTimePeriods.length; i++) {
if (stamp >= summerTimePeriods[i][0] && stamp < summerTimePeriods[i][1]) {
isSummerDST = true;
break;
}
}
if (isSummerDST) {
return "Summer" /* TimeMode.Summer */;
}
else {
return "Winter" /* TimeMode.Winter */;
}
};
};
/**
* Get timezone offset in ms
*/
function getOffsetMs(tz) {
const currentYear = new Date().getFullYear();
const summerOffset = getTimezoneOffset(new Date(currentYear, 6, 1), tz);
const winterOffset = getTimezoneOffset(new Date(currentYear, 0, 1), tz);
return [summerOffset * 60 * 1000, winterOffset * 60 * 1000];
}
/**
* Получение данных о переключении времени на DST для US
*/
function savingTimePeriodsForUS(summerTimePeriods) {
const currentYear = new Date().getFullYear();
// Для упрощения вычислений возьмем несколько лет
[0, 1, 2, 3, 4, -1, -2, -3, -4, -5].forEach((move) => {
const year = currentYear + move;
const march = new Date(year, 2, 7);
const secondSunday = 7 + (7 - march.getDay());
const november = new Date(year, 10, 7);
const sunday = 7 - november.getDay();
const summer = new Date(year, 2, secondSunday).getTime();
const winter = new Date(year, 10, sunday).getTime();
summerTimePeriods.push([summer, winter]);
});
}
//# sourceMappingURL=index.js.map