11 / 12Prism Systems · FinTech & Banking
Backtests that tell you when they're lying
An event-driven strategy backtester: strategies see one bar at a time and fill at the next open. It models NSE delivery and intraday charges, square-root market impact, participation caps, gap-aware stops, position and gross limits, and a drawdown kill switch. Parameter sweeps report a deflated Sharpe ratio, walk-forward analysis keeps tests out of sample, and Monte Carlo bootstraps the returns.
A live market, a strategy trading it, and a check on whether to believe the results
A synthetic NSE-like market prints a new daily bar six times a second. Pick a strategy and a symbol, drag its parameters, and the entire history replays instantly with the new settings. Trigger a crash, rally or choppy market, add a stop or kill switch, or turn on look-ahead to see how much a peek is worth. Sweep the parameters to see if the best result survives deflation, and bootstrap the returns to see the range of outcomes.
What's inside the engine
Real algorithms, not mock-ups. The simulator above runs the exact same code you import.
No look-ahead by construction
Bars are fed one at a time, so ctx.hist() can only return the past. Orders decided on bar i fill at bar i+1's open. Same-bar close fills exist only as an explicit opt-in (fill: "close"), so you can measure the bias.
Indian cost model
NSE delivery and intraday schedules: brokerage (with a ₹20 cap for intraday), STT, exchange transaction charges, the SEBI fee, buy-side stamp duty, GST on fees and the DP charge on delivery sells. Flat-bps and zero-cost options are included too.
Market impact + capacity
Half-spread plus k·σ·√(qty / volume) square-root impact, using each symbol's own rolling volatility. Fills are capped at 10% of a bar's volume, so you can watch a strategy stop working as the account grows.
Risk between strategy and market
Position and gross exposure limits scale requests down, shorts can be disabled, and the engine can set fixed or trailing stops. Stops fill at the stop price, or at the open when price gaps through them. A drawdown kill switch liquidates and halts trading.
Seven strategies
SMA crossover, RSI mean reversion with a trend filter, Bollinger reversion, Donchian breakout with ATR risk sizing, cross-sectional momentum with an absolute filter, rolling-OLS pairs trading, and buy and hold. Custom strategies need only onBar(ctx).
Statistics that matter
CAGR, volatility, Sharpe, Sortino, Calmar, maximum drawdown and its duration, historical VaR and CVaR, beta and alpha, win rate, profit factor, expectancy, MAE and MFE, exposure, turnover, costs and monthly returns.
Overfitting checks
The probabilistic Sharpe ratio corrects for sample length, skew and fat tails. The deflated Sharpe ratio compares the best sweep result with what the luckiest of N random strategies would show. Walk-forward analysis reports in-sample against out-of-sample efficiency.
CLI + HTTP API
demo, run, sweep (with an ASCII heatmap), walkforward, montecarlo, costs, strategies, data, bench and serve. The API exposes POST /v1/backtest, /v1/sweep, /v1/walkforward and /v1/montecarlo, with synthetic or uploaded CSV data.
From request to result
Feed
Each date's bars are appended to per-symbol history. Rolling volatility is updated for the impact model, and symbols missing on a date carry their last close.
Fill
Orders from yesterday's decision fill at today's open after slippage and the participation cap. Stops are then checked against today's range and are gap-aware.
Mark
Positions are marked at the close, short borrow and optional cash interest are charged, trailing stops ratchet, and each trade's excursions are tracked.
Decide
The strategy sees bars up to today and states target weights. The engine clamps them to the position and gross limits, rejects disallowed shorts, applies a rebalance band and queues the difference as orders.
Judge
Equity, drawdown and trades become statistics. Sweeps, walk-forward runs and bootstraps then ask whether the result would survive outside this one sample.
System design
Every box is a module in src/. Data flows left to right.
Ship it in your own stack
Zero dependencies. Works in Node.js 18+ and modern browsers.
import { backtest, sweep, walkForward, monteCarlo, generate, parseCSV, GRIDS } from "prism-backtest";
const data = { BANKX: generate({ seed: 6, years: 6 }).BANKX }; // or { RELIANCE: parseCSV(fs.readFileSync("RELIANCE.csv", "utf8")) }
const r = backtest(data, {
strategy: "sma-cross", params: { fast: 20, slow: 50 },
cash: 10_00_000, costs: "india-delivery", // STT, stamp duty, exchange + SEBI fees, GST, DP charge
slippage: { model: "sqrt", k: 0.6, spreadBps: 2 }, // half spread + square-root impact
risk: { stopLoss: 0.08, maxPos: 1, ddHalt: 0.25 }, // gap-aware stop, kill switch at -25%
});
r.metrics; // { cagr, sharpe, sortino, maxDD, calmar, var95, winRate, profitFactor, psr, fees, slippage, ... }
r.trades; // [{ sym, side, entryD, exitD, entry, exit, pnl, ret, mae, mfe, exitTag }]
const s = sweep(data, { strategy: "sma-cross", grid: GRIDS["sma-cross"] });
s.best; s.dsr; // deflated Sharpe after s.trials combinations
const wf = walkForward(data, { strategy: "sma-cross", grid: GRIDS["sma-cross"], train: 504, test: 126 });
wf.isSharpe; wf.oos.sharpe; wf.efficiency; // in-sample vs out-of-sample
const mc = monteCarlo(r, { runs: 1000, block: 10 });
mc.final[0.05]; mc.maxDD[0.95]; mc.pLoss;
// your own strategy: state target weights, the engine does the rest
const myStrategy = { onBar(ctx) { const c = ctx.close("BANKX"), c20 = ctx.close("BANKX", 20); if (c20) ctx.target("BANKX", c > c20 ? 1 : 0); } };
backtest(data, { strategy: myStrategy });$ npx github:krishyaa06/prism-backtest demo
$ npx github:krishyaa06/prism-backtest run --strategy donchian --symbols BANKX --trades
$ npx github:krishyaa06/prism-backtest run --strategy rsi-revert --csv RELIANCE.csv --costs india-delivery
$ npx github:krishyaa06/prism-backtest sweep --strategy sma-cross
$ npx github:krishyaa06/prism-backtest walkforward --strategy sma-cross --train 504 --test 126
$ npx github:krishyaa06/prism-backtest montecarlo --runs 2000
$ npx github:krishyaa06/prism-backtest costs --value 100000
$ npx github:krishyaa06/prism-backtest serve --port 8789# use the CLI without installing
$ npx github:krishyaa06/prism-backtest --help
# or add the engine to your project
$ npm install github:krishyaa06/prism-backtest
# run the simulator locally
$ git clone https://github.com/krishyaa06/prism-backtest.git && cd prism-backtest
$ npx serve . # then open http://localhost:3000