From d8f8b049431c2b61fa591f1969a1d2f55066d620 Mon Sep 17 00:00:00 2001 From: KienVT9 Date: Fri, 11 Jul 2025 17:28:40 +0700 Subject: [PATCH] update --- ecosystem.config.js | 18 ++ src/app.ts | 2 +- src/dao/analysis.ts | 22 +++ src/dao/order.ts | 9 + src/dao/position.ts | 9 + src/dao/subwave.ts | 10 ++ src/dao/wave.ts | 9 + src/handlers/candleHandler.ts | 20 ++- src/helpers/candles.ts | 32 +++- src/schedule/candleAnalysisSchedule.ts | 103 +++++++++-- src/schedule/index.ts | 8 + src/services/indicatorService.ts | 231 +++++++++++++++++++++++-- src/services/supabaseService.ts | 2 +- test.ts | 20 +-- tsconfig.json | 125 ++----------- 15 files changed, 458 insertions(+), 162 deletions(-) create mode 100644 ecosystem.config.js create mode 100644 src/dao/order.ts create mode 100644 src/dao/position.ts create mode 100644 src/dao/subwave.ts create mode 100644 src/dao/wave.ts create mode 100644 src/schedule/index.ts diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..166bfdf --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1,18 @@ +module.exports = { + apps: [ + { + name: "ai-trading-sys", + script: "node dist/app.js", + instances: 1, + autorestart: true, + watch: false, + max_memory_restart: "512M", + env: { + NODE_ENV: "development", + }, + env_production: { + NODE_ENV: "production", + }, + }, + ], +}; \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 9f2293f..dfd1e5c 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,7 +6,7 @@ import positionsApi from './api/positions'; import candlesApi from './api/candles'; import swaggerUi from 'swagger-ui-express'; import YAML from 'yamljs'; -import './schedule/candleAnalysisSchedule'; +import './schedule'; const app: Application = express(); diff --git a/src/dao/analysis.ts b/src/dao/analysis.ts index e69de29..60442d4 100644 --- a/src/dao/analysis.ts +++ b/src/dao/analysis.ts @@ -0,0 +1,22 @@ +export interface Analysis { + symbol: string; + interval: string; + emaDirection: string; + macdDirection: string; + isMacdCrossUp: boolean; + isMacdCrossDown: boolean; + isMacdUpper: boolean; + isMacdLower: boolean; + isEmaCrossUp: boolean; + isEmaCrossDown: boolean; + isPinBar: boolean; + isHighVolatility: boolean; + isBuy: boolean; + isSell: boolean; + isTouch200: boolean; + isReverse200: boolean; + lowHight: number; + numberTouch200: number; + numberMacdCrossUp: number; + numberMacdCrossDown: number; +} \ No newline at end of file diff --git a/src/dao/order.ts b/src/dao/order.ts new file mode 100644 index 0000000..1f48e17 --- /dev/null +++ b/src/dao/order.ts @@ -0,0 +1,9 @@ +export interface Order { + symbol: string; + side: "buy" | "sell"; + entry: number; + volume: number; + leverage?: number; + stopLoss?: number; + takeProfit?: number; +} \ No newline at end of file diff --git a/src/dao/position.ts b/src/dao/position.ts new file mode 100644 index 0000000..7fcadc2 --- /dev/null +++ b/src/dao/position.ts @@ -0,0 +1,9 @@ +export interface Position { + symbol: string; + side: string; + entry: number; + leverage: number; + volume: number; + profit: number; + profitPercentage: number; +} \ No newline at end of file diff --git a/src/dao/subwave.ts b/src/dao/subwave.ts new file mode 100644 index 0000000..b14a4a5 --- /dev/null +++ b/src/dao/subwave.ts @@ -0,0 +1,10 @@ +export interface Subwave { + symbol: string; + interval: string; + subwave: string; + subwaveDirection: string; + subwaveType: string; + subwaveLength: number; + subwaveStart: number; + subwaveEnd: number; +} \ No newline at end of file diff --git a/src/dao/wave.ts b/src/dao/wave.ts new file mode 100644 index 0000000..c61c985 --- /dev/null +++ b/src/dao/wave.ts @@ -0,0 +1,9 @@ +export interface Wave { + symbol: string; + interval: string; + trend: 'Bullish' | 'Bearish'; + numberTouchEma: number; + numberMacdCrossUp: number; + numberMacdCrossDown: number; + lowOrHighPrice: number; +} \ No newline at end of file diff --git a/src/handlers/candleHandler.ts b/src/handlers/candleHandler.ts index 52735d5..51b675e 100644 --- a/src/handlers/candleHandler.ts +++ b/src/handlers/candleHandler.ts @@ -1,11 +1,23 @@ import { Request, Response } from 'express'; import { BybitService } from '../services/bybitService'; -import * as indicatorService from '../services/indicatorService'; +import { IndicatorService } from '../services/indicatorService'; +import { Candle } from '../dao/candles'; +import { KlineIntervalV3 } from 'bybit-api'; export const analyzeCandles = async (req: Request, res: Response) => { - const { symbol, interval } = req.params; + const { symbol, interval: intervalString } = req.params; + const interval = intervalString as KlineIntervalV3; const bybitService = new BybitService(process.env.BYBIT_API_KEY!, process.env.BYBIT_API_SECRET!); - const candles = await bybitService.getCandles({ symbol, interval: '5', category: 'linear', limit: 200 }); - const analysis = indicatorService.analyze(candles); + const candles = await bybitService.getCandles({ symbol, interval, category: 'linear', limit: 200 }); + const indicatorService = new IndicatorService(); + const analysis = indicatorService.analyze(candles, { + symbol, + interval, + trend: 'Bullish', + numberTouchEma: 0, + numberMacdCrossUp: 0, + numberMacdCrossDown: 0, + lowOrHighPrice: 0, + }); res.json(analysis); }; \ No newline at end of file diff --git a/src/helpers/candles.ts b/src/helpers/candles.ts index f6b1dbd..5ee9768 100644 --- a/src/helpers/candles.ts +++ b/src/helpers/candles.ts @@ -1,9 +1,4 @@ -interface Candle { - open: number; - close: number; - low: number; - high: number; -} +import { Candle } from "../dao/candles"; type PatternType = | "Doji" @@ -647,3 +642,28 @@ export function isHighVolatilityCandle(candles: Candle[]): boolean { // A candle is considered high volatility if either its range or its body size (or both) are significantly larger return isRangeHigh || isBodySizeHigh; } + +function upperShadow(candle: Candle): number { + return candle.high - Math.max(candle.open, candle.close); +} + +function lowerShadow(candle: Candle): number { + return Math.min(candle.open, candle.close) - candle.low; +} + +export function isPinBar(candle: Candle): {isPinBar: boolean, isBullish: boolean, isBearish: boolean} { + const bodySize = getBodySize(candle); + const totalRange = getTotalRange(candle); + const upperShadowSize = upperShadow(candle); + const lowerShadowSize = lowerShadow(candle); + + if (bodySize < totalRange * 0.3 && upperShadowSize > bodySize * 2) { + return {isPinBar: true, isBullish: true, isBearish: false}; + } + + if (bodySize < totalRange * 0.3 && lowerShadowSize > bodySize * 2) { + return {isPinBar: true, isBullish: false, isBearish: true}; + } + + return {isPinBar: false, isBullish: false, isBearish: false}; +} diff --git a/src/schedule/candleAnalysisSchedule.ts b/src/schedule/candleAnalysisSchedule.ts index 7f1a5b4..2f63326 100644 --- a/src/schedule/candleAnalysisSchedule.ts +++ b/src/schedule/candleAnalysisSchedule.ts @@ -1,25 +1,94 @@ import schedule from 'node-schedule'; -import * as indicatorService from '../services/indicatorService'; +import { IndicatorService } from '../services/indicatorService'; import { BybitService } from '../services/bybitService'; import { KlineIntervalV3 } from 'bybit-api'; import { sendLarkMessage } from '../services/messageService'; +import { Candle } from '../dao/candles'; +import { Order } from '../dao/order'; -// Hàm thực hiện phân tích nến -async function analyzeCandlesJob(symbol: string, interval: KlineIntervalV3) { - const bybitService = new BybitService(process.env.BYBIT_API_KEY!, process.env.BYBIT_API_SECRET!, false); - // TODO: Lấy client thật nếu cần - const candles = await bybitService.getCandles({ symbol, interval, category: 'linear', limit: 200 }); - const analysis = indicatorService.analyze(candles); - await sendLarkMessage('oc_f9b2e8f0309ecab0c94e3e134b0ddd29', JSON.stringify(analysis)); - // Có thể gửi kết quả qua Lark, lưu DB, ... +const indicatorService = new IndicatorService(); +const bybitService = new BybitService(process.env.BYBIT_API_KEY!, process.env.BYBIT_API_SECRET!, false); + +function sendMessage(message: string) { + sendLarkMessage('oc_f9b2e8f0309ecab0c94e3e134b0ddd29', message); } -// Lập lịch chạy vào 00:00 mỗi ngày -const rule = new schedule.RecurrenceRule(); -rule.minute = [4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59]; -rule.second = 59; +// Hàm thực hiện phân tích nến +export async function analyzeCandlesJob(symbol: string, interval: KlineIntervalV3, end?: number) { + // TODO: Lấy client thật nếu cần + const candles = await bybitService.getCandles({ symbol, interval, category: 'linear', limit: 500, end }); + const wave = await indicatorService.getWave(symbol, interval); + console.log(wave); + const analysis= indicatorService.analyze(candles, wave); + indicatorService.handleEvent(analysis, candles, { + onBuy: (order: Order, reason: string) => { + sendMessage(`Buy ${symbol} ${interval}M ${reason} + symbol: ${order.symbol} + side: ${order.side} + entry: ${order.entry} + stopLoss: ${order.stopLoss} + volume: ${order.volume} + reason: ${reason} + `); + console.log(`Buy ${symbol} ${interval}M ${reason} ${candles[0].time}`); + }, + onSell: (order: Order, reason: string) => { + sendMessage(`Sell ${symbol} ${interval}M ${reason} + symbol: ${order.symbol} + side: ${order.side} + entry: ${order.entry} + stopLoss: ${order.stopLoss} + volume: ${order.volume} + reason: ${reason} + `); + console.log(`Sell ${symbol} ${interval}M ${reason} ${candles[0].time}`); + }, + onEvent: (data: any, eventType: string) => { + sendMessage(`${eventType} ${symbol} ${interval}M ${data.close}`) + console.log(`${eventType} ${symbol} ${interval}M ${JSON.stringify(data)}`); + }, + }); + analysis.symbol = symbol; + analysis.interval = interval; + console.log(analysis); + await indicatorService.upsertWave({ + symbol, + interval, + trend: analysis.emaDirection as 'Bullish' | 'Bearish', + numberTouchEma: analysis.numberTouch200, + numberMacdCrossUp: analysis.numberMacdCrossUp, + numberMacdCrossDown: analysis.numberMacdCrossDown, + lowOrHighPrice: analysis.lowHight, + }); +} -schedule.scheduleJob(rule, () => { - // Có thể lặp qua nhiều symbol/interval nếu muốn - analyzeCandlesJob('BTCUSDT', '5'); -}); \ No newline at end of file +export function createCandleAnalysisSchedule(symbol: string, interval: KlineIntervalV3) { + const rule = new schedule.RecurrenceRule(); + rule.tz = 'Asia/Ho_Chi_Minh'; + switch (interval) { + case '5': + rule.minute = [4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59]; + break; + case '15': + rule.minute = [14, 29, 44, 59]; + break; + case '30': + rule.minute = [29, 59]; + break; + case '60': + rule.minute = [59]; + break; + case '240': + rule.minute = [59]; + rule.hour = [2, 6, 10, 14, 18, 22]; + break; + case 'D': + rule.minute = [59]; + rule.hour = [6]; + break; + } + rule.second = 59; + schedule.scheduleJob(rule, () => { + analyzeCandlesJob(symbol, interval); + }); +} \ No newline at end of file diff --git a/src/schedule/index.ts b/src/schedule/index.ts new file mode 100644 index 0000000..2a0934f --- /dev/null +++ b/src/schedule/index.ts @@ -0,0 +1,8 @@ +import { createCandleAnalysisSchedule } from "./candleAnalysisSchedule"; + +createCandleAnalysisSchedule("ETHUSDT", "15"); +createCandleAnalysisSchedule("BTCUSDT", "15"); +createCandleAnalysisSchedule("ETHUSDT", "60"); +createCandleAnalysisSchedule("BTCUSDT", "60"); +createCandleAnalysisSchedule("ETHUSDT", "240"); +createCandleAnalysisSchedule("BTCUSDT", "240"); \ No newline at end of file diff --git a/src/services/indicatorService.ts b/src/services/indicatorService.ts index 4e3b926..75bf5f9 100644 --- a/src/services/indicatorService.ts +++ b/src/services/indicatorService.ts @@ -1,11 +1,33 @@ import { EMA, MACD } from "technicalindicators"; import { Candle } from "../dao/candles"; -import { analyzeCandleSequence } from "../helpers/candles"; +import { analyzeCandleSequence, isHighVolatilityCandle, isPinBar } from "../helpers/candles"; +import { Analysis } from "../dao/analysis"; +import { KlineIntervalV3 } from "bybit-api"; +import { Order } from "../dao/order"; +import { supabase } from "./supabaseService"; +import { Wave } from "../dao/wave"; + +export interface EventHandler { + onBuy: (candle: Order, reason: string) => void; + onSell: (candle: Order, reason: string) => void; + onEvent: (data: any, eventType: string) => void; +} export class IndicatorService { constructor() {} - analyze(candles: Candle[]): { ema34: number; ema200: number; macd: any } { + analyze(candles: Candle[], wave: Wave): Analysis { + if (!wave) { + wave = { + symbol: "", + interval: "", + trend: "Bullish", + numberTouchEma: 0, + numberMacdCrossUp: 0, + numberMacdCrossDown: 0, + lowOrHighPrice: 0, + }; + } let close = candles.map((c) => c.close); const ema34 = EMA.calculate({ period: 34, @@ -27,28 +49,213 @@ export class IndicatorService { reversedInput: true, }); const candle = candles[0]; + + const analysis: Analysis = { + symbol: wave.symbol, + interval: wave.interval, + emaDirection: "", + macdDirection: "", + isMacdCrossUp: false, + isMacdCrossDown: false, + isEmaCrossUp: false, + isEmaCrossDown: false, + isPinBar: false, + isHighVolatility: false, + isBuy: false, + isSell: false, + isTouch200: false, + isReverse200: false, + lowHight: wave.lowOrHighPrice, + numberTouch200: wave.numberTouchEma, + numberMacdCrossUp: wave.numberMacdCrossUp, + numberMacdCrossDown: wave.numberMacdCrossDown, + isMacdUpper: false, + isMacdLower: false, + }; + + if (ema34[0] > ema200[0]) { + if (wave.trend === "Bearish") { + analysis.numberTouch200 = 0; + } + analysis.emaDirection = "Bullish"; + } else { + if (wave.trend === "Bullish") { + analysis.numberTouch200 = 0; + } + analysis.emaDirection = "Bearish"; + } + + if (macd[0].MACD! > macd[0].signal!) { + if (wave.trend === "Bearish") { + analysis.numberMacdCrossUp = 0; + analysis.numberMacdCrossDown = 0; + } + analysis.macdDirection = "Bullish"; + } else { + if (wave.trend === "Bullish") { + analysis.numberMacdCrossDown = 0; + analysis.numberMacdCrossUp = 0; + } + analysis.macdDirection = "Bearish"; + } + + if (analysis.emaDirection === "Bullish") { + if (analysis.lowHight < candle.high) { + analysis.lowHight = candle.high; + } + } else { + if (analysis.lowHight > candle.low) { + analysis.lowHight = candle.low; + } + } + + if (macd[0].MACD! > 0) { + analysis.isMacdUpper = true; + } else { + analysis.isMacdLower = true; + } + + if (macd[0].MACD! > macd[0].signal! && macd[1].MACD! < macd[1].signal!) { + analysis.isMacdCrossUp = true; + analysis.numberMacdCrossUp++; + } else if (macd[0].MACD! < macd[0].signal! && macd[1].MACD! > macd[1].signal!) { + analysis.isMacdCrossDown = true; + analysis.numberMacdCrossDown++; + } + + if (ema34[0] > ema200[0] && ema34[1] < ema200[1]) { + analysis.isEmaCrossUp = true; + } else if (ema34[0] < ema200[0] && ema34[1] > ema200[1]) { + analysis.isEmaCrossDown = true; + } + + if (isPinBar(candle).isPinBar) { + analysis.isPinBar = true; + } + + if (isHighVolatilityCandle(candles.slice(0, 50).reverse())) { + analysis.isHighVolatility = true; + } + if ( candle.low < ema200[0] && candle.high > ema200[0] && - candle.close > ema200[0] + candle.close > ema200[0] && + candle.open > ema200[0] && + analysis.emaDirection === "Bullish" ) { - console.log("Buy"); + analysis.numberTouch200++; + analysis.isTouch200 = true; } if ( candle.high > ema200[0] && candle.low < ema200[0] && - candle.close < ema200[0] + candle.close < ema200[0] && + candle.open < ema200[0] && + analysis.emaDirection === "Bearish" ) { - console.log("Sell"); + analysis.numberTouch200++; + analysis.isTouch200 = true; } - const candleAnalysis = analyzeCandleSequence([ - candles[2], - candles[1], - candles[0], - ]); + if (candle.open < ema200[0] && candle.close > ema200[0] && analysis.emaDirection === "Bullish") { + const candlesCheck = [candles[3], candles[2], candles[1], candles[0]]; + const ema200Check = [ema200[3], ema200[2], ema200[1], ema200[0]]; + const candleCheck = candlesCheck.find( + (c, i) => c.close < ema200Check[i] && c.open > ema200Check[i] + ); + if (candleCheck) { + analysis.numberTouch200++; + analysis.isReverse200 = true; + } + } - return { ema34: ema34[0], ema200: ema200[0], macd: macd[0] }; + if (candle.open > ema200[0] && candle.close < ema200[0] && analysis.emaDirection === "Bearish") { + const candlesCheck = [candles[3], candles[2], candles[1], candles[0]]; + const ema200Check = [ema200[3], ema200[2], ema200[1], ema200[0]]; + const candleCheck = candlesCheck.find( + (c, i) => c.close > ema200Check[i] && c.open < ema200Check[i] + ); + if (candleCheck) { + analysis.numberTouch200++; + analysis.isReverse200 = true; + } + } + + console.log(analysis); + + return analysis; + } + + makeOrder(analysis: Analysis, candles: Candle[], side: "buy" | "sell"): Order { + const last10Candles = candles.slice(0, 12); + const lowestPrice = last10Candles.reduce((min, c) => Math.min(min, c.low), Number.MAX_SAFE_INTEGER); + const highestPrice = last10Candles.reduce((max, c) => Math.max(max, c.high), Number.MIN_SAFE_INTEGER); + const order: Order = { + symbol: analysis.symbol, + side, + entry: candles[0].close, + stopLoss: side === "buy" ? lowestPrice : highestPrice, + volume: 1, + }; + return order; + } + + handleEvent(analysis: Analysis, candles: Candle[], eventHandler: EventHandler) { + if (analysis.isTouch200 && analysis.emaDirection === "Bullish") { + const order = this.makeOrder(analysis, candles, "buy"); + eventHandler.onBuy(order, "Follow trend EMA Touch 200"); + } + if (analysis.isTouch200 && analysis.emaDirection === "Bearish") { + const order = this.makeOrder(analysis, candles, "sell"); + eventHandler.onSell(order, "Follow trend EMA Touch 200"); + } + if (analysis.isMacdCrossUp && analysis.isMacdUpper) { + const order = this.makeOrder(analysis, candles, "buy"); + eventHandler.onBuy(order, "Follow trend MACD Cross Up"); + } + if (analysis.isMacdCrossDown && analysis.isMacdLower) { + const order = this.makeOrder(analysis, candles, "sell"); + eventHandler.onSell(order, "Follow trend MACD Cross Down"); + } + + if (analysis.isMacdCrossUp && analysis.isMacdLower && analysis.numberMacdCrossUp >= 2) { + const order = this.makeOrder(analysis, candles, "buy"); + eventHandler.onBuy(order, "Counter trend rủi ro cao MACD Cross Up"); + } + if (analysis.isMacdCrossDown && analysis.isMacdUpper && analysis.numberMacdCrossDown >= 2) { + const order = this.makeOrder(analysis, candles, "sell"); + eventHandler.onSell(order, "Counter trend rủi ro cao MACD Cross Down"); + } + } + + /** + * Lấy bản ghi wave theo symbol và interval + */ + async getWave(symbol: string, interval: string) { + const { data, error } = await supabase + .from('waves') + .select('*') + .eq('symbol', symbol) + .eq('interval', interval) + .single(); + if (error) return null; + return data; + } + + /** + * Update hoặc Insert wave theo symbol và interval + */ + async upsertWave(wave: Wave) { + const { data, error } = await supabase + .from('waves') + .upsert([ + wave + ], { onConflict: 'symbol,interval' }); + if (error) { + console.error(error); + } + return data; } } diff --git a/src/services/supabaseService.ts b/src/services/supabaseService.ts index 106bfbf..2c43d46 100644 --- a/src/services/supabaseService.ts +++ b/src/services/supabaseService.ts @@ -1,6 +1,6 @@ import { createClient, SupabaseClient } from '@supabase/supabase-js'; -const supabase: SupabaseClient = createClient( +export const supabase: SupabaseClient = createClient( process.env.SUPABASE_URL || '', process.env.SUPABASE_KEY || '' ); diff --git a/test.ts b/test.ts index 7524268..18cf9ab 100644 --- a/test.ts +++ b/test.ts @@ -4,23 +4,21 @@ import * as indicatorService from "./src/services/indicatorService"; import { analyzeCandleSequence, isHighVolatilityCandle, + isPinBar, } from "./src/helpers/candles"; +import { analyzeCandlesJob } from "./src/schedule/candleAnalysisSchedule"; const bybitService = new BybitService( process.env.BYBIT_API_KEY!, process.env.BYBIT_API_SECRET!, false ); + +function toTimestamp(strTime: string): number { + return new Date(strTime).getTime(); +} + (async () => { - const candles = await bybitService.getCandles({ - symbol: "BTCUSDT", - interval: "240", - category: "linear", - limit: 500, - }); - console.log(candles[0], candles[1]); - const cA = analyzeCandleSequence([candles[2], candles[1], candles[0]]); - const isH = isHighVolatilityCandle(candles.reverse()); - console.log(cA); - console.log("isHighVolatilityCandle", isH); + // await analyzeCandlesJob("ETHUSDT", "15", toTimestamp("2025-07-08 23:59:59")); + await analyzeCandlesJob("ETHUSDT", "15"); })(); diff --git a/tsconfig.json b/tsconfig.json index 904d43f..680591a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,113 +1,18 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "libReplacement": true, /* Enable lib replacement. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ - // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + "target": "es2016", + "module": "commonjs", + "rootDir": "src", + "outDir": "dist", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "allowJs": true, + "declaration": true, + "baseUrl": "./" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "ecosystem.config.js", "test.ts"] }