shape-runtime 0.3.1

Bytecode compiler, builtins, and runtime infrastructure for Shape
Documentation
/// @module std::finance::backtest::state
/// Backtest State Types
///
/// Core state types for backtesting simulations using the high-performance
/// simulation engine (simulate() and simulate_correlated()).

// ===== Backtest State =====

/// Core state tracked during a backtest simulation
/// All monetary values are in account currency
pub type BacktestState = {
    // Portfolio state
    cash: number;           // Available cash
    position: number;       // Current position size (positive = long, negative = short)
    entry_price: number;    // Average entry price of current position
    equity: number;         // Total equity (cash + position value)

    // Trade statistics
    trades: number;         // Total number of completed trades
    wins: number;           // Number of winning trades
    losses: number;         // Number of losing trades

    // Drawdown tracking
    peak_equity: number;    // Highest equity achieved
    max_drawdown: number;   // Maximum drawdown seen (as decimal, e.g., 0.15 = 15%)

    // P&L tracking
    total_pnl: number;      // Total realized P&L
    unrealized_pnl: number; // Unrealized P&L on open position
};

/// Create initial backtest state with given capital
pub fn initial_state(capital = 100000.0) {
    {
        cash: capital,
        position: 0.0,
        entry_price: 0.0,
        equity: capital,
        trades: 0,
        wins: 0,
        losses: 0,
        peak_equity: capital,
        max_drawdown: 0.0,
        total_pnl: 0.0,
        unrealized_pnl: 0.0
    }
}

// ===== Order Types =====

/// Order request generated by strategy
pub type Order = {
    side: string;           // "buy" | "sell"
    quantity: number;       // Number of units
    price: number;          // Limit price (0 for market order)
    order_type: string;     // "market" | "limit" | "stop"
    stop_loss: number;      // Stop loss price (0 = none)
    take_profit: number;    // Take profit price (0 = none)
};

/// Create a market buy order
pub fn market_buy(quantity, stop_loss = 0.0, take_profit = 0.0) {
    {
        side: "buy",
        quantity: quantity,
        price: 0.0,
        order_type: "market",
        stop_loss: stop_loss,
        take_profit: take_profit
    }
}

/// Create a market sell order
pub fn market_sell(quantity, stop_loss = 0.0, take_profit = 0.0) {
    {
        side: "sell",
        quantity: quantity,
        price: 0.0,
        order_type: "market",
        stop_loss: stop_loss,
        take_profit: take_profit
    }
}

/// Create a limit buy order
pub fn limit_buy(quantity, price, stop_loss = 0.0, take_profit = 0.0) {
    {
        side: "buy",
        quantity: quantity,
        price: price,
        order_type: "limit",
        stop_loss: stop_loss,
        take_profit: take_profit
    }
}

/// Create a limit sell order
pub fn limit_sell(quantity, price, stop_loss = 0.0, take_profit = 0.0) {
    {
        side: "sell",
        quantity: quantity,
        price: price,
        order_type: "limit",
        stop_loss: stop_loss,
        take_profit: take_profit
    }
}

// ===== Position Helpers =====

/// Check if we have a long position
pub fn is_long(state) {
    state.position > 0
}

/// Check if we have a short position
pub fn is_short(state) {
    state.position < 0
}

/// Check if we have no position
pub fn is_flat(state) {
    state.position == 0
}

/// Get absolute position size
pub fn position_size(state) {
    abs(state.position)
}

/// Calculate current win rate (0-1)
pub fn win_rate(state) {
    if state.trades == 0 {
        0.0
    } else {
        state.wins / state.trades
    }
}

/// Calculate profit factor (gross profit / gross loss)
/// Returns infinity representation (999999) if no losses
pub fn profit_factor(state) {
    // Note: Would need separate gross_profit/gross_loss tracking
    // This is a simplified version based on win/loss counts
    if state.losses == 0 {
        999999.0
    } else if state.wins == 0 {
        0.0
    } else {
        state.wins / state.losses
    }
}