@christtrade/depth 0.12.21
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.
- package/LICENSE.md +201 -0
- package/NOTICE +15 -0
- package/README.md +159 -0
- package/depth.cjs +1136 -0
- package/depth.css +2 -0
- package/depth.mjs +1136 -0
- package/depth.nopreflight.css +2 -0
- package/index.d.ts +1 -0
- package/package.json +32 -0
- package/types/ChartInner.d.ts +114 -0
- package/types/ChartOuter.d.ts +31 -0
- package/types/components/account/AccountSummary.d.ts +8 -0
- package/types/components/chart/chart-context-menu.d.ts +30 -0
- package/types/components/chart/chart-settings-dialog.d.ts +15 -0
- package/types/components/chart/chart-status-overlay.d.ts +24 -0
- package/types/components/chart/data-status.d.ts +10 -0
- package/types/components/chart/pane-legend.d.ts +37 -0
- package/types/components/chart/session-status-badge.d.ts +14 -0
- package/types/components/chart/status-bar.d.ts +9 -0
- package/types/components/chart/symbol-icon.d.ts +9 -0
- package/types/components/chart/tz.d.ts +10 -0
- package/types/components/drawings/drawing-icons.d.ts +2 -0
- package/types/components/drawings/drawing-settings-bar.d.ts +15 -0
- package/types/components/drawings/drawing-settings-dialog.d.ts +268 -0
- package/types/components/drawings/drawing-toolbar.d.ts +14 -0
- package/types/components/drawings/drawing-tools.d.ts +23 -0
- package/types/components/indicators/indicators-dialog.d.ts +20 -0
- package/types/components/indicators/indicators-settings-dialog.d.ts +164 -0
- package/types/components/multi-chart/GridDividers.d.ts +12 -0
- package/types/components/multi-chart/LayoutPicker.d.ts +19 -0
- package/types/components/plugin-panels/BottomBarPluginHost.d.ts +7 -0
- package/types/components/plugin-panels/PluginFixedPanelHost.d.ts +18 -0
- package/types/components/plugin-panels/PluginToolbarHost.d.ts +7 -0
- package/types/components/plugin-panels/PluginWindowsDropdown.d.ts +7 -0
- package/types/components/plugins/plugin-manager-dialog.d.ts +14 -0
- package/types/components/toolbar/SymbolSwitcher.d.ts +8 -0
- package/types/components/toolbar/chart-icons.d.ts +16 -0
- package/types/components/toolbar/chart-type-selector.d.ts +11 -0
- package/types/components/toolbar/timeframe-selector.d.ts +15 -0
- package/types/components/trading/OrderPanel.d.ts +36 -0
- package/types/components/trading/QuickTradingButtons.d.ts +7 -0
- package/types/components/trading/order-math.d.ts +94 -0
- package/types/components/ui/button.d.ts +11 -0
- package/types/components/ui/checkbox.d.ts +4 -0
- package/types/components/ui/color-picker.d.ts +12 -0
- package/types/components/ui/dialog.d.ts +19 -0
- package/types/components/ui/dropdown-menu.d.ts +27 -0
- package/types/components/ui/hover-card.d.ts +6 -0
- package/types/components/ui/input.d.ts +4 -0
- package/types/components/ui/popover.d.ts +7 -0
- package/types/components/ui/resizable.d.ts +23 -0
- package/types/components/ui/separator.d.ts +4 -0
- package/types/components/ui/slider.d.ts +4 -0
- package/types/components/ui/switch.d.ts +4 -0
- package/types/components/ui/tooltip.d.ts +7 -0
- package/types/core/AccountManager.d.ts +142 -0
- package/types/core/ChartModel.d.ts +84 -0
- package/types/core/ChartState.d.ts +51 -0
- package/types/core/ChartTypeRegistry.d.ts +27 -0
- package/types/core/DataEngine.d.ts +143 -0
- package/types/core/DataSourceRegistry.d.ts +106 -0
- package/types/core/DepthChart.d.ts +458 -0
- package/types/core/DrawingRegistry.d.ts +133 -0
- package/types/core/DrawingStore.d.ts +26 -0
- package/types/core/ExecutionEngine.d.ts +95 -0
- package/types/core/GlobalChartBus.d.ts +32 -0
- package/types/core/Playback.d.ts +48 -0
- package/types/core/PlaybackStateRegistry.d.ts +25 -0
- package/types/core/PluginRegistry.d.ts +67 -0
- package/types/core/PluginSchedule.d.ts +15 -0
- package/types/core/RenderEngine.d.ts +143 -0
- package/types/core/ScriptedPlugin.d.ts +153 -0
- package/types/core/SessionMapper.d.ts +54 -0
- package/types/core/SessionUtils.d.ts +53 -0
- package/types/core/TypedEventBus.d.ts +691 -0
- package/types/core/WasmPluginHost.d.ts +39 -0
- package/types/core/index.d.ts +70 -0
- package/types/core/plugin-startup.d.ts +33 -0
- package/types/core/processing/data-chunk.d.ts +37 -0
- package/types/core/processing/data-level.d.ts +13 -0
- package/types/core/processing/l2-processor.d.ts +10 -0
- package/types/core/processing/l3-processor.d.ts +26 -0
- package/types/core/processing/ohlcv-processor.d.ts +14 -0
- package/types/core/processing/tick-processor.d.ts +14 -0
- package/types/core/script-dsl.d.ts +20 -0
- package/types/core/script-scope.d.ts +4 -0
- package/types/core/script.worker.d.ts +1 -0
- package/types/hooks/useCellBridges.d.ts +36 -0
- package/types/hooks/useChartData.d.ts +153 -0
- package/types/hooks/useChartHandlers.d.ts +94 -0
- package/types/hooks/useChartInteraction.d.ts +160 -0
- package/types/hooks/useChartLayout.d.ts +21 -0
- package/types/hooks/useChartPlugin.d.ts +34 -0
- package/types/hooks/useChartSettings.d.ts +44 -0
- package/types/hooks/useChartSubscriptions.d.ts +64 -0
- package/types/hooks/useChartView.d.ts +47 -0
- package/types/hooks/usePlaybackEngine.d.ts +85 -0
- package/types/hooks/useRenderEngine.d.ts +64 -0
- package/types/hooks/useTradeLines.d.ts +80 -0
- package/types/hooks/useTradingState.d.ts +135 -0
- package/types/interfaces/IAccountAdapter.d.ts +38 -0
- package/types/interfaces/ICoordinateTransformer.d.ts +105 -0
- package/types/interfaces/IDataAdapter.d.ts +402 -0
- package/types/interfaces/IExecutionAdapter.d.ts +71 -0
- package/types/interfaces/plugins/IChartPlugin.d.ts +254 -0
- package/types/interfaces/plugins/IChartTypePlugin.d.ts +126 -0
- package/types/interfaces/plugins/IDataSourcePlugin.d.ts +20 -0
- package/types/interfaces/plugins/IDrawingPlugin.d.ts +62 -0
- package/types/interfaces/plugins/IIndicatorPlugin.d.ts +97 -0
- package/types/interfaces/plugins/index.d.ts +5 -0
- package/types/lib/bar-grid.d.ts +6 -0
- package/types/lib/book.d.ts +5 -0
- package/types/lib/clock.d.ts +7 -0
- package/types/lib/compact-buffer.d.ts +66 -0
- package/types/lib/constants.d.ts +5 -0
- package/types/lib/createSimulatedAdapter.d.ts +42 -0
- package/types/lib/dpr.d.ts +27 -0
- package/types/lib/heatmap.worker.d.ts +1 -0
- package/types/lib/indicator-stdlib.d.ts +426 -0
- package/types/lib/indicator-worker.d.ts +65 -0
- package/types/lib/matchingEngine.d.ts +144 -0
- package/types/lib/notifications/tradeToast.d.ts +31 -0
- package/types/lib/pointer-lock.d.ts +5 -0
- package/types/lib/priceFormat.d.ts +17 -0
- package/types/lib/priceTransition.d.ts +22 -0
- package/types/lib/renderers/drawFootprintChart.d.ts +5 -0
- package/types/lib/renderers/drawTradeLines.d.ts +112 -0
- package/types/lib/renderers/drawings-renderer.d.ts +57 -0
- package/types/lib/renderers/renderer.d.ts +113 -0
- package/types/lib/sampler.d.ts +7 -0
- package/types/lib/series/japaneseCharts.d.ts +88 -0
- package/types/lib/slice-worker-client.d.ts +138 -0
- package/types/lib/slice.worker.d.ts +139 -0
- package/types/lib/storage.d.ts +108 -0
- package/types/lib/symbol-info.d.ts +12 -0
- package/types/lib/symbol-search.d.ts +29 -0
- package/types/lib/timeframes.d.ts +46 -0
- package/types/lib/tradingview-import.d.ts +32 -0
- package/types/lib/types/chart-settings.d.ts +90 -0
- package/types/lib/types/drawing-types.d.ts +393 -0
- package/types/lib/types/footprint.d.ts +119 -0
- package/types/lib/types/heatmap-types.d.ts +30 -0
- package/types/lib/types/index.d.ts +147 -0
- package/types/lib/types/indicator-types.d.ts +123 -0
- package/types/lib/types/layout-sync.d.ts +43 -0
- package/types/lib/types/trading-types.d.ts +323 -0
- package/types/lib/use-forwarded-ref.d.ts +1 -0
- package/types/lib/utils.d.ts +2 -0
- package/types/plugins/alligator.d.ts +1 -0
- package/types/plugins/atr.d.ts +1 -0
- package/types/plugins/awesome-oscillator.d.ts +1 -0
- package/types/plugins/bollinger-bands.d.ts +1 -0
- package/types/plugins/cci.d.ts +1 -0
- package/types/plugins/cvd.d.ts +1 -0
- package/types/plugins/donchian.d.ts +1 -0
- package/types/plugins/ichimoku.d.ts +1 -0
- package/types/plugins/index.d.ts +25 -0
- package/types/plugins/keltner.d.ts +1 -0
- package/types/plugins/macd.d.ts +1 -0
- package/types/plugins/mfi.d.ts +1 -0
- package/types/plugins/moving-average.d.ts +1 -0
- package/types/plugins/obv.d.ts +1 -0
- package/types/plugins/psar.d.ts +1 -0
- package/types/plugins/rsi.d.ts +1 -0
- package/types/plugins/sessions.d.ts +1 -0
- package/types/plugins/stochastic.d.ts +1 -0
- package/types/plugins/supertrend.d.ts +1 -0
- package/types/plugins/volume.d.ts +1 -0
- package/types/plugins/vwap.d.ts +1 -0
- package/types/plugins/williams-r.d.ts +1 -0
- package/types/react/useDepthChart.d.ts +6 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { LiveTransformer } from '../../core';
|
|
2
|
+
import type { DataLevel } from '../../interfaces/IDataAdapter';
|
|
3
|
+
import type { Crosshair } from '../renderers/renderer';
|
|
4
|
+
/** Pixel region a pane occupies on the canvas (absolute coordinates). */
|
|
5
|
+
export type Rect = {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
w: number;
|
|
9
|
+
h: number;
|
|
10
|
+
};
|
|
11
|
+
export interface ChartPane {
|
|
12
|
+
id: string;
|
|
13
|
+
isMain: boolean;
|
|
14
|
+
heightRatio: number;
|
|
15
|
+
label?: string;
|
|
16
|
+
yMin: number;
|
|
17
|
+
yMax: number;
|
|
18
|
+
yAxisAuto: boolean;
|
|
19
|
+
collapsed: boolean;
|
|
20
|
+
savedHeightRatio?: number;
|
|
21
|
+
symbol?: string;
|
|
22
|
+
tf?: string;
|
|
23
|
+
exchange?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Everything an indicator needs to draw itself.
|
|
27
|
+
* `rect` uses LOCAL coordinates (origin = top-left of this pane).
|
|
28
|
+
*
|
|
29
|
+
* `horizon` is the current playback horizon in nanoseconds.
|
|
30
|
+
* Indicators MUST use this to clip their output - never draw data beyond
|
|
31
|
+
* horizon. This is the only way to guarantee no future data leaks at
|
|
32
|
+
* sub-bar precision. tMax is the rightmost visible timestamp of the view
|
|
33
|
+
* and is unrelated to horizon.
|
|
34
|
+
*/
|
|
35
|
+
export interface RenderContext {
|
|
36
|
+
ctx: CanvasRenderingContext2D;
|
|
37
|
+
/** Local rect - origin is (0, 0) after ctx.translate has been applied. */
|
|
38
|
+
rect: Rect;
|
|
39
|
+
/** Shared time axis (nanoseconds). */
|
|
40
|
+
tMin: bigint;
|
|
41
|
+
tMax: bigint;
|
|
42
|
+
/** Pane-local price / value axis. */
|
|
43
|
+
yMin: number;
|
|
44
|
+
yMax: number;
|
|
45
|
+
/** Active bar duration in nanoseconds (0n = tick/raw mode). */
|
|
46
|
+
barNs: bigint;
|
|
47
|
+
/**
|
|
48
|
+
* Current playback horizon in nanoseconds.
|
|
49
|
+
* Clip all drawing to ts <= horizon. Do not draw anything beyond this
|
|
50
|
+
* timestamp - doing so leaks future data.
|
|
51
|
+
*
|
|
52
|
+
* 0n means no horizon is active (live / full-history mode), in which
|
|
53
|
+
* case you can draw everything.
|
|
54
|
+
*/
|
|
55
|
+
horizon: bigint;
|
|
56
|
+
transformer: LiveTransformer;
|
|
57
|
+
}
|
|
58
|
+
export interface Indicator {
|
|
59
|
+
id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
visible: boolean;
|
|
62
|
+
layout: 'overlay' | 'pane';
|
|
63
|
+
paneId?: string;
|
|
64
|
+
category?: string;
|
|
65
|
+
shortName?: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Minimum data level this indicator can be computed from. Defaults to
|
|
69
|
+
* 'ohlcv'. Activation is refused on a symbol that serves less than this -
|
|
70
|
+
* the alternative is an indicator that draws nothing and looks broken.
|
|
71
|
+
*/
|
|
72
|
+
require?: DataLevel;
|
|
73
|
+
settings: any;
|
|
74
|
+
/**
|
|
75
|
+
* Serialized init function - runs in the indicator worker on full load
|
|
76
|
+
* (initial data load, backward seek, timeframe change).
|
|
77
|
+
*
|
|
78
|
+
* Signature: (input: { trades: SerialTrade[], barNs: bigint, params?: unknown }) => State
|
|
79
|
+
*
|
|
80
|
+
* Returns the full computed state. Must be pure - no imports, no closures.
|
|
81
|
+
* The returned State is stored in the worker and passed to workerUpdate
|
|
82
|
+
* on every horizon tick.
|
|
83
|
+
*/
|
|
84
|
+
workerInit: string;
|
|
85
|
+
/**
|
|
86
|
+
* Serialized incremental update function - runs in the indicator worker
|
|
87
|
+
* on every horizon advance tick (hot path: called up to 1200 times/s at 20x).
|
|
88
|
+
*
|
|
89
|
+
* Signature: (input: { newTrades: SerialTrade[], state: State, barNs: bigint, horizon: bigint, params?: unknown }) => { points: OutputPoints, state: State }
|
|
90
|
+
*
|
|
91
|
+
* `newTrades` contains only the trades since the last horizon position.
|
|
92
|
+
* `state` is whatever workerInit (or the previous workerUpdate) returned.
|
|
93
|
+
* Returns new output points to append, plus the updated state.
|
|
94
|
+
*
|
|
95
|
+
* Must be pure - no imports, no closures.
|
|
96
|
+
*/
|
|
97
|
+
workerUpdate: string;
|
|
98
|
+
/**
|
|
99
|
+
* Called on the main thread after workerInit completes (full load /
|
|
100
|
+
* backward seek). Replaces all stored output data.
|
|
101
|
+
*
|
|
102
|
+
* `data` is whatever workerInit returned.
|
|
103
|
+
*/
|
|
104
|
+
hydrate(data: unknown, barNs: bigint): void;
|
|
105
|
+
/**
|
|
106
|
+
* Called on the main thread after workerUpdate completes (horizon advance).
|
|
107
|
+
* Appends the new output points to existing stored data - never replaces.
|
|
108
|
+
*
|
|
109
|
+
* `points` is whatever workerUpdate returned in the `points` field.
|
|
110
|
+
*/
|
|
111
|
+
appendHydrate(points: unknown, barNs: bigint): void;
|
|
112
|
+
drawBase?(ctx: RenderContext): void;
|
|
113
|
+
drawUI?(ctx: RenderContext, crosshair: Crosshair): void;
|
|
114
|
+
getAutoYBounds?(tMin: bigint, tMax: bigint, horizon: bigint): {
|
|
115
|
+
min: number;
|
|
116
|
+
max: number;
|
|
117
|
+
} | null;
|
|
118
|
+
}
|
|
119
|
+
export declare const PANE_DIVIDER_HIT = 6;
|
|
120
|
+
export declare const PANE_MIN_HEIGHT_RATIO = 0.05;
|
|
121
|
+
export declare function getPaneLayouts(panes: ChartPane[], totalH: number, canvasW: number, yAxisWidth: number): Record<string, Rect>;
|
|
122
|
+
export declare function hitTestDivider(mouseY: number, panes: ChartPane[], layouts: Record<string, Rect>): number;
|
|
123
|
+
export declare function hitTestPane(mouseY: number, panes: ChartPane[], layouts: Record<string, Rect>): ChartPane | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Which properties are shared between the cells of a layout. */
|
|
2
|
+
export type SyncInLayout = {
|
|
3
|
+
/** Changing a cell's symbol changes every cell's symbol. */
|
|
4
|
+
symbol: boolean;
|
|
5
|
+
/** Changing a cell's timeframe changes every cell's timeframe. */
|
|
6
|
+
interval: boolean;
|
|
7
|
+
/** The hovered cell's crosshair is mirrored (by time/price) onto the others. */
|
|
8
|
+
crosshair: boolean;
|
|
9
|
+
/** Scrolling a cell scrolls the others to the same right edge - each keeps its own zoom. */
|
|
10
|
+
time: boolean;
|
|
11
|
+
/** Panning/zooming a cell gives the others the exact same visible range. */
|
|
12
|
+
dateRange: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare const DEFAULT_SYNC_IN_LAYOUT: SyncInLayout;
|
|
15
|
+
/**
|
|
16
|
+
* A crosshair position expressed in *data* space so any other cell can place it
|
|
17
|
+
* on its own axes, whatever it is showing or however it is zoomed.
|
|
18
|
+
*
|
|
19
|
+
* Sent once per pointer move by the hovered cell - never per frame. Receivers
|
|
20
|
+
* keep the payload and re-project it every time they paint, so panning or
|
|
21
|
+
* zooming a follower keeps the mirrored crosshair pinned to the same bar
|
|
22
|
+
* without another message.
|
|
23
|
+
*/
|
|
24
|
+
export type CrosshairSync = {
|
|
25
|
+
/** Cell that owns the pointer. Receivers ignore their own id. */
|
|
26
|
+
id: number;
|
|
27
|
+
/** Time under the cursor (ns). Drives the mirrored vertical line. */
|
|
28
|
+
ts: bigint;
|
|
29
|
+
/** Value under the cursor, in the source pane's own scale. */
|
|
30
|
+
price: number;
|
|
31
|
+
/** Pane the cursor is in ('main' or an indicator pane id). */
|
|
32
|
+
paneId: string;
|
|
33
|
+
/** Cursor position inside that pane, 0 (top) -> 1 (bottom). */
|
|
34
|
+
yFrac: number;
|
|
35
|
+
/** Source symbol - the price only carries over to cells showing the same one. */
|
|
36
|
+
symbol: string | null;
|
|
37
|
+
};
|
|
38
|
+
/** The visible time range of the cell the user is scrolling/zooming. */
|
|
39
|
+
export type TimeRangeSync = {
|
|
40
|
+
id: number;
|
|
41
|
+
tMin: bigint;
|
|
42
|
+
tMax: bigint;
|
|
43
|
+
};
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
export type OrderSide = 'long' | 'short';
|
|
2
|
+
export type PositionSide = 'long' | 'short' | 'flat';
|
|
3
|
+
export type OrderType = 'market' | 'limit' | 'stop' | 'stop_limit';
|
|
4
|
+
export type OrderStatus = 'pending' | 'working' | 'partial' | 'filled' | 'cancelled' | 'rejected';
|
|
5
|
+
export type PositionStatus = 'open' | 'closed' | 'partially_closed';
|
|
6
|
+
export type TimeInForce = 'gtc' | 'day' | 'ioc' | 'fok' | 'gtd';
|
|
7
|
+
export type CloseReason = 'manual' | 'tp' | 'sl' | 'order' | 'market' | 'limit' | 'stop';
|
|
8
|
+
export type CommissionConfig = {
|
|
9
|
+
type: 'fixed' | 'percent';
|
|
10
|
+
/** fixed: $ per fill - percent: % of notional */
|
|
11
|
+
value: number;
|
|
12
|
+
};
|
|
13
|
+
export type SlippageConfig = {
|
|
14
|
+
type: 'ticks' | 'percent';
|
|
15
|
+
/** ticks: number of ticks - percent: % of price */
|
|
16
|
+
value: number;
|
|
17
|
+
};
|
|
18
|
+
export type BracketLevel = {
|
|
19
|
+
/** Stable id - use nanoid(). Lets the engine match broker updates without
|
|
20
|
+
* relying on array position. Required when round-tripping through a broker. */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Price to trigger the TP or SL order. */
|
|
23
|
+
price: number;
|
|
24
|
+
/** Contracts / shares to close at this level. Must be > 0. */
|
|
25
|
+
qty: number;
|
|
26
|
+
/** Set by the engine when the bracket order is triggered. */
|
|
27
|
+
triggered: boolean;
|
|
28
|
+
/** Unix ns when triggered. 0 = not yet triggered. */
|
|
29
|
+
triggeredAt: number;
|
|
30
|
+
};
|
|
31
|
+
export type BracketSpec = {
|
|
32
|
+
takeProfits?: BracketLevel[];
|
|
33
|
+
stopLosses?: BracketLevel[];
|
|
34
|
+
};
|
|
35
|
+
export type Order = {
|
|
36
|
+
id: string;
|
|
37
|
+
symbol: string;
|
|
38
|
+
side: OrderSide;
|
|
39
|
+
type: OrderType;
|
|
40
|
+
/** Total order quantity (contracts / shares). Always positive. */
|
|
41
|
+
quantity: number;
|
|
42
|
+
/** Limit price - required for 'limit' and 'stop_limit'. */
|
|
43
|
+
price: number;
|
|
44
|
+
/** Stop trigger price - required for 'stop' and 'stop_limit'. */
|
|
45
|
+
stopPrice: number;
|
|
46
|
+
tif: TimeInForce;
|
|
47
|
+
/** If true, will only reduce an existing position; will never open or flip. */
|
|
48
|
+
reduceOnly: boolean;
|
|
49
|
+
/** Apply reduce logic to this specific position first (multi-position setups). */
|
|
50
|
+
targetPositionId?: string;
|
|
51
|
+
/** Bracket to attach to the position this order opens. */
|
|
52
|
+
bracket: BracketSpec;
|
|
53
|
+
status: OrderStatus;
|
|
54
|
+
filledQuantity: number;
|
|
55
|
+
/** Volume-weighted average fill price. */
|
|
56
|
+
avgPrice: number;
|
|
57
|
+
/** Internal flag for STOP_LIMIT - set by engine when stop is triggered. */
|
|
58
|
+
triggered: boolean;
|
|
59
|
+
createdAt: number;
|
|
60
|
+
updatedAt: number;
|
|
61
|
+
fees: number;
|
|
62
|
+
commission: number;
|
|
63
|
+
slippage: number;
|
|
64
|
+
metadata: Record<string, any>;
|
|
65
|
+
};
|
|
66
|
+
export type Fill = {
|
|
67
|
+
id: string;
|
|
68
|
+
orderId: string;
|
|
69
|
+
symbol: string;
|
|
70
|
+
side: OrderSide;
|
|
71
|
+
price: number;
|
|
72
|
+
quantity: number;
|
|
73
|
+
ts: number;
|
|
74
|
+
fee: number;
|
|
75
|
+
feeCurrency: string;
|
|
76
|
+
/** Id of the position opened by this fill. */
|
|
77
|
+
openedPositionId?: string;
|
|
78
|
+
/** Ids of positions reduced by this fill. */
|
|
79
|
+
reducedPositionIds?: string[];
|
|
80
|
+
};
|
|
81
|
+
export type PositionClose = {
|
|
82
|
+
timestamp: number;
|
|
83
|
+
price: number;
|
|
84
|
+
quantity: number;
|
|
85
|
+
/** Gross PnL for this close (price diff x qty x tickValue). */
|
|
86
|
+
pnl: number;
|
|
87
|
+
/** Net PnL after per-close costs and allocated open-leg costs. */
|
|
88
|
+
pnlNet: number;
|
|
89
|
+
reason: CloseReason;
|
|
90
|
+
orderId: string;
|
|
91
|
+
orderType: OrderType;
|
|
92
|
+
tpId?: string;
|
|
93
|
+
slId?: string;
|
|
94
|
+
/** Realized risk-reward ratio after this close. */
|
|
95
|
+
realizedRRAfter: number;
|
|
96
|
+
fees: number;
|
|
97
|
+
commission: number;
|
|
98
|
+
slippage: number;
|
|
99
|
+
spread: number;
|
|
100
|
+
/** Portion of open-leg costs allocated to this close (for auditing). */
|
|
101
|
+
openCostAllocated?: number;
|
|
102
|
+
notes?: object[];
|
|
103
|
+
tags?: object[];
|
|
104
|
+
};
|
|
105
|
+
export type Position = {
|
|
106
|
+
id: string;
|
|
107
|
+
symbol: string;
|
|
108
|
+
side: PositionSide;
|
|
109
|
+
type: OrderType;
|
|
110
|
+
status: PositionStatus;
|
|
111
|
+
/** Quantity at open. Immutable after creation. */
|
|
112
|
+
startingQuantity: number;
|
|
113
|
+
/** Current open quantity (startingQuantity minus qty from closes[]). */
|
|
114
|
+
remainingQuantity: number;
|
|
115
|
+
/** Volume-weighted average entry price. */
|
|
116
|
+
entryPrice: number;
|
|
117
|
+
/** Mark price for live PnL - updated by tick(). */
|
|
118
|
+
currentPrice?: number;
|
|
119
|
+
unrealizedPnl: number;
|
|
120
|
+
unrealizedPnlPct: number;
|
|
121
|
+
/** Cumulative gross realized PnL across all closes[]. */
|
|
122
|
+
realizedPnl: number;
|
|
123
|
+
/** Initial risk per unit (|entry - initialSL|). Set once at open. */
|
|
124
|
+
initialRiskPerUnit: number;
|
|
125
|
+
/** Total initial risk (initialRiskPerUnit x startingQuantity). */
|
|
126
|
+
initialRiskTotal: number;
|
|
127
|
+
/** Unix ns when initialRisk was locked in. 0 = not yet locked. */
|
|
128
|
+
initialRiskLockedAt: number;
|
|
129
|
+
/** Intended RR at open (set by the user pre-trade). */
|
|
130
|
+
initialRR: number;
|
|
131
|
+
/** Running realized RR (realizedPnl / initialRiskTotal). */
|
|
132
|
+
realizedRR: number;
|
|
133
|
+
/** Best realized RR reached while the position was open. */
|
|
134
|
+
maxFavorableR: number;
|
|
135
|
+
/** Worst realized RR reached while the position was open. */
|
|
136
|
+
maxAdverseR: number;
|
|
137
|
+
/** Highest mark price seen (long) / lowest mark price seen (short). */
|
|
138
|
+
highWatermark: number;
|
|
139
|
+
/** Lowest mark price seen (long) / highest mark price seen (short). */
|
|
140
|
+
lowWatermark: number;
|
|
141
|
+
/** Maximum adverse excursion - worst price against the position. */
|
|
142
|
+
maeAbs: number;
|
|
143
|
+
/** Maximum favorable excursion - best price in favour. */
|
|
144
|
+
mfeAbs: number;
|
|
145
|
+
/** Largest drawdown from the high-watermark in price units. */
|
|
146
|
+
maxDrawdownAbs: number;
|
|
147
|
+
maxDrawdownPct: number;
|
|
148
|
+
takeProfits: BracketLevel[];
|
|
149
|
+
stopLosses: BracketLevel[];
|
|
150
|
+
/** Break-even level - single price, does not close quantity. */
|
|
151
|
+
bePrice?: number;
|
|
152
|
+
/** One entry per partial or full close. */
|
|
153
|
+
closes: PositionClose[];
|
|
154
|
+
spread: number;
|
|
155
|
+
feesTotal: number;
|
|
156
|
+
commissionTotal: number;
|
|
157
|
+
slippageTotal: number;
|
|
158
|
+
/** (commission_open + fees_open) / startingQuantity - for proportional allocation on partial closes. */
|
|
159
|
+
openCostPerUnit: number;
|
|
160
|
+
openCostTotal: number;
|
|
161
|
+
openedAt: number;
|
|
162
|
+
closedAt?: number;
|
|
163
|
+
updatedAt: number;
|
|
164
|
+
notes?: object[];
|
|
165
|
+
tags?: object[];
|
|
166
|
+
checklist?: object[];
|
|
167
|
+
rating?: number;
|
|
168
|
+
emotion?: object[];
|
|
169
|
+
images?: object[];
|
|
170
|
+
tradeType?: string;
|
|
171
|
+
confidence?: number;
|
|
172
|
+
playbookAdherence?: number;
|
|
173
|
+
metadata?: Record<string, any>;
|
|
174
|
+
};
|
|
175
|
+
export type CreatePositionParams = {
|
|
176
|
+
symbol: string;
|
|
177
|
+
side: PositionSide;
|
|
178
|
+
type: OrderType;
|
|
179
|
+
entryPrice: number;
|
|
180
|
+
quantity: number;
|
|
181
|
+
timestamp: number;
|
|
182
|
+
takeProfits?: Array<{
|
|
183
|
+
price: number;
|
|
184
|
+
qty: number;
|
|
185
|
+
}>;
|
|
186
|
+
stopLosses?: Array<{
|
|
187
|
+
price: number;
|
|
188
|
+
qty: number;
|
|
189
|
+
}>;
|
|
190
|
+
metadata: Record<string, any>;
|
|
191
|
+
notes?: object[];
|
|
192
|
+
tags?: object[];
|
|
193
|
+
checklist?: object[];
|
|
194
|
+
rating?: number;
|
|
195
|
+
emotion?: object[];
|
|
196
|
+
images?: object[];
|
|
197
|
+
confidence?: number;
|
|
198
|
+
playbookAdherence?: number;
|
|
199
|
+
tradeType?: string;
|
|
200
|
+
};
|
|
201
|
+
export type ClosePositionParams = {
|
|
202
|
+
positionId: string;
|
|
203
|
+
price: number;
|
|
204
|
+
/** Defaults to full remainingQuantity if omitted. */
|
|
205
|
+
quantity: number;
|
|
206
|
+
timestamp: number;
|
|
207
|
+
reason: CloseReason;
|
|
208
|
+
orderId?: string;
|
|
209
|
+
orderType?: OrderType;
|
|
210
|
+
tpId?: string;
|
|
211
|
+
slId?: string;
|
|
212
|
+
fees: number;
|
|
213
|
+
commission: number;
|
|
214
|
+
slippage: number;
|
|
215
|
+
};
|
|
216
|
+
export type CreateOrderParams = {
|
|
217
|
+
symbol: string;
|
|
218
|
+
side: OrderSide;
|
|
219
|
+
type: OrderType;
|
|
220
|
+
quantity: number;
|
|
221
|
+
price: number;
|
|
222
|
+
stopPrice: number;
|
|
223
|
+
tif: TimeInForce;
|
|
224
|
+
reduceOnly: boolean;
|
|
225
|
+
timestamp: number;
|
|
226
|
+
targetPositionId?: string;
|
|
227
|
+
bracket?: BracketSpec;
|
|
228
|
+
metadata: Record<string, any>;
|
|
229
|
+
fees: number;
|
|
230
|
+
commission: number;
|
|
231
|
+
slippage: number;
|
|
232
|
+
notes?: object[];
|
|
233
|
+
tags?: object[];
|
|
234
|
+
};
|
|
235
|
+
export type PriceTick = {
|
|
236
|
+
symbol: string;
|
|
237
|
+
bid: number;
|
|
238
|
+
ask: number;
|
|
239
|
+
last?: number;
|
|
240
|
+
ts: number;
|
|
241
|
+
};
|
|
242
|
+
export type BracketAmendment = {
|
|
243
|
+
positionId: string;
|
|
244
|
+
which: 'tp' | 'sl' | 'be';
|
|
245
|
+
/** 0-based array index in takeProfits / stopLosses. */
|
|
246
|
+
index: number;
|
|
247
|
+
/** BracketLevel.id */
|
|
248
|
+
levelId: string;
|
|
249
|
+
price: number;
|
|
250
|
+
qty: number;
|
|
251
|
+
/**
|
|
252
|
+
* Drop this level instead of repricing it (the x on a TP/SL line).
|
|
253
|
+
*
|
|
254
|
+
* Removal goes through the same call as a move on purpose: whoever is
|
|
255
|
+
* managing the position - the built-in engine or a broker adapter - has to
|
|
256
|
+
* hear about it, or the level stays armed after the user has taken it off
|
|
257
|
+
* the chart. `price` and `qty` are ignored when this is set.
|
|
258
|
+
*/
|
|
259
|
+
remove?: boolean;
|
|
260
|
+
};
|
|
261
|
+
export type TradingEventKind = 'order:placed' | 'order:updated' | 'order:cancelled' | 'order:filled' | 'order:rejected' | 'position:opened' | 'position:updated' | 'position:closed' | 'fill:received';
|
|
262
|
+
export type TradingEvent = {
|
|
263
|
+
kind: 'order:placed';
|
|
264
|
+
order: Order;
|
|
265
|
+
} | {
|
|
266
|
+
kind: 'order:updated';
|
|
267
|
+
order: Order;
|
|
268
|
+
} | {
|
|
269
|
+
kind: 'order:cancelled';
|
|
270
|
+
order: Order;
|
|
271
|
+
} | {
|
|
272
|
+
kind: 'order:filled';
|
|
273
|
+
order: Order;
|
|
274
|
+
fill: Fill;
|
|
275
|
+
} | {
|
|
276
|
+
kind: 'order:rejected';
|
|
277
|
+
order: Order;
|
|
278
|
+
reason?: string;
|
|
279
|
+
} | {
|
|
280
|
+
kind: 'position:opened';
|
|
281
|
+
position: Position;
|
|
282
|
+
} | {
|
|
283
|
+
kind: 'position:updated';
|
|
284
|
+
position: Position;
|
|
285
|
+
} | {
|
|
286
|
+
kind: 'position:closed';
|
|
287
|
+
position: Position;
|
|
288
|
+
realizedPnl: number;
|
|
289
|
+
} | {
|
|
290
|
+
kind: 'fill:received';
|
|
291
|
+
fill: Fill;
|
|
292
|
+
};
|
|
293
|
+
export type PositionsSnapshot = {
|
|
294
|
+
positions: Position[];
|
|
295
|
+
orders: Order[];
|
|
296
|
+
positionCounter: number;
|
|
297
|
+
orderCounter: number;
|
|
298
|
+
lastState: {
|
|
299
|
+
lastPriceBySymbol: Record<string, number>;
|
|
300
|
+
lastSpreadBySymbol: Record<string, number>;
|
|
301
|
+
lastBarEndBySymbol: Record<string, number>;
|
|
302
|
+
currentTimeBySymbol: Record<string, number>;
|
|
303
|
+
tradeCosts: {
|
|
304
|
+
commission: CommissionConfig;
|
|
305
|
+
slippage: SlippageConfig;
|
|
306
|
+
fees: number;
|
|
307
|
+
};
|
|
308
|
+
defaultNonFuturesTickSize?: number;
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
/**
|
|
312
|
+
* What one point is worth on one contract, for a symbol with no spec attached.
|
|
313
|
+
*
|
|
314
|
+
* Micros are tested first: every micro's ticker contains its mini's, so "MNQ"
|
|
315
|
+
* matched the NQ branch and a micro trade was valued at ten times its size.
|
|
316
|
+
* A symbol that carries a `ContractSpec` never reaches here - this is only the
|
|
317
|
+
* floor under adapters that supply nothing.
|
|
318
|
+
*/
|
|
319
|
+
export declare function getTickValue(symbol: string): number;
|
|
320
|
+
export declare function calcUnrealizedPnl(position: Position, markPrice: number, tickValue: number): number;
|
|
321
|
+
export declare function calcUnrealizedPnlPct(position: Position, markPrice: number, tickValue: number): number;
|
|
322
|
+
export declare function formatPnl(pnl: number, decimals?: number): string;
|
|
323
|
+
export declare function formatPnlPct(pct: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useForwardedRef<T>(forwardedRef: React.ForwardedRef<T>): React.MutableRefObject<T | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const alligatorIndi = "\nconst alligatorIndi = plugin({\n name: \"Alligator\",\n shortName: \"ALLI\",\n description: \"Bill Williams' three displaced balance lines\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 100,\n params: {\n jawShift: { label: \"Jaw shift\", type: \"stepperInt\", default: 8, min: 0, max: 50 },\n teethShift: { label: \"Teeth shift\", type: \"stepperInt\", default: 5, min: 0, max: 50 },\n lipsShift: { label: \"Lips shift\", type: \"stepperInt\", default: 3, min: 0, max: 50 }\n }\n})\n\nconst JAW = \"#08b3de\"\nconst TEETH = \"#ef5350\"\nconst LIPS = \"#26a69a\"\n\nalligatorIndi.init = function({ data, barNs, params }) {\n const bars = data.ohlcv\n const n = bars.length\n if (!n) return { jaw: [], teeth: [], lips: [] }\n\n const { jaw, teeth, lips } = alligator(bars)\n const tsAt = i => i < n ? bars[i].ts : bars[n - 1].ts + BigInt(i - n + 1) * barNs\n\n const shifted = (values, shift) => {\n const step = barNs > 0n ? shift : 0\n const out = []\n for (let i = 0; i < n; i++) {\n if (isNaN(values[i])) continue\n out.push({ t: tsAt(i + step), price: values[i] })\n }\n return out\n }\n\n return {\n jaw: shifted(jaw, params.jawShift),\n teeth: shifted(teeth, params.teethShift),\n lips: shifted(lips, params.lipsShift)\n }\n}\n\nalligatorIndi.draw = function(s) {\n return [\n drawLine(s.jaw, JAW, 1),\n drawLine(s.teeth, TEETH, 1),\n drawLine(s.lips, LIPS, 1)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const atrIndi = "\nconst atrIndi = plugin({\n name: \"Average True Range\",\n shortName: \"ATR\",\n description: \"Wilder-smoothed range, in price units\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 150,\n params: {\n length: { label: \"Length\", type: \"number\", default: 14, min: 1, max: 300 },\n smoothing: { label: \"Average\", type: \"number\", default: 0, min: 0, max: 300 },\n line: { label: \"ATR\", type: \"color\", default: \"#f5a623\" },\n avg: { label: \"Average\", type: \"color\", default: \"#787b86\" }\n }\n})\n\natrIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const values = atr(bars, params.length)\n\n return {\n atr: toPoints(ts, values),\n avg: params.smoothing >= 2 ? toPoints(ts, sma(values, params.smoothing)) : [],\n line: params.line,\n avgColor: params.avg\n }\n}\n\natrIndi.draw = function(s) {\n const out = [\n fillBetween(s.atr, 0, { mode: 'solid', color: s.line + '14' }),\n drawLine(s.atr, s.line, 2)\n ]\n\n if (s.avg.length) out.push(drawLine(s.avg, s.avgColor, 1, [4, 4]))\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const awesomeIndi = "\nconst awesome = plugin({\n name: \"Awesome Oscillator\",\n shortName: \"AO\",\n description: \"Fast minus slow median-price average\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 150,\n params: {\n fast: { label: \"Fast\", type: \"number\", default: 5, min: 1, max: 200 },\n slow: { label: \"Slow\", type: \"number\", default: 34, min: 2, max: 400 },\n up: { label: \"Rising\", type: \"color\", default: \"#26a69a\" },\n down: { label: \"Falling\", type: \"color\", default: \"#ef5350\" }\n }\n})\n\nawesome.init = function({ data, params }) {\n const bars = data.ohlcv\n const hl2 = bars.map(b => (b.high + b.low) / 2)\n const fast = sma(hl2, params.fast)\n const slow = sma(hl2, params.slow)\n\n const pts = []\n const colors = []\n let prev = NaN\n\n for (let i = 0; i < bars.length; i++) {\n const v = fast[i] - slow[i]\n if (isNaN(v)) continue\n pts.push({ t: bars[i].ts, price: v })\n colors.push(isNaN(prev) || v >= prev ? params.up : params.down)\n prev = v\n }\n\n return { pts, colors }\n}\n\nawesome.draw = function(s) {\n return [\n drawHistogram(s.pts, s.colors, 0, 0.25),\n drawHLine(0, \"#ffffff1f\", 1)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const bbIndi = "\nconst bollinger = plugin({\n name: \"Bollinger Bands\",\n shortName: \"BB\",\n description: \"Standard-deviation envelope around a moving average\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 120,\n params: {\n length: { label: \"Length\", type: \"number\", default: 20, min: 2, max: 500 },\n mult: { label: \"Std dev\", type: \"number\", default: 2, min: 0.1, max: 10, step: 0.1 },\n band: { label: \"Bands\", type: \"color\", default: \"#08b3de\" },\n basis: { label: \"Basis\", type: \"color\", default: \"#f5a623\" },\n fill: { label: \"Shade channel\", type: \"boolean\", default: true }\n }\n})\n\nbollinger.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const { upper, mid, lower } = bb(bars, params.length, params.mult)\n\n return {\n upper: toPoints(ts, upper),\n mid: toPoints(ts, mid),\n lower: toPoints(ts, lower),\n band: params.band,\n basis: params.basis,\n fill: params.fill\n }\n}\n\nbollinger.draw = function(s) {\n const out = []\n\n if (s.fill) {\n out.push(fillBetween(s.upper, s.lower, { mode: 'solid', color: s.band + '12' }))\n }\n\n out.push(drawLine(s.upper, s.band, 1))\n out.push(drawLine(s.lower, s.band, 1))\n out.push(drawLine(s.mid, s.basis, 1, [5, 4]))\n\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cciIndi = "\nconst cciIndi = plugin({\n name: \"Commodity Channel Index\",\n shortName: \"CCI\",\n description: \"Typical price against its mean deviation\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 100,\n params: {\n length: { label: \"Length\", type: \"number\", default: 20, min: 2, max: 300 },\n level: { label: \"Level\", type: \"number\", default: 100, min: 10, max: 400 },\n line: { label: \"CCI\", type: \"color\", default: \"#08b3de\" }\n }\n})\n\ncciIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const values = cci(bars, params.length)\n\n return {\n cci: toPoints(bars.map(b => b.ts), values),\n level: params.level,\n line: params.line\n }\n}\n\ncciIndi.draw = function(s) {\n return [\n fillBetween(s.level, -s.level, { mode: 'solid', color: '#ffffff08' }),\n drawHLine(s.level, \"#ffffff1f\", 1, [4, 4]),\n drawHLine(0, \"#ffffff12\", 1),\n drawHLine(-s.level, \"#ffffff1f\", 1, [4, 4]),\n drawLine(s.cci, s.line, 2)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cvdIndi = "\nconst cvd = plugin({\n name: \"Cumulative Volume Delta\",\n shortName: \"CVD\",\n description: \"Running aggressor imbalance, bucketed per bar\",\n type: PluginType.indicator,\n require: DataLevel.l3,\n layout: Layout.pane,\n version: \"1.0.0\",\n params: {\n up: { label: \"Rising\", type: \"color\", default: \"#26a69a\" },\n down: { label: \"Falling\", type: \"color\", default: \"#ef5350\" },\n deltaBars: { label: \"Per-bar delta\", type: \"checkbox\", default: true }\n }\n})\n\n// Trades arrive as { ts, price, size, side } - 'B' lifted the ask, 'A' hit the bid.\n// Everything is folded in place: only the bar the trade lands in is touched, and\n// draw() reads the arrays as they stand.\nfunction fold(state, trades) {\n for (const trade of trades) {\n const bar = state.barNs > 0n ? trade.ts / state.barNs * state.barNs : trade.ts\n const signed = trade.side === 'B' ? trade.size : -trade.size\n state.total += signed\n\n const i = state.pts.length - 1\n if (i >= 0 && state.pts[i].t === bar) {\n state.pts[i].price = state.total\n state.delta[i].price += signed\n } else {\n state.pts.push({ t: bar, price: state.total })\n state.delta.push({ t: bar, price: signed })\n state.lineColors.push(state.up)\n state.barColors.push(state.up)\n }\n\n const j = state.pts.length - 1\n state.lineColors[j] = j > 0 && state.pts[j].price < state.pts[j - 1].price ? state.down : state.up\n state.barColors[j] = state.delta[j].price >= 0 ? state.upFaded : state.downFaded\n }\n\n return state\n}\n\ncvd.init = function({ data, barNs, params }) {\n return fold({\n pts: [],\n delta: [],\n lineColors: [],\n barColors: [],\n total: 0,\n barNs,\n up: params.up,\n down: params.down,\n upFaded: params.up + '4d',\n downFaded: params.down + '4d',\n deltaBars: params.deltaBars\n }, data.trades)\n}\n\n// Only the trades since the last horizon step arrive here, so the running total\n// carries forward instead of being rebuilt from scratch.\ncvd.update = function({ newData, state }) {\n return { points: {}, state: fold(state, newData.trades) }\n}\n\ncvd.draw = function(s) {\n const out = []\n if (s.deltaBars) out.push(drawHistogram(s.delta, s.barColors, 0, 0.3))\n out.push(drawHLine(0, \"#ffffff1f\", 1))\n out.push(drawLine(s.pts, s.lineColors, 2))\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const donchianIndi = "\nconst donchianIndi = plugin({\n name: \"Donchian Channels\",\n shortName: \"DC\",\n description: \"Rolling highest high and lowest low\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 100,\n params: {\n length: { label: \"Length\", type: \"number\", default: 20, min: 2, max: 500 },\n upper: { label: \"Upper\", type: \"color\", default: \"#26a69a\" },\n lower: { label: \"Lower\", type: \"color\", default: \"#ef5350\" },\n showMid:{ label: \"Show midline\", type: \"checkbox\", default: true }\n }\n})\n\ndonchianIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const { upper, mid, lower } = donchian(bars, params.length)\n\n return {\n upper: toPoints(ts, upper),\n mid: params.showMid ? toPoints(ts, mid) : [],\n lower: toPoints(ts, lower),\n upperColor: params.upper,\n lowerColor: params.lower\n }\n}\n\ndonchianIndi.draw = function(s) {\n const out = [\n fillBetween(s.upper, s.lower, { mode: 'solid', color: '#ffffff08' }),\n drawLine(s.upper, s.upperColor, 1),\n drawLine(s.lower, s.lowerColor, 1)\n ]\n\n if (s.mid.length) out.push(drawLine(s.mid, '#787b86', 1, [4, 4]))\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ichimokuIndi = "\nconst ichimoku = plugin({\n name: \"Ichimoku Cloud\",\n shortName: \"ICH\",\n description: \"Tenkan, Kijun and the forward-projected kumo\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 200,\n params: {\n conversion: { label: \"Conversion\", type: \"number\", default: 9, min: 1, max: 200 },\n base: { label: \"Base\", type: \"number\", default: 26, min: 1, max: 400 },\n spanB: { label: \"Span B\", type: \"number\", default: 52, min: 1, max: 600 },\n displace: { label: \"Displacement\", type: \"number\", default: 26, min: 0, max: 200 },\n lagging: { label: \"Lagging span\", type: \"checkbox\", default: true }\n }\n})\n\nconst TENKAN = \"#08b3de\"\nconst KIJUN = \"#ef5350\"\nconst SPAN_A = \"#26a69a\"\nconst SPAN_B = \"#f5a623\"\nconst LAG = \"#9d8cd6\"\n\nfunction midChannel(highs, lows, period) {\n const hi = highest(highs, period)\n const lo = lowest(lows, period)\n const out = new Array(highs.length)\n for (let i = 0; i < out.length; i++) out[i] = (hi[i] + lo[i]) / 2\n return out\n}\n\nichimoku.init = function({ data, barNs, params }) {\n const bars = data.ohlcv\n const n = bars.length\n if (!n) return { tenkan: [], kijun: [], spanA: [], spanB: [], lagging: [], cloud: [] }\n\n const highs = bars.map(b => b.high)\n const lows = bars.map(b => b.low)\n\n const tenkan = midChannel(highs, lows, params.conversion)\n const kijun = midChannel(highs, lows, params.base)\n const spanBRaw = midChannel(highs, lows, params.spanB)\n const spanARaw = new Array(n)\n for (let i = 0; i < n; i++) spanARaw[i] = (tenkan[i] + kijun[i]) / 2\n\n // The kumo is plotted `displace` bars ahead, so the last stretch sits past\n // the newest bar - those timestamps have to be extrapolated from barNs.\n const shift = barNs > 0n ? params.displace : 0\n const tsAt = i => i < n ? bars[i].ts : bars[n - 1].ts + BigInt(i - n + 1) * barNs\n\n // Both spans are pushed together so the two arrays stay index-aligned -\n // cloudRuns pairs them positionally.\n const spanA = []\n const spanB = []\n for (let i = 0; i < n; i++) {\n if (isNaN(spanARaw[i]) || isNaN(spanBRaw[i])) continue\n const t = tsAt(i + shift)\n spanA.push({ t, price: spanARaw[i] })\n spanB.push({ t, price: spanBRaw[i] })\n }\n\n const lagging = []\n if (params.lagging) {\n for (let i = shift; i < n; i++) lagging.push({ t: bars[i - shift].ts, price: bars[i].close })\n }\n\n return {\n tenkan: toPoints(bars.map(b => b.ts), tenkan),\n kijun: toPoints(bars.map(b => b.ts), kijun),\n spanA,\n spanB,\n lagging,\n cloud: cloudRuns(spanA, spanB)\n }\n}\n\n// Split the kumo where A and B cross so each run can be filled on its own.\nfunction cloudRuns(spanA, spanB) {\n const len = spanA.length\n const runs = []\n let start = 0\n\n for (let i = 1; i < len; i++) {\n const before = spanA[i - 1].price >= spanB[i - 1].price\n if ((spanA[i].price >= spanB[i].price) === before) continue\n runs.push({ a: spanA.slice(start, i), b: spanB.slice(start, i), bullish: before })\n start = i\n }\n\n if (start < len) {\n runs.push({\n a: spanA.slice(start),\n b: spanB.slice(start),\n bullish: spanA[start].price >= spanB[start].price\n })\n }\n\n return runs\n}\n\nichimoku.draw = function(s) {\n const out = []\n\n for (const run of s.cloud) {\n out.push(fillBetween(run.a, run.b, {\n mode: 'solid',\n color: run.bullish ? SPAN_A + '20' : SPAN_B + '20'\n }))\n }\n\n out.push(drawLine(s.spanA, SPAN_A, 1))\n out.push(drawLine(s.spanB, SPAN_B, 1))\n out.push(drawLine(s.kijun, KIJUN, 1))\n out.push(drawLine(s.tenkan, TENKAN, 1))\n if (s.lagging.length) out.push(drawLine(s.lagging, LAG, 1, [3, 3]))\n\n return out\n}";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { alligatorIndi } from './alligator';
|
|
2
|
+
import { atrIndi } from './atr';
|
|
3
|
+
import { awesomeIndi } from './awesome-oscillator';
|
|
4
|
+
import { bbIndi } from './bollinger-bands';
|
|
5
|
+
import { cciIndi } from './cci';
|
|
6
|
+
import { cvdIndi } from './cvd';
|
|
7
|
+
import { donchianIndi } from './donchian';
|
|
8
|
+
import { ichimokuIndi } from './ichimoku';
|
|
9
|
+
import { keltnerIndi } from './keltner';
|
|
10
|
+
import { macdIndi } from './macd';
|
|
11
|
+
import { maIndi } from './moving-average';
|
|
12
|
+
import { mfiIndi } from './mfi';
|
|
13
|
+
import { obvIndi } from './obv';
|
|
14
|
+
import { psarIndi } from './psar';
|
|
15
|
+
import { rsiIndi } from './rsi';
|
|
16
|
+
import { sessionsIndi } from './sessions';
|
|
17
|
+
import { stochasticIndi } from './stochastic';
|
|
18
|
+
import { supertrendIndi } from './supertrend';
|
|
19
|
+
import { volumeIndi } from './volume';
|
|
20
|
+
import { vwapIndi } from './vwap';
|
|
21
|
+
import { williamsRIndi } from './williams-r';
|
|
22
|
+
/** [script, plugin id, picker category] */
|
|
23
|
+
export type BuiltinIndicatorEntry = readonly [code: string, id: string, category: string];
|
|
24
|
+
export declare const BUILTIN_INDICATORS: readonly BuiltinIndicatorEntry[];
|
|
25
|
+
export { alligatorIndi, atrIndi, awesomeIndi, bbIndi, cciIndi, cvdIndi, donchianIndi, ichimokuIndi, keltnerIndi, macdIndi, maIndi, mfiIndi, obvIndi, psarIndi, rsiIndi, sessionsIndi, stochasticIndi, supertrendIndi, volumeIndi, vwapIndi, williamsRIndi, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const keltnerIndi = "\nconst keltnerIndi = plugin({\n name: \"Keltner Channels\",\n shortName: \"KC\",\n description: \"ATR envelope around an exponential basis\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 150,\n params: {\n length: { label: \"Length\", type: \"number\", default: 20, min: 2, max: 500 },\n atrLength: { label: \"ATR length\", type: \"number\", default: 10, min: 1, max: 500 },\n mult: { label: \"Multiplier\", type: \"number\", default: 1.5, min: 0.1, max: 10, step: 0.1 },\n band: { label: \"Channel\", type: \"color\", default: \"#26a69a\" },\n basis: { label: \"Basis\", type: \"color\", default: \"#f5a623\" }\n }\n})\n\nkeltnerIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const { upper, mid, lower } = keltner(bars, params.length, params.atrLength, params.mult)\n\n return {\n upper: toPoints(ts, upper),\n mid: toPoints(ts, mid),\n lower: toPoints(ts, lower),\n band: params.band,\n basis: params.basis\n }\n}\n\nkeltnerIndi.draw = function(s) {\n return [\n fillBetween(s.upper, s.lower, { mode: 'solid', color: s.band + '10' }),\n drawLine(s.upper, s.band, 1),\n drawLine(s.lower, s.band, 1),\n drawLine(s.mid, s.basis, 1, [5, 4])\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const macdIndi = "\nconst macdIndi = plugin({\n name: \"MACD\",\n shortName: \"MACD\",\n description: \"Moving average convergence / divergence\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 200,\n params: {\n fast: { label: \"Fast\", type: \"number\", default: 12, min: 1, max: 400 },\n slow: { label: \"Slow\", type: \"number\", default: 26, min: 1, max: 600 },\n signal: { label: \"Signal\", type: \"number\", default: 9, min: 1, max: 200 },\n macdColor: { label: \"MACD\", type: \"color\", default: \"#08b3de\" },\n signalColor: { label: \"Signal\", type: \"color\", default: \"#f5a623\" }\n }\n})\n\nconst UP = \"#26a69a\"\nconst DOWN = \"#ef5350\"\n\nmacdIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const { macd: line, signal, histogram } = macd(bars, params.fast, params.slow, params.signal)\n\n // Four-tone histogram: shade by sign, brightness by whether it's growing.\n const hist = []\n const colors = []\n for (let i = 0; i < histogram.length; i++) {\n const v = histogram[i]\n if (isNaN(v)) continue\n const growing = i === 0 || isNaN(histogram[i - 1]) || Math.abs(v) >= Math.abs(histogram[i - 1])\n hist.push({ t: ts[i], price: v })\n colors.push((v >= 0 ? UP : DOWN) + (growing ? 'ff' : '66'))\n }\n\n return {\n line: toPoints(ts, line),\n signal: toPoints(ts, signal),\n hist,\n colors,\n macdColor: params.macdColor,\n signalColor: params.signalColor\n }\n}\n\nmacdIndi.draw = function(s) {\n return [\n drawHistogram(s.hist, s.colors, 0, 0.25),\n drawHLine(0, \"#ffffff1f\", 1),\n drawLine(s.line, s.macdColor, 2),\n drawLine(s.signal, s.signalColor, 1)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const mfiIndi = "\nconst mfiIndi = plugin({\n name: \"Money Flow Index\",\n shortName: \"MFI\",\n description: \"Volume-weighted RSI of the typical price\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 100,\n params: {\n length: { label: \"Length\", type: \"number\", default: 14, min: 2, max: 200 },\n overbought: { label: \"Overbought\", type: \"number\", default: 80, min: 50, max: 100 },\n oversold: { label: \"Oversold\", type: \"number\", default: 20, min: 0, max: 50 },\n line: { label: \"MFI\", type: \"color\", default: \"#26a69a\" }\n }\n})\n\nmfiIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n\n return {\n mfi: toPoints(bars.map(b => b.ts), mfi(bars, params.length)),\n overbought: params.overbought,\n oversold: params.oversold,\n line: params.line\n }\n}\n\nmfiIndi.draw = function(s) {\n return [\n fillBetween(s.overbought, s.oversold, { mode: 'solid', color: '#ffffff08' }),\n drawHLine(s.overbought, \"#ffffff1f\", 1, [4, 4]),\n drawHLine(s.oversold, \"#ffffff1f\", 1, [4, 4]),\n drawLine(s.mfi, s.line, 2)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const maIndi = "\nconst movingAverage = plugin({\n name: \"Moving Average\",\n shortName: \"MA\",\n description: \"Fast / slow pair, any method, any source\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 250,\n params: {\n method: { label: \"Method\", type: \"select\", default: \"EMA\", options: [\n { value: \"SMA\", label: \"Simple\" },\n { value: \"EMA\", label: \"Exponential\" },\n { value: \"WMA\", label: \"Weighted\" },\n { value: \"HMA\", label: \"Hull\" },\n { value: \"RMA\", label: \"Wilder\" }\n ] },\n source: { label: \"Source\", type: \"select\", default: \"close\", options: [\n { value: \"close\", label: \"Close\" },\n { value: \"open\", label: \"Open\" },\n { value: \"high\", label: \"High\" },\n { value: \"low\", label: \"Low\" },\n { value: \"hl2\", label: \"HL/2\" },\n { value: \"hlc3\", label: \"HLC/3\" },\n { value: \"ohlc4\", label: \"OHLC/4\" }\n ] },\n fast: { label: \"Fast\", type: \"number\", default: 21, min: 2, max: 1000 },\n slow: { label: \"Slow\", type: \"number\", default: 50, min: 0, max: 1000 },\n fastColor: { label: \"Fast\", type: \"color\", default: \"#08b3de\" },\n slowColor: { label: \"Slow\", type: \"color\", default: \"#f5a623\" },\n width: { label: \"Width\", type: \"stepperInt\", default: 2, min: 1, max: 4 }\n }\n})\n\nconst SOURCE = {\n close: b => b.close,\n open: b => b.open,\n high: b => b.high,\n low: b => b.low,\n hl2: b => (b.high + b.low) / 2,\n hlc3: b => (b.high + b.low + b.close) / 3,\n ohlc4: b => (b.open + b.high + b.low + b.close) / 4\n}\n\nconst METHOD = { SMA: sma, EMA: ema, WMA: wma, HMA: hma, RMA: rma }\n\nmovingAverage.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const src = bars.map(SOURCE[params.source] || SOURCE.close)\n const avg = METHOD[params.method] || ema\n\n return {\n fast: toPoints(ts, avg(src, params.fast)),\n slow: params.slow >= 2 ? toPoints(ts, avg(src, params.slow)) : [],\n fastColor: params.fastColor,\n slowColor: params.slowColor,\n width: params.width\n }\n}\n\nmovingAverage.draw = function(s) {\n const out = [drawLine(s.fast, s.fastColor, s.width)]\n if (s.slow.length) out.push(drawLine(s.slow, s.slowColor, s.width))\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const obvIndi = "\nconst obvIndi = plugin({\n name: \"On-Balance Volume\",\n shortName: \"OBV\",\n description: \"Running volume signed by the close\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 200,\n params: {\n smoothing: { label: \"Average\", type: \"number\", default: 20, min: 0, max: 500 },\n line: { label: \"OBV\", type: \"color\", default: \"#08b3de\" },\n avg: { label: \"Average\", type: \"color\", default: \"#f5a623\" }\n }\n})\n\nobvIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const values = obv(bars)\n\n return {\n obv: toPoints(ts, values),\n avg: params.smoothing >= 2 ? toPoints(ts, ema(values, params.smoothing)) : [],\n line: params.line,\n avgColor: params.avg\n }\n}\n\nobvIndi.draw = function(s) {\n const out = [drawLine(s.obv, s.line, 2)]\n if (s.avg.length) out.push(drawLine(s.avg, s.avgColor, 1))\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const psarIndi = "\nconst psar = plugin({\n name: \"Parabolic SAR\",\n shortName: \"SAR\",\n description: \"Accelerating stop-and-reverse dots\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 100,\n params: {\n step: { label: \"Step\", type: \"number\", default: 0.02, min: 0.001, max: 0.5, step: 0.001 },\n max: { label: \"Max step\", type: \"number\", default: 0.2, min: 0.01, max: 1, step: 0.01 },\n up: { label: \"Rising\", type: \"color\", default: \"#26a69a\" },\n down: { label: \"Falling\", type: \"color\", default: \"#ef5350\" },\n size: { label: \"Dot size\", type: \"stepperInt\", default: 2, min: 1, max: 6 }\n }\n})\n\npsar.init = function({ data, params }) {\n const bars = data.ohlcv\n const pts = []\n const colors = []\n if (bars.length < 2) return { pts, colors, size: params.size }\n\n let rising = bars[1].close >= bars[0].close\n let sar = rising ? bars[0].low : bars[0].high\n let extreme = rising ? bars[1].high : bars[1].low\n let accel = params.step\n\n for (let i = 1; i < bars.length; i++) {\n const bar = bars[i]\n sar = sar + accel * (extreme - sar)\n\n // The stop may never sit inside the last two bars' range.\n const prev = bars[i - 1]\n if (rising) {\n sar = Math.min(sar, prev.low, bars[i - 2] ? bars[i - 2].low : prev.low)\n } else {\n sar = Math.max(sar, prev.high, bars[i - 2] ? bars[i - 2].high : prev.high)\n }\n\n if (rising ? bar.low < sar : bar.high > sar) {\n rising = !rising\n sar = extreme\n extreme = rising ? bar.high : bar.low\n accel = params.step\n } else if (rising ? bar.high > extreme : bar.low < extreme) {\n extreme = rising ? bar.high : bar.low\n accel = Math.min(accel + params.step, params.max)\n }\n\n pts.push({ t: bar.ts, price: sar })\n colors.push(rising ? params.up : params.down)\n }\n\n return { pts, colors, size: params.size }\n}\n\npsar.draw = function(s) {\n return [drawDots(s.pts, s.colors, s.size)]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const rsiIndi = "\nconst rsiIndi = plugin({\n name: \"Relative Strength Index\",\n shortName: \"RSI\",\n description: \"Momentum oscillator with overbought / oversold zones\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 150,\n params: {\n length: { label: \"Length\", type: \"number\", default: 14, min: 2, max: 200 },\n smoothing: { label: \"Average\", type: \"number\", default: 14, min: 1, max: 200 },\n overbought:{ label: \"Overbought\", type: \"number\", default: 70, min: 50, max: 100 },\n oversold: { label: \"Oversold\", type: \"number\", default: 30, min: 0, max: 50 },\n line: { label: \"RSI\", type: \"color\", default: \"#7e57c2\" },\n signal: { label: \"Average\", type: \"color\", default: \"#f5a623\" }\n }\n})\n\nrsiIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const values = rsi(bars, params.length)\n\n return {\n rsi: toPoints(ts, values),\n ma: toPoints(ts, sma(values, params.smoothing)),\n overbought: params.overbought,\n oversold: params.oversold,\n line: params.line,\n signal: params.signal\n }\n}\n\nrsiIndi.draw = function(s) {\n const grid = \"#ffffff1f\"\n\n return [\n fillBetween(s.overbought, s.oversold, { mode: 'solid', color: s.line + '1a' }),\n\n // Gradients fade out at the threshold, so only the excursion past it shows.\n fillBetween(s.rsi, s.oversold, {\n mode: 'vertical',\n stops: [\n { price: s.oversold, color: 'rgba(239,83,80,0)' },\n { price: 0, color: 'rgba(239,83,80,0.55)' }\n ]\n }),\n fillBetween(s.overbought, s.rsi, {\n mode: 'vertical',\n stops: [\n { price: 100, color: 'rgba(38,166,154,0.55)' },\n { price: s.overbought, color: 'rgba(38,166,154,0)' }\n ]\n }),\n\n drawHLine(s.overbought, grid, 1, [4, 4]),\n drawHLine(50, \"#ffffff12\", 1, [4, 4]),\n drawHLine(s.oversold, grid, 1, [4, 4]),\n\n drawLine(s.ma, s.signal, 1),\n drawLine(s.rsi, s.line, 2)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sessionsIndi = "\nconst sessionsIndi = plugin({\n name: \"Trading Sessions\",\n shortName: \"SESS\",\n description: \"Asia / London / New York session ranges\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n params: {\n tz: { label: \"Timezone\", type: \"select\", default: \"UTC\", options: [\n { value: \"UTC\", label: \"UTC\" },\n { value: \"America/New_York\", label: \"New York\" },\n { value: \"Europe/London\", label: \"London\" },\n { value: \"Asia/Tokyo\", label: \"Tokyo\" }\n ] },\n asia: { label: \"Asia\", type: \"checkbox\", default: true },\n london: { label: \"London\", type: \"checkbox\", default: true },\n newYork: { label: \"New York\", type: \"checkbox\", default: true },\n labels: { label: \"Show labels\", type: \"checkbox\", default: true },\n opacity: { label: \"Shading\", type: \"opacity\", default: 12 }\n }\n})\n\nconst SESSIONS = [\n { key: \"asia\", label: \"Asia\", startHour: 0, startMinute: 0, endHour: 9, endMinute: 0, color: \"#7e57c2\" },\n { key: \"london\", label: \"London\", startHour: 7, startMinute: 0, endHour: 16, endMinute: 0, color: \"#08b3de\" },\n { key: \"newYork\", label: \"New York\", startHour: 13, startMinute: 30, endHour: 22, endMinute: 0, color: \"#f5a623\" }\n]\n\nfunction alpha(hex, percent) {\n const a = Math.round(Math.max(0, Math.min(100, percent)) * 2.55)\n return hex + a.toString(16).padStart(2, '0')\n}\n\nsessionsIndi.init = function({ data, params }) {\n const active = SESSIONS.filter(s => params[s.key])\n const bands = active.length\n ? sessionBoundaries(data.ohlcv, active, { tz: params.tz })\n : []\n\n return { bands, labels: params.labels, opacity: params.opacity }\n}\n\nsessionsIndi.draw = function(s) {\n const out = []\n\n for (const band of s.bands) {\n out.push(drawRect(band.startTs, band.low, band.endTs, band.high, {\n fillColor: alpha(band.color, s.opacity),\n borderColor: alpha(band.color, 55),\n radius: 3\n }))\n\n if (s.labels) {\n out.push(drawLabel(band.label, band.startTs, band.high, band.color, 10, true, 'left', 'bottom'))\n }\n }\n\n return out\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const stochasticIndi = "\nconst stochastic = plugin({\n name: \"Stochastic\",\n shortName: \"STOCH\",\n description: \"Close relative to the recent high / low range\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n layout: Layout.pane,\n version: \"1.0.0\",\n lookback: 100,\n params: {\n k: { label: \"%K length\", type: \"number\", default: 14, min: 1, max: 200 },\n smooth: { label: \"%K smoothing\", type: \"number\", default: 3, min: 1, max: 50 },\n d: { label: \"%D length\", type: \"number\", default: 3, min: 1, max: 50 },\n overbought: { label: \"Overbought\", type: \"number\", default: 80, min: 50, max: 100 },\n oversold: { label: \"Oversold\", type: \"number\", default: 20, min: 0, max: 50 },\n kColor: { label: \"%K\", type: \"color\", default: \"#08b3de\" },\n dColor: { label: \"%D\", type: \"color\", default: \"#f5a623\" }\n }\n})\n\nstochastic.init = function({ data, params }) {\n const bars = data.ohlcv\n const ts = bars.map(b => b.ts)\n const { k, d } = stoch(bars, params.k, params.d, params.smooth)\n\n return {\n k: toPoints(ts, k),\n d: toPoints(ts, d),\n overbought: params.overbought,\n oversold: params.oversold,\n kColor: params.kColor,\n dColor: params.dColor\n }\n}\n\nstochastic.draw = function(s) {\n return [\n fillBetween(s.overbought, s.oversold, { mode: 'solid', color: '#ffffff08' }),\n drawHLine(s.overbought, \"#ffffff1f\", 1, [4, 4]),\n drawHLine(s.oversold, \"#ffffff1f\", 1, [4, 4]),\n drawLine(s.d, s.dColor, 1),\n drawLine(s.k, s.kColor, 2)\n ]\n}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const supertrendIndi = "\nconst supertrendIndi = plugin({\n name: \"Supertrend\",\n shortName: \"ST\",\n description: \"ATR trailing stop that flips with the trend\",\n type: PluginType.indicator,\n require: DataLevel.ohlcv,\n version: \"1.0.0\",\n lookback: 150,\n params: {\n length: { label: \"ATR length\", type: \"number\", default: 10, min: 1, max: 200 },\n mult: { label: \"Multiplier\", type: \"number\", default: 3, min: 0.1, max: 20, step: 0.1 },\n up: { label: \"Uptrend\", type: \"color\", default: \"#26a69a\" },\n down: { label: \"Downtrend\", type: \"color\", default: \"#ef5350\" },\n markers:{ label: \"Flip markers\", type: \"checkbox\", default: true }\n }\n})\n\nsupertrendIndi.init = function({ data, params }) {\n const bars = data.ohlcv\n const { trend, upper, lower } = supertrend(bars, params.length, params.mult)\n\n // One continuous stop line; colour is per-point so the flip shows in place.\n const pts = []\n const colors = []\n const flips = []\n\n for (let i = 0; i < bars.length; i++) {\n const up = trend[i] === 1\n const value = up ? lower[i] : upper[i]\n if (isNaN(value)) continue\n\n pts.push({ t: bars[i].ts, price: value })\n colors.push(up ? params.up : params.down)\n\n if (i > 0 && trend[i] !== trend[i - 1]) {\n flips.push({ t: bars[i].ts, price: value, up })\n }\n }\n\n return { pts, colors, flips, up: params.up, down: params.down, markers: params.markers }\n}\n\nsupertrendIndi.draw = function(s) {\n const out = [drawLine(s.pts, s.colors, 2)]\n\n if (s.markers) {\n for (const f of s.flips) {\n out.push(drawLabel(f.up ? '\u25B2' : '\u25BC', f.t, f.price, f.up ? s.up : s.down, 11, true, 'center', f.up ? 'top' : 'bottom'))\n }\n }\n\n return out\n}";
|