Skip to content

Risk Management

Multi-layer risk management: pre-trade checks, position monitoring, and account-level controls.

Pre-Trade Pipeline

Validates every order before it reaches the exchange:

ts
import { Pipeline, riskProviderFor } from "@nemesis-oss/dhanhq-sdk";

const pipeline = new Pipeline({
  provider: riskProviderFor(client),
  limits: { maxQuantity: 50, dailyMaxLoss: 25_000 },
});

// Throws RiskViolationError on first failure
await pipeline.run({ args: order, instrument });

// Collect all violations for preview
const { passed, violations } = await pipeline.report({ args: order, instrument });

Checks cover:

  • Trading permission (exchange open/close)
  • ASM/GSM restriction status
  • Product support for the instrument
  • Order type validity
  • Quantity and notional limits
  • Market hours (NSE/BSE)
  • Position count limits
  • Single-symbol concentration
  • Daily loss threshold
  • Options-specific rules (lot size, strike validity)

These checks are NSE/BSE-specific and do not apply to Global Stocks.

Position Monitor

Real-time exit signals driven by WebSocket ticks:

ts
import { PositionMonitor } from "@nemesis-oss/dhanhq-sdk";

const monitor = new PositionMonitor();

client.ws.market.on("tick", (tick) => monitor.onTick(tick));

monitor.track({
  securityId: "2885",
  exchangeSegment: "NSE_EQ",
  quantity: 100,
  entryPrice: 1400,
  stopLoss: 1386,
  target: 1428,
  trail: { atr: 7, multiplier: 2 },
});

monitor.on("exit", (signal) => {
  console.log(signal.reason, signal.pnl);
  // reason: "stop_loss" | "target" | "trailing_stop"
});

PositionMonitor only decides — it never places an order.

Account-Level Controls

ts
// Auto-square-off at profit/loss thresholds
await client.traderControls.setPnlExit({
  profitValue: 5_000,
  lossValue: 2_500,
  enableKillSwitch: true,
});

// Emergency block
await client.traderControls.setKillSwitch("ACTIVATE");

Position Sizing

Pure functions — no API access needed for planning:

ts
import { fixedRiskSize, volatilitySize, kellySize } from "@nemesis-oss/dhanhq-sdk";

// Fixed-percent risk: quantity such that a stop-out costs 2% of the account
const size = fixedRiskSize({
  accountBalance: 1_000_000,
  riskPercent: 2,
  entryPrice: 100,
  stopLossPrice: 95,
});

// Same idea, but the stop distance comes from ATR
const atrSize = volatilitySize({
  accountBalance: 1_000_000,
  riskPercent: 2,
  entryPrice: 100,
  atr: 7,
  atrMultiplier: 2,
});

// Half-Kelly, scaled by historical win rate and average win/loss
const kelly = kellySize({
  winRate: 0.55,
  avgWin: 8,
  avgLoss: 5,
  accountBalance: 1_000_000,
  entryPrice: 100,
});

Trailing Stops

TrailManager ratchets a stop up with the high-water mark and never moves it down:

ts
import { TrailManager, atrStop, percentageStop } from "@nemesis-oss/dhanhq-sdk";

// Initial stop placement
const initialStop = atrStop(100, 7, 2);        // ATR-based
const percentStop = percentageStop(100, 2);    // fixed 2% below entry

// Then feed live prices in as they arrive
const trail = new TrailManager(100, initialStop, 7, 2);
const update = trail.update(112);
console.log(update.stop, update.highest, update.triggered);

Community project — not affiliated with Dhan. MIT License.