Module Algostream_risk_management.Risk_limits

Configurable risk limits + pre-trade breach detection.

Pure-function check: callers feed the current portfolio + a proposed order, get back a list of breaches (empty when within limits). The new layer never mutates anything — strategies decide whether to block the order or proceed.

Path-dependent limits

Drawdown and daily loss cannot be computed from a portfolio snapshot: both need history the snapshot does not carry. Rather than give this module state, pre_trade_check takes them as scalars and the caller owns the tracking — Drawdown.Tracker already does exactly this, and both call sites (Algostream_backtest.Engine and Algostream_runtime.Instance) hold one.

The thresholds are compared the same way Monitor.update compares them, so the pre-trade gate and the monitoring snapshot cannot disagree about whether a limit is breached.

type t = {
  1. max_drawdown : float;
    (*

    fractional, positive; gate + Monitor

    *)
  2. max_daily_loss : float;
    (*

    fractional, positive; gate + Monitor

    *)
  3. max_leverage : float;
  4. max_var_pct : float;
    (*

    Monitor only. A VaR gate needs a return distribution, which the pre-trade path does not have.

    *)
  5. max_position_concentration : float;
  6. max_gross_exposure : float;
    (*

    gate only

    *)
  7. correlation_breakdown_threshold : float;
}
val default : t
type breach =
  1. | Drawdown of {
    1. current : float;
    2. limit : float;
    }
  2. | Daily_loss of {
    1. current : float;
    2. limit : float;
    }
  3. | Leverage of {
    1. current : float;
    2. limit : float;
    }
  4. | Var of {
    1. current : float;
    2. limit : float;
    }
  5. | Position_concentration of {
    1. symbol : string;
    2. current : float;
    3. limit : float;
    }
  6. | Gross_exposure of {
    1. current : float;
    2. limit : float;
    }
val pre_trade_check : t -> portfolio:Portfolio.portfolio -> proposed_order:Order.order -> ?proposed_price:float -> ?current_drawdown:float -> ?daily_pnl_pct:float -> unit -> breach list

Breaches for the proposed order, empty when it is within every limit.

current_drawdown is the fractional drop from the running equity peak, positive, as Drawdown.Tracker.current_drawdown returns it. daily_pnl_pct is a signed fractional return over the accounting day, so a loss is negative. Both default to 0.0 — i.e. omitting them disables those two checks rather than tripping them.

val breach_to_string : breach -> string