@nemesis-oss/pine-ts
v0.1.1
Published
Pine Script v6-inspired trading runtime and API for TypeScript trading systems
Readme
pine-ts
Pine Script v6-inspired trading runtime for TypeScript.
pine-ts is designed to let TypeScript trading bots use a Pine-like API (ta.*, math.*, request.*, strategy.*, series/history semantics, bar state, plotting, alerts, and collections) while obtaining market data through pluggable providers. Binance is the first-class provider via @nemesis-oss/binance-sdk.
Project status
Early foundation. The repository is intentionally starting with the runtime contracts and deterministic series/technical-analysis core before implementing the full Pine v6 surface.
Goals
- Pine v6-compatible developer ergonomics where practical.
- Deterministic historical bar-by-bar execution.
- Realtime execution with explicit confirmed/unconfirmed bar state.
- History references such as
close[1]. - Incremental indicator state rather than repeated whole-array scans.
request.security()-style multi-symbol/timeframe contexts.- Strategy/backtest/paper/live broker separation.
- Chart/rendering adapters independent of the runtime core.
- Binance REST/WebSocket integration through
@nemesis-oss/binance-sdk. - DhanHQ (NSE/BSE) integration through
@nemesis-oss/dhanhq-sdk. - Machine-readable API manifest to track Pine reference coverage.
Non-goals
pine-ts does not pretend Binance can provide every TradingView dataset. Provider-specific capabilities will be explicit errors rather than fabricated values.
Architecture
Trading Bot
|
v
@nemesis-oss/pine-ts
|
+-- Core runtime / execution / series / state
+-- ta.* / math.* / collections / strings / colors
+-- request.* / timeframe / sessions
+-- strategy.* / broker interface / backtesting
+-- plotting / drawing / alerts
|
+--> BinanceProvider --> @nemesis-oss/binance-sdk
|
+--> Renderer adaptersUsage
import { BinanceClient } from "@nemesis-oss/binance-sdk";
import { BinanceProvider, PineRuntime, ta, type PineScript } from "@nemesis-oss/pine-ts";
const client = new BinanceClient();
const provider = new BinanceProvider({ market: client.spot.market, socket: client.spot.ws });
const runtime = new PineRuntime({ provider, symbol: "BTCUSDT", timeframe: "15" });
const script: PineScript = (ctx) => {
const fast = ta.ema(ctx.close, 9);
const slow = ta.ema(ctx.close, 21);
// Each ctx.scope id is an independent Pine call site with its own state.
const trend = ctx.scope("trend", () => ta.sma(ctx.close, 50));
if (ctx.barstate.isconfirmed && ta.crossover(fast, slow).value) {
console.log("cross up", ctx.close.value, trend.value);
}
};
await runtime.run(script); // historical bars; a still-forming last kline runs as the open realtime bar
await runtime.runRealtime(script); // continues on the kline streamDhanHQ (NSE/BSE)
import { DhanClient } from "@nemesis-oss/dhanhq-sdk";
import { DhanHQProvider, PineRuntime } from "@nemesis-oss/pine-ts";
const client = DhanClient.fromEnv();
const provider = new DhanHQProvider({
charts: client.charts,
instruments: client.instruments,
feed: client.ws.market,
});
await client.ws.connect(); // the caller owns the socket
// Symbols are "<exchangeSegment>:<securityId>" composite keys.
const runtime = new PineRuntime({ provider, symbol: "IDX_I:13", timeframe: "15" });
await runtime.run(script);
await runtime.runRealtime(script);Bars are anchored to the session open (NSE 09:15 IST), matching TradingView.
Historical minute bars are built from 1-minute candles and realtime bars from
trade ticks with the same bucketing, so both agree on bar boundaries. A bar
closes on the first tick of the next bucket or closeGraceMs after its bucket
ends.
Neither SDK is a runtime dependency: the providers consume their surfaces structurally, and the tests type-check the real SDK classes against them.
Community scripts
community.* holds faithful ports of open-source TradingView scripts, checked
bar for bar against a literal transcription of the published Pine source.
import { community, ta } from "@nemesis-oss/pine-ts";
const script: PineScript = (ctx) => {
// Machine Learning Adaptive SuperTrend [AlgoAlpha]
const st = community.mlAdaptiveSupertrend({ atrLength: 10, factor: 3, trainingPeriod: 100 });
const bullish = ta.crossunder(
st.direction,
ctx.series("zero", () => 0),
).value;
};direction follows Pine's SuperTrend convention: -1 is an uptrend, 1 a
downtrend.
Development
Requires Node.js 22+.
corepack enable
pnpm install
pnpm build
pnpm test
pnpm typecheckExamples
Runnable examples use local sample data and do not require exchange credentials:
pnpm exec tsx examples/historical-sma-crossover.ts
pnpm exec tsx examples/realtime-bar-updates.ts
pnpm exec tsx examples/simple-backtest-loop.ts
pnpm exec tsx examples/rsi-momentum-filter.tsThe first example detects SMA crossover signals from historical bars. The second shows how repeated updates to a realtime bar are evaluated before confirmation. The third runs a simulated trade backtest tracking cash, positions, and net PnL. The fourth demonstrates combining an RSI oscillator with an EMA trend filter.
Roadmap
See docs/ROADMAP.md, docs/ARCHITECTURE.md, docs/SEMANTICS.md, and docs/COMPATIBILITY.md. The runtime's execution semantics — series state machine, node rollback/commit contract, var/varip lifecycle, na model, and the four executable invariants (determinism, replay equivalence, truncation equivalence, chunk invariance) — are specified in docs/SEMANTICS.md.
License
MIT, except src/community/ml-adaptive-supertrend.ts, a port of AlgoAlpha's
"Machine Learning Adaptive SuperTrend", which stays under the Mozilla Public
License 2.0 of the original script (see the file header). The package license
is therefore MIT AND MPL-2.0.
