pinets 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/pinets.min.browser.es.js +23 -40
  2. package/dist/pinets.min.browser.es.js.map +1 -1
  3. package/dist/pinets.min.browser.js +48 -65
  4. package/dist/pinets.min.browser.js.map +1 -1
  5. package/dist/pinets.min.cjs +23 -40
  6. package/dist/pinets.min.cjs.map +1 -1
  7. package/dist/pinets.min.es.js +45 -62
  8. package/dist/pinets.min.es.js.map +1 -1
  9. package/dist/types/Context.class.d.ts +24 -0
  10. package/dist/types/PineTS.class.d.ts +18 -1
  11. package/dist/types/errors/PineRuntimeError.d.ts +27 -0
  12. package/dist/types/index.d.ts +10 -1
  13. package/dist/types/marketData/Alpaca/AlpacaProvider.class.d.ts +115 -0
  14. package/dist/types/marketData/BaseProvider.d.ts +92 -0
  15. package/dist/types/marketData/Binance/BinanceProvider.class.d.ts +10 -12
  16. package/dist/types/marketData/FMP/FMPProvider.class.d.ts +69 -0
  17. package/dist/types/marketData/IProvider.d.ts +20 -7
  18. package/dist/types/marketData/Mock/MockProvider.class.d.ts +12 -29
  19. package/dist/types/marketData/Provider.class.d.ts +4 -1
  20. package/dist/types/marketData/aggregation.d.ts +38 -0
  21. package/dist/types/marketData/types.d.ts +106 -0
  22. package/dist/types/namespaces/Core.d.ts +40 -2
  23. package/dist/types/transpiler/analysis/ScopeManager.d.ts +4 -0
  24. package/dist/types/transpiler/pineToJS/codegen.d.ts +34 -1
  25. package/dist/types/transpiler/pineToJS/parser.d.ts +1 -0
  26. package/dist/types/transpiler/settings.d.ts +1 -0
  27. package/dist/types/transpiler/transformers/StatementTransformer.d.ts +10 -0
  28. package/package.json +4 -4
  29. package/dist/types/NaProxy.d.ts +0 -19
  30. package/dist/types/TimeSeries.class.d.ts +0 -49
  31. package/dist/types/TimeSeries.d.ts +0 -15
  32. package/dist/types/namespaces/Input.d.ts +0 -24
  33. package/dist/types/namespaces/PineArray.d.ts +0 -62
  34. package/dist/types/namespaces/PineColor.d.ts +0 -0
  35. package/dist/types/namespaces/PineMath.d.ts +0 -28
  36. package/dist/types/namespaces/PineRequest.d.ts +0 -8
  37. package/dist/types/namespaces/Plot.helper.d.ts +0 -16
  38. package/dist/types/namespaces/TechnicalAnalysis.d.ts +0 -30
  39. package/dist/types/namespaces/request/types/barmerge.type.d.ts +0 -7
  40. package/dist/types/namespaces/strategy/StrategySimulator.d.ts +0 -84
  41. package/dist/types/namespaces/strategy/closedtrades/index.d.ts +0 -18
  42. package/dist/types/namespaces/strategy/methods/any.d.ts +0 -5
  43. package/dist/types/namespaces/strategy/methods/cancel.d.ts +0 -1
  44. package/dist/types/namespaces/strategy/methods/cancel_all.d.ts +0 -1
  45. package/dist/types/namespaces/strategy/methods/cash.d.ts +0 -5
  46. package/dist/types/namespaces/strategy/methods/close.d.ts +0 -1
  47. package/dist/types/namespaces/strategy/methods/close_all.d.ts +0 -1
  48. package/dist/types/namespaces/strategy/methods/closedtrades.d.ts +0 -4
  49. package/dist/types/namespaces/strategy/methods/entry.d.ts +0 -3
  50. package/dist/types/namespaces/strategy/methods/equity.d.ts +0 -4
  51. package/dist/types/namespaces/strategy/methods/exit.d.ts +0 -3
  52. package/dist/types/namespaces/strategy/methods/fixed.d.ts +0 -5
  53. package/dist/types/namespaces/strategy/methods/long.d.ts +0 -4
  54. package/dist/types/namespaces/strategy/methods/netprofit.d.ts +0 -4
  55. package/dist/types/namespaces/strategy/methods/opentrades.d.ts +0 -4
  56. package/dist/types/namespaces/strategy/methods/order.d.ts +0 -6
  57. package/dist/types/namespaces/strategy/methods/param.d.ts +0 -5
  58. package/dist/types/namespaces/strategy/methods/percent_of_equity.d.ts +0 -5
  59. package/dist/types/namespaces/strategy/methods/position_avg_price.d.ts +0 -5
  60. package/dist/types/namespaces/strategy/methods/position_entry.d.ts +0 -5
  61. package/dist/types/namespaces/strategy/methods/position_entry_name.d.ts +0 -5
  62. package/dist/types/namespaces/strategy/methods/position_size.d.ts +0 -5
  63. package/dist/types/namespaces/strategy/methods/short.d.ts +0 -4
  64. package/dist/types/namespaces/strategy/models/Order.d.ts +0 -31
  65. package/dist/types/namespaces/strategy/models/Position.d.ts +0 -16
  66. package/dist/types/namespaces/strategy/models/Trade.d.ts +0 -45
  67. package/dist/types/namespaces/strategy/opentrades/index.d.ts +0 -10
  68. package/dist/types/namespaces/strategy/risk/index.d.ts +0 -11
  69. package/dist/types/namespaces/strategy/strategy.index.d.ts +0 -53
  70. package/dist/types/namespaces/strategy/types.d.ts +0 -92
  71. package/dist/types/namespaces/strategy/utils.d.ts +0 -28
  72. package/dist/types/namespaces/ta/getters/obv.d.ts +0 -12
  73. package/dist/types/namespaces/ta/getters/tr.d.ts +0 -1
  74. package/dist/types/transpiler/ScopeManager.class.d.ts +0 -36
@@ -14,7 +14,31 @@ export declare class Context {
14
14
  isSecondaryContext: boolean;
15
15
  chartTimezone: string | null;
16
16
  dataVersion: number;
17
+ __maxLoops: number;
17
18
  NA: any;
19
+ /** Runtime warnings (OOB access, etc.) — non-blocking, script continues. */
20
+ warnings: {
21
+ message: string;
22
+ method?: string;
23
+ bar: number;
24
+ }[];
25
+ /** Alert events emitted by alert() and alertcondition() calls. */
26
+ alerts: {
27
+ type: string;
28
+ id: string;
29
+ message: string;
30
+ title?: string;
31
+ freq?: string;
32
+ bar_index: number;
33
+ time: number;
34
+ }[];
35
+ /** Alert mode: 'realtime' = only fire on live bars (TV behavior), 'all' = fire on every bar (backtest). */
36
+ _alertMode: 'realtime' | 'all';
37
+ /** Monotonically increasing counter, incremented each time a bar starts executing.
38
+ * Used by alertcondition/AlertHelper to detect re-execution of the same bar. */
39
+ _execTick: number;
40
+ /** Emit a runtime warning. The script continues execution (returns na/no-op). */
41
+ warn(message: string, method?: string): void;
18
42
  lang: any;
19
43
  length: number;
20
44
  /** References to drawing helpers for streaming rollback */
@@ -40,6 +40,23 @@ export declare class PineTS {
40
40
  * @param timezone IANA timezone name (e.g. 'America/New_York'), UTC offset ('UTC+5'), or 'UTC'
41
41
  */
42
42
  setTimezone(timezone: string): void;
43
+ private _maxLoops;
44
+ /**
45
+ * Set the maximum number of iterations allowed per loop.
46
+ * Mirrors TradingView's internal loop protection. If a for/while loop
47
+ * exceeds this limit, a runtime error is thrown.
48
+ * @param maxLoops Maximum iterations per loop (default: 500000)
49
+ */
50
+ setMaxLoops(maxLoops: number): void;
51
+ private _alertMode;
52
+ /**
53
+ * Set alert mode.
54
+ * - 'realtime' (default): alerts only fire on the last (realtime) bar,
55
+ * matching TradingView behavior.
56
+ * - 'all': alerts fire on every bar, useful for backtesting alert strategies.
57
+ * @param mode Alert firing mode
58
+ */
59
+ setAlertMode(mode: 'realtime' | 'all'): void;
43
60
  constructor(source: IProvider | any[], tickerId?: string, timeframe?: string, limit?: number, sDate?: number, eDate?: number);
44
61
  setDebugSettings({ ln, debug }: {
45
62
  ln: boolean;
@@ -74,7 +91,7 @@ export declare class PineTS {
74
91
  live?: boolean;
75
92
  interval?: number;
76
93
  }): {
77
- on: (event: 'data' | 'error', callback: Function) => void;
94
+ on: (event: 'data' | 'error' | 'warning' | 'alert', callback: Function) => void;
78
95
  stop: () => void;
79
96
  };
80
97
  /**
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Runtime error thrown by PineTS when a Pine Script runtime violation occurs.
3
+ * Mirrors TradingView behavior where operations like out-of-bounds array/matrix
4
+ * access or infinite loops halt the script with a runtime error.
5
+ *
6
+ * Consumers can catch this specific error type to distinguish Pine runtime
7
+ * errors from general JavaScript errors:
8
+ *
9
+ * ```typescript
10
+ * try {
11
+ * const result = await pineTS.run(code);
12
+ * } catch (err) {
13
+ * if (err instanceof PineRuntimeError) {
14
+ * console.log('Pine runtime error:', err.message);
15
+ * console.log('Method:', err.method); // e.g. 'array.get'
16
+ * }
17
+ * }
18
+ * ```
19
+ */
20
+ export declare class PineRuntimeError extends Error {
21
+ /**
22
+ * The Pine Script method that caused the error (e.g. 'array.get', 'matrix.set').
23
+ * May be undefined for non-method errors (e.g. loop guard).
24
+ */
25
+ method?: string;
26
+ constructor(message: string, method?: string);
27
+ }
@@ -2,4 +2,13 @@ import PineTS from './PineTS.class';
2
2
  import { Context } from './Context.class';
3
3
  import { Provider } from './marketData/Provider.class';
4
4
  import { Indicator } from './Indicator';
5
- export { PineTS, Context, Provider, Indicator };
5
+ import { PineRuntimeError } from './errors/PineRuntimeError';
6
+ export { BaseProvider } from './marketData/BaseProvider';
7
+ export { BinanceProvider } from './marketData/Binance/BinanceProvider.class';
8
+ export { FMPProvider } from './marketData/FMP/FMPProvider.class';
9
+ export { AlpacaProvider } from './marketData/Alpaca/AlpacaProvider.class';
10
+ export type { IProvider, ISymbolInfo, BaseProviderConfig, ApiKeyProviderConfig } from './marketData/IProvider';
11
+ export type { Kline, PeriodType } from './marketData/types';
12
+ export { computeNextPeriodStart, localTimeToUTC, computeSessionClose, TIMEFRAME_SECONDS, TIMEFRAME_PERIOD_INFO } from './marketData/types';
13
+ export { aggregateCandles, selectSubTimeframe, getAggregationRatio } from './marketData/aggregation';
14
+ export { PineTS, Context, Provider, Indicator, PineRuntimeError };
@@ -0,0 +1,115 @@
1
+ import { ISymbolInfo, ApiKeyProviderConfig } from '@pinets/marketData/IProvider';
2
+ import { BaseProvider } from '@pinets/marketData/BaseProvider';
3
+ import { Kline } from '@pinets/marketData/types';
4
+ /**
5
+ * Configuration for AlpacaProvider.
6
+ *
7
+ * @property apiKey - Alpaca API Key ID
8
+ * @property apiSecret - Alpaca API Secret Key
9
+ * @property paper - Use paper trading endpoint for asset info (default: true)
10
+ * @property feed - Market data feed: 'sip' (paid, full market) or 'iex' (free tier). Default: 'sip'
11
+ * @property dataUrl - Override the market data base URL
12
+ * @property tradingUrl - Override the trading/asset API base URL
13
+ */
14
+ export interface AlpacaProviderConfig extends ApiKeyProviderConfig {
15
+ apiSecret: string;
16
+ paper?: boolean;
17
+ feed?: 'sip' | 'iex';
18
+ dataUrl?: string;
19
+ tradingUrl?: string;
20
+ }
21
+ /**
22
+ * Alpaca Markets data provider.
23
+ *
24
+ * Supports US stocks and crypto via Alpaca's Market Data API v2.
25
+ * All timeframes (1Min through 1Month) are natively supported.
26
+ *
27
+ * ## Usage
28
+ *
29
+ * ### Direct instantiation:
30
+ * ```typescript
31
+ * const alpaca = new AlpacaProvider({
32
+ * apiKey: 'PK...',
33
+ * apiSecret: '...',
34
+ * });
35
+ * const pineTS = new PineTS(alpaca, 'AAPL', 'D', null, sDate, eDate);
36
+ * ```
37
+ *
38
+ * ### Via Provider registry:
39
+ * ```typescript
40
+ * Provider.Alpaca.configure({ apiKey: 'PK...', apiSecret: '...' });
41
+ * const pineTS = new PineTS(Provider.Alpaca, 'AAPL', 'D', null, sDate, eDate);
42
+ * ```
43
+ *
44
+ * ## API Keys
45
+ * Get free API keys at https://alpaca.markets/
46
+ * Free tier provides IEX data; paid plan adds SIP (full market) data.
47
+ *
48
+ * ## Symbol Format
49
+ * - Stocks: `AAPL`, `MSFT`, `SPY`
50
+ * - Crypto: `BTC/USD`, `ETH/USD` (slash notation)
51
+ */
52
+ export declare class AlpacaProvider extends BaseProvider<AlpacaProviderConfig> {
53
+ private _apiKey;
54
+ private _apiSecret;
55
+ private _dataUrl;
56
+ private _tradingUrl;
57
+ private _feed;
58
+ private _assetCache;
59
+ /** Calendar cache: date string "YYYY-MM-DD" → { open, close } times. */
60
+ private _calendarCache;
61
+ constructor(config?: AlpacaProviderConfig);
62
+ configure(config: AlpacaProviderConfig): void;
63
+ private _headers;
64
+ protected getSupportedTimeframes(): Set<string>;
65
+ protected _getMarketDataNative(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
66
+ /**
67
+ * Fetch all bars with automatic pagination.
68
+ */
69
+ private _fetchAllBars;
70
+ /**
71
+ * Build the bars URL for stocks or crypto.
72
+ */
73
+ private _buildBarsUrl;
74
+ getSymbolInfo(tickerId: string): Promise<ISymbolInfo>;
75
+ /**
76
+ * Convert bars for crypto (24/7 — no session boundaries).
77
+ * closeTime = next bar's openTime, or openTime + period for last bar.
78
+ */
79
+ private _convertBarsCrypto;
80
+ /**
81
+ * Convert bars for stocks using the Alpaca trading calendar.
82
+ * closeTime = exact session close from the calendar (handles early closes, DST).
83
+ */
84
+ private _convertBarsStock;
85
+ /** Build a Kline from an AlpacaBar + computed times. */
86
+ private _toKline;
87
+ /**
88
+ * Find the last trading day of the week containing `barDate` and return
89
+ * its session close time in UTC ms.
90
+ */
91
+ private _weeklyCloseFromCalendar;
92
+ /**
93
+ * Find the last trading day of the month containing `barDate` and return
94
+ * its session close time in UTC ms.
95
+ */
96
+ private _monthlyCloseFromCalendar;
97
+ /**
98
+ * Ensure the calendar cache covers the given date range.
99
+ * Fetches from Alpaca's `GET /v2/calendar` endpoint, which returns
100
+ * per-day trading hours including early closes (data from 1970-2029).
101
+ */
102
+ private _ensureCalendar;
103
+ private _fetchAsset;
104
+ /**
105
+ * Parse an Alpaca timeframe string (e.g., '1Min', '4Hour', '1Month')
106
+ * into a PeriodType and multiplier for calendar-aware date math.
107
+ */
108
+ private _parseAlpacaTimeframe;
109
+ /** Resolve PineTS timeframe to Alpaca timeframe string. */
110
+ private _resolveTimeframe;
111
+ /** Heuristic: crypto tickers contain '/'. */
112
+ private _isCrypto;
113
+ /** Add N days to a "YYYY-MM-DD" date string. */
114
+ private _addDaysToDate;
115
+ }
@@ -0,0 +1,92 @@
1
+ import { IProvider, ISymbolInfo, BaseProviderConfig } from './IProvider';
2
+ import { Kline } from './types';
3
+ /**
4
+ * Abstract base class for market data providers.
5
+ *
6
+ * Provides shared logic: closeTime normalization, fail-early API key
7
+ * validation, and **automatic candle aggregation** for unsupported
8
+ * timeframes.
9
+ *
10
+ * ## Aggregation
11
+ *
12
+ * When a provider doesn't natively support a timeframe, `getMarketData()`
13
+ * automatically:
14
+ * 1. Selects the best sub-timeframe the provider supports
15
+ * 2. Fetches sub-candles via `_getMarketDataNative()`
16
+ * 3. Aggregates them into the requested timeframe
17
+ *
18
+ * Providers declare native support via `getSupportedTimeframes()` and
19
+ * implement `_getMarketDataNative()` for the actual API call.
20
+ *
21
+ * ## Usage
22
+ *
23
+ * ```typescript
24
+ * class MyProvider extends BaseProvider<MyConfig> {
25
+ * protected getSupportedTimeframes() {
26
+ * return new Set(['1', '5', '15', '60', 'D']);
27
+ * }
28
+ * protected async _getMarketDataNative(...) { ... }
29
+ * }
30
+ * ```
31
+ */
32
+ export declare abstract class BaseProvider<TConfig extends BaseProviderConfig = BaseProviderConfig> implements IProvider {
33
+ private _configured;
34
+ private _requiresApiKey;
35
+ private _providerName;
36
+ private _aggregationSubTimeframe;
37
+ constructor(options: {
38
+ requiresApiKey: boolean;
39
+ providerName: string;
40
+ });
41
+ /**
42
+ * Fail-early check — call at the top of `_getMarketDataNative()` / `getSymbolInfo()`
43
+ * in providers that require an API key.
44
+ */
45
+ protected ensureConfigured(): void;
46
+ /**
47
+ * Base configure — marks the provider as configured.
48
+ * Subclasses override to store their specific config, and must call `super.configure(config)`.
49
+ */
50
+ configure(config: TConfig): void;
51
+ /** Whether this provider has been configured (always true for keyless providers). */
52
+ get isConfigured(): boolean;
53
+ /**
54
+ * Shared closeTime normalization utility.
55
+ * Delegates to the standalone `normalizeCloseTime()` from `types.ts`.
56
+ */
57
+ protected normalizeCloseTime(data: Kline[]): void;
58
+ /**
59
+ * Override the sub-timeframe used for aggregation.
60
+ * When set, this timeframe is used instead of auto-selecting the best divisor.
61
+ * Set to `null` to re-enable automatic selection.
62
+ */
63
+ setAggregationSubTimeframe(subTimeframe: string | null): void;
64
+ /**
65
+ * Return the set of timeframes this provider supports natively.
66
+ *
67
+ * Override in subclasses. Default: all canonical timeframes (no aggregation).
68
+ * Use canonical keys: '1','3','5','15','30','45','60','120','180','240','D','W','M'
69
+ * and optionally second-based: '1S','5S','10S','15S','30S'.
70
+ */
71
+ protected getSupportedTimeframes(): Set<string>;
72
+ /**
73
+ * Fetch market data — delegates to native fetch or aggregates from sub-candles.
74
+ *
75
+ * 1. If the timeframe is natively supported, delegates to `_getMarketDataNative()`.
76
+ * 2. Otherwise, selects the best sub-timeframe, fetches sub-candles, and aggregates.
77
+ */
78
+ getMarketData(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
79
+ /**
80
+ * Fetch market data natively from the provider's API.
81
+ *
82
+ * Subclasses MUST implement this. It is called by the BaseProvider
83
+ * orchestrator either for the requested timeframe (if natively supported)
84
+ * or for a sub-candle timeframe (if aggregation is needed).
85
+ */
86
+ protected abstract _getMarketDataNative(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
87
+ abstract getSymbolInfo(tickerId: string): Promise<ISymbolInfo>;
88
+ /**
89
+ * Compute how many sub-candles to fetch to produce `limit` aggregated candles.
90
+ */
91
+ private _computeSubLimit;
92
+ }
@@ -1,15 +1,13 @@
1
- import { IProvider, ISymbolInfo } from '@pinets/marketData/IProvider';
2
- export declare class BinanceProvider implements IProvider {
1
+ import { ISymbolInfo } from '@pinets/marketData/IProvider';
2
+ import { BaseProvider } from '@pinets/marketData/BaseProvider';
3
+ import { Kline } from '@pinets/marketData/types';
4
+ /** Config for BinanceProvider (no API key needed). */
5
+ export interface BinanceProviderConfig {
6
+ }
7
+ export declare class BinanceProvider extends BaseProvider<BinanceProviderConfig> {
3
8
  private cacheManager;
4
9
  private activeApiUrl;
5
10
  constructor();
6
- /**
7
- * Normalize closeTime to TradingView convention: closeTime = next bar's openTime.
8
- * Binance raw API returns closeTime as (nextBarOpen - 1ms). For all bars except the
9
- * last, we use the next bar's actual openTime (exact). For the last bar, we add 1ms
10
- * to the raw value.
11
- */
12
- private _normalizeCloseTime;
13
11
  /**
14
12
  * Resolves the working Binance API endpoint.
15
13
  * Tries default first, then falls back to US endpoint.
@@ -21,13 +19,13 @@ export declare class BinanceProvider implements IProvider {
21
19
  * Used internally by pagination methods that assemble chunks before normalizing.
22
20
  */
23
21
  private _fetchRawChunk;
24
- getMarketDataInterval(tickerId: string, timeframe: string, sDate: number, eDate: number): Promise<any>;
22
+ getMarketDataInterval(tickerId: string, timeframe: string, sDate: number, eDate: number): Promise<Kline[]>;
25
23
  private getMarketDataBackwards;
26
- getMarketData(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<any>;
24
+ protected getSupportedTimeframes(): Set<string>;
25
+ protected _getMarketDataNative(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
27
26
  /**
28
27
  * Determines if pagination is needed based on the parameters
29
28
  */
30
29
  private shouldPaginate;
31
30
  getSymbolInfo(tickerId: string): Promise<ISymbolInfo>;
32
- configure(config: any): void;
33
31
  }
@@ -0,0 +1,69 @@
1
+ import { ISymbolInfo, ApiKeyProviderConfig } from '@pinets/marketData/IProvider';
2
+ import { BaseProvider } from '@pinets/marketData/BaseProvider';
3
+ import { Kline } from '@pinets/marketData/types';
4
+ /** Configuration for FMPProvider — requires an API key. */
5
+ export interface FMPProviderConfig extends ApiKeyProviderConfig {
6
+ /** Optional: override the base URL (e.g. for proxy or self-hosted). */
7
+ baseUrl?: string;
8
+ }
9
+ /**
10
+ * Financial Modeling Prep (FMP) market data provider.
11
+ *
12
+ * Supports stocks, ETFs, crypto, and forex via FMP's stable API.
13
+ *
14
+ * ## Usage
15
+ *
16
+ * ### Direct instantiation:
17
+ * ```typescript
18
+ * const fmp = new FMPProvider({ apiKey: 'your-key' });
19
+ * const pineTS = new PineTS(fmp, 'AAPL', 'D', null, sDate, eDate);
20
+ * ```
21
+ *
22
+ * ### Via Provider registry:
23
+ * ```typescript
24
+ * Provider.FMP.configure({ apiKey: 'your-key' });
25
+ * const pineTS = new PineTS(Provider.FMP, 'AAPL', 'D', null, sDate, eDate);
26
+ * ```
27
+ *
28
+ * ## API Key
29
+ * Get a free API key (250 req/day) at https://financialmodelingprep.com/
30
+ * Intraday data (1min, 5min, 15min, 30min, 1h, 4h) requires a paid plan.
31
+ *
32
+ * ## Symbol Format
33
+ * Use standard ticker symbols: `AAPL`, `MSFT`, `SPY`, `BTCUSD`, `EURUSD`
34
+ */
35
+ export declare class FMPProvider extends BaseProvider<FMPProviderConfig> {
36
+ private _apiKey;
37
+ private _baseUrl;
38
+ private _profileCache;
39
+ constructor(config?: FMPProviderConfig);
40
+ configure(config: FMPProviderConfig): void;
41
+ protected getSupportedTimeframes(): Set<string>;
42
+ protected _getMarketDataNative(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
43
+ /**
44
+ * Fetch daily EOD data from FMP and convert to Kline format.
45
+ */
46
+ private _fetchDailyData;
47
+ /**
48
+ * Fetch intraday chart data from FMP and convert to Kline format.
49
+ * Note: Requires a paid FMP plan.
50
+ */
51
+ private _fetchIntradayData;
52
+ getSymbolInfo(tickerId: string): Promise<ISymbolInfo>;
53
+ private _fetchProfile;
54
+ /**
55
+ * Resolve session string and timezone for a ticker by fetching its profile.
56
+ * Falls back to NYSE defaults if profile is unavailable.
57
+ */
58
+ private _resolveSessionInfo;
59
+ /** Convert ms timestamp to FMP date string "YYYY-MM-DD". */
60
+ private _msToDateStr;
61
+ /** Convert FMP date string "YYYY-MM-DD" to ms timestamp (UTC midnight). */
62
+ private _dateStrToMs;
63
+ /** Convert FMP datetime string "YYYY-MM-DD HH:MM:SS" to ms timestamp. */
64
+ private _dateTimeStrToMs;
65
+ /** Heuristic: crypto tickers end with USD/USDT/BTC/ETH. */
66
+ private _isCrypto;
67
+ /** Heuristic: forex pairs are 6 chars, two 3-letter currency codes. */
68
+ private _isForex;
69
+ }
@@ -1,3 +1,11 @@
1
+ import type { Kline } from './types';
2
+ /** Base config — all providers extend this (may be empty for keyless providers). */
3
+ export interface BaseProviderConfig {
4
+ }
5
+ /** Config for providers that require an API key (FMP, Alpaca, etc.). */
6
+ export interface ApiKeyProviderConfig extends BaseProviderConfig {
7
+ apiKey: string;
8
+ }
1
9
  export type ISymbolInfo = {
2
10
  current_contract: string;
3
11
  description: string;
@@ -44,16 +52,21 @@ export type ISymbolInfo = {
44
52
  * Market data provider interface.
45
53
  *
46
54
  * ## closeTime convention
47
- * Providers MUST return `closeTime` following the TradingView convention:
48
- * `closeTime` = the timestamp of the **start of the next bar** (not the last
49
- * millisecond of the current bar). For example, a weekly bar opening on
50
- * Monday 2019-01-07T00:00Z should have `closeTime = 2019-01-14T00:00Z`.
55
+ * Providers MUST return `closeTime` as the **session close time** for the bar,
56
+ * mirroring TradingView's `time_close` built-in variable.
57
+ *
58
+ * - **Stocks / regulated markets**: `closeTime` = the session close time on
59
+ * the bar's trading day (e.g., 16:00 ET for NYSE daily bars, 13:00 ET for
60
+ * early-close days). For weekly/monthly bars, use the session close of the
61
+ * last trading day in the period.
62
+ * - **24/7 markets (crypto)**: `closeTime` = the start of the next bar
63
+ * (equivalent to `openTime + barDuration`), since there are no session gaps.
51
64
  *
52
- * If a provider's raw data uses a different convention (e.g., Binance returns
53
- * `nextBarOpen - 1ms`), the provider must normalize before returning.
65
+ * Use `computeSessionClose()` from `types.ts` for session-aware computation,
66
+ * or the Alpaca Calendar API for exact per-day close times including early closes.
54
67
  */
55
68
  export interface IProvider {
56
- getMarketData(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<any>;
69
+ getMarketData(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
57
70
  getSymbolInfo(tickerId: string): Promise<ISymbolInfo>;
58
71
  configure(config: any): void;
59
72
  }
@@ -1,17 +1,9 @@
1
- import { IProvider, ISymbolInfo } from '@pinets/marketData/IProvider';
2
- interface Kline {
3
- openTime: number;
4
- open: number;
5
- high: number;
6
- low: number;
7
- close: number;
8
- volume: number;
9
- closeTime: number;
10
- quoteAssetVolume: number;
11
- numberOfTrades: number;
12
- takerBuyBaseAssetVolume: number;
13
- takerBuyQuoteAssetVolume: number;
14
- ignore: number | string;
1
+ import { ISymbolInfo } from '@pinets/marketData/IProvider';
2
+ import { BaseProvider } from '@pinets/marketData/BaseProvider';
3
+ import { Kline } from '@pinets/marketData/types';
4
+ /** Config for MockProvider. */
5
+ export interface MockProviderConfig {
6
+ dataDirectory?: string;
15
7
  }
16
8
  /**
17
9
  * Mock Market Data Provider for Unit Tests
@@ -30,14 +22,12 @@ interface Kline {
30
22
  *
31
23
  * Example: BTCUSDC-1h-1704067200000-1763683199000.json
32
24
  */
33
- export declare class MockProvider implements IProvider {
25
+ export declare class MockProvider extends BaseProvider<MockProviderConfig> {
34
26
  private dataCache;
35
27
  private exchangeInfoCache;
36
28
  private dataDirectory;
37
- constructor(dataDirectory?: string);
38
- configure({ dataDirectory }: {
39
- dataDirectory?: string;
40
- }): void;
29
+ constructor(dataDirectoryOrConfig?: string | MockProviderConfig);
30
+ configure(config: MockProviderConfig): void;
41
31
  /**
42
32
  * Generates a cache key for the data file
43
33
  */
@@ -58,8 +48,9 @@ export declare class MockProvider implements IProvider {
58
48
  * Normalizes timeframe to match file naming convention
59
49
  */
60
50
  private normalizeTimeframe;
51
+ protected getSupportedTimeframes(): Set<string>;
61
52
  /**
62
- * Implements IProvider.getMarketData
53
+ * Implements _getMarketDataNative
63
54
  *
64
55
  * @param tickerId - Symbol (e.g., 'BTCUSDC')
65
56
  * @param timeframe - Timeframe (e.g., '1h', '60', 'D')
@@ -68,7 +59,7 @@ export declare class MockProvider implements IProvider {
68
59
  * @param eDate - Optional end date (timestamp in milliseconds)
69
60
  * @returns Promise<Kline[]> - Array of candle data
70
61
  */
71
- getMarketData(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
62
+ protected _getMarketDataNative(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<Kline[]>;
72
63
  /**
73
64
  * Loads exchange info from JSON file
74
65
  */
@@ -80,13 +71,6 @@ export declare class MockProvider implements IProvider {
80
71
  * @returns Promise<ISymbolInfo> - Symbol information
81
72
  */
82
73
  getSymbolInfo(tickerId: string): Promise<ISymbolInfo>;
83
- /**
84
- * Normalize closeTime to TradingView convention: closeTime = next bar's openTime.
85
- * Mock data files contain raw Binance data where closeTime = (nextBarOpen - 1ms).
86
- * For all bars except the last, we use the next bar's actual openTime. For the
87
- * last bar, we add 1ms to the raw value.
88
- */
89
- private _normalizeCloseTime;
90
74
  /**
91
75
  * Clears the data cache
92
76
  */
@@ -96,4 +80,3 @@ export declare class MockProvider implements IProvider {
96
80
  */
97
81
  setDataDirectory(directory: string): void;
98
82
  }
99
- export {};
@@ -1,7 +1,10 @@
1
1
  import { IProvider } from './IProvider';
2
+ export { BinanceProvider } from './Binance/BinanceProvider.class';
3
+ export { FMPProvider } from './FMP/FMPProvider.class';
4
+ export { AlpacaProvider } from './Alpaca/AlpacaProvider.class';
5
+ export { BaseProvider } from './BaseProvider';
2
6
  type TProvider = {
3
7
  [key: string]: IProvider;
4
8
  };
5
9
  export declare const Provider: TProvider;
6
10
  export declare function registerProvider(name: string, provider: IProvider): void;
7
- export {};
@@ -0,0 +1,38 @@
1
+ import { Kline } from './types';
2
+ /**
3
+ * Given a target timeframe and a set of supported timeframes, select the
4
+ * best sub-timeframe to aggregate from.
5
+ *
6
+ * Strategy:
7
+ * - **W/M targets**: always use `'D'` (calendar-based grouping).
8
+ * - **All others**: pick the largest supported timeframe whose duration
9
+ * evenly divides the target duration (using `TIMEFRAME_SECONDS`).
10
+ *
11
+ * @returns The best sub-timeframe, or `null` if none found.
12
+ */
13
+ export declare function selectSubTimeframe(targetTimeframe: string, supportedTimeframes: Set<string>): string | null;
14
+ /**
15
+ * Compute how many sub-candles fit into one aggregated candle.
16
+ *
17
+ * For fixed-duration aggregation: `targetSeconds / subSeconds`.
18
+ * For calendar-based (W/M from D): returns `Infinity` to signal variable grouping.
19
+ */
20
+ export declare function getAggregationRatio(targetTimeframe: string, subTimeframe: string): number;
21
+ /**
22
+ * Aggregate sub-candles into higher-timeframe candles.
23
+ *
24
+ * Three modes:
25
+ * 1. **Fixed-ratio** (intraday → higher intraday): groups every N consecutive
26
+ * sub-candles, with session-boundary detection to avoid cross-session merging.
27
+ * 2. **Weekly from daily**: groups daily bars by ISO week number.
28
+ * 3. **Monthly from daily**: groups daily bars by calendar year+month.
29
+ *
30
+ * OHLCV merge:
31
+ * - `open` = first sub-candle's open
32
+ * - `high` = max of all highs
33
+ * - `low` = min of all lows
34
+ * - `close` = last sub-candle's close
35
+ * - `volume` = sum
36
+ * - `closeTime` = last sub-candle's closeTime (preserves session-aware close)
37
+ */
38
+ export declare function aggregateCandles(subCandles: Kline[], targetTimeframe: string, subTimeframe: string): Kline[];