ZenQuant.Sizing (zen_quant v0.2.0)

Copy Markdown View Source

Position sizing calculations for trading systems.

Pure functions for calculating position sizes based on risk parameters, account size, and volatility. Supports multiple sizing strategies.

Example

# Fixed fractional sizing (risk 1% of account)
ZenQuant.Sizing.fixed_fractional(100_000, 0.01, 500)
# => 2.0  (2 units where each unit has $500 max loss)

# Kelly criterion
ZenQuant.Sizing.kelly(0.55, 1.5)
# => 0.183  (18.3% of bankroll)

API Functions

FunctionArityDescriptionParam Kinds
optimal_f1Calculate Ralph Vince's optimal fixed fraction from trade history.trades: value
anti_martingale4Calculate anti-martingale position adjustment.base_size: value, consecutive_wins: value
volatility_scaled4Calculate position size scaled by volatility.account_size: value, risk_percent: value, current_volatility: value, target_volatility: value
kelly3Calculate optimal position size using Kelly criterion.win_rate: value, win_loss_ratio: value
max_loss2Calculate position size based on maximum loss amount.max_loss_amount: value, stop_distance: value
fixed_fractional3Calculate position size using fixed fractional method.account_size: value, risk_percent: value, stop_distance: value

Summary

Types

Fraction of bankroll (0.0 to 1.0)

Position size in units or currency

Functions

Calculate position size using fixed fractional method.

Calculate optimal position size using Kelly criterion.

Calculate position size based on maximum loss amount.

Calculate Ralph Vince's optimal fixed fraction from trade history.

Types

fraction()

@type fraction() :: float()

Fraction of bankroll (0.0 to 1.0)

position_size()

@type position_size() :: float()

Position size in units or currency

Functions

anti_martingale(base_size, consecutive_wins, scale_factor \\ 0.25, max_scale \\ 2.0)

@spec anti_martingale(number(), integer(), fraction(), float()) :: position_size()

Calculate anti-martingale position adjustment.

Parameters

  • base_size - Starting position size (value)
  • consecutive_wins - Number of consecutive wins (negative for losses) (value)

Options

  • scale_factor - Adjustment per win/loss (0.25 = 25%) (default: 0.25)
  • max_scale - Maximum multiplier cap (default: 2.0)

Returns

Adjusted position size (float)

Example

0.1095
# descripex:contract
%{
  opts: %{
    scale_factor: %{
      default: 0.25,
      type: :float,
      description: "Adjustment per win/loss (0.25 = 25%)"
    },
    max_scale: %{
      default: 2.0,
      type: :float,
      description: "Maximum multiplier cap"
    }
  },
  params: %{
    base_size: %{description: "Starting position size", kind: :value},
    consecutive_wins: %{
      description: "Number of consecutive wins (negative for losses)",
      kind: :value
    }
  },
  returns: %{type: :float, description: "Adjusted position size"},
  returns_example: 0.1095
}

fixed_fractional(account_size, risk_percent, stop_distance)

@spec fixed_fractional(number(), fraction(), number()) :: position_size()

Calculate position size using fixed fractional method.

Parameters

  • account_size - Total account equity (value)
  • risk_percent - Risk per trade as decimal (e.g., 0.01 = 1%) (value)
  • stop_distance - Distance to stop loss in account currency per unit (value)

Returns

Position size in units (e.g., contracts) (float)

Example

0.1095
# descripex:contract
%{
  params: %{
    account_size: %{description: "Total account equity", kind: :value},
    risk_percent: %{
      description: "Risk per trade as decimal (e.g., 0.01 = 1%)",
      kind: :value
    },
    stop_distance: %{
      description: "Distance to stop loss in account currency per unit",
      kind: :value
    }
  },
  returns: %{
    type: :float,
    description: "Position size in units (e.g., contracts)"
  },
  returns_example: 0.1095
}

kelly(win_rate, win_loss_ratio, kelly_fraction \\ 0.5)

@spec kelly(fraction(), float(), fraction()) :: fraction()

Calculate optimal position size using Kelly criterion.

Parameters

  • win_rate - Probability of winning (0.0 to 1.0) (value)
  • win_loss_ratio - Average win divided by average loss (value)

Options

  • kelly_fraction - Fraction of Kelly to use (0.5 = half Kelly) (default: 0.5)

Returns

Optimal bet size as fraction of bankroll, 0.0 if negative EV (float)

Example

0.1095
# descripex:contract
%{
  opts: %{
    kelly_fraction: %{
      default: 0.5,
      type: :float,
      description: "Fraction of Kelly to use (0.5 = half Kelly)"
    }
  },
  params: %{
    win_rate: %{
      description: "Probability of winning (0.0 to 1.0)",
      kind: :value
    },
    win_loss_ratio: %{
      description: "Average win divided by average loss",
      kind: :value
    }
  },
  returns: %{
    type: :float,
    description: "Optimal bet size as fraction of bankroll, 0.0 if negative EV"
  },
  returns_example: 0.1095
}

max_loss(max_loss_amount, stop_distance)

@spec max_loss(number(), number()) :: position_size()

Calculate position size based on maximum loss amount.

Parameters

  • max_loss_amount - Maximum acceptable loss in account currency (value)
  • stop_distance - Distance to stop loss per unit (value)

Returns

Position size in units (float)

Example

0.1095
# descripex:contract
%{
  params: %{
    stop_distance: %{
      description: "Distance to stop loss per unit",
      kind: :value
    },
    max_loss_amount: %{
      description: "Maximum acceptable loss in account currency",
      kind: :value
    }
  },
  returns: %{type: :float, description: "Position size in units"},
  returns_example: 0.1095
}

optimal_f(trades)

@spec optimal_f([number()]) :: fraction() | nil

Calculate Ralph Vince's optimal fixed fraction from trade history.

Parameters

  • trades - List of trade results (positive for wins, negative for losses) (value)

Returns

Optimal fraction of account to risk per trade, or nil if insufficient data (float)

Example

0.1095
# descripex:contract
%{
  params: %{
    trades: %{
      description: "List of trade results (positive for wins, negative for losses)",
      kind: :value
    }
  },
  returns: %{
    type: :float,
    description: "Optimal fraction of account to risk per trade, or nil if insufficient data"
  },
  returns_example: 0.1095
}

volatility_scaled(account_size, risk_percent, current_volatility, target_volatility)

@spec volatility_scaled(number(), fraction(), number(), number()) :: position_size()

Calculate position size scaled by volatility.

Parameters

  • account_size - Total account equity (value)
  • risk_percent - Base risk per trade as decimal (value)
  • current_volatility - Current volatility measure (e.g., ATR, std dev) (value)
  • target_volatility - Target/baseline volatility for normal sizing (value)

Returns

Volatility-adjusted risk amount in account currency (float)

Example

0.1095
# descripex:contract
%{
  params: %{
    account_size: %{description: "Total account equity", kind: :value},
    risk_percent: %{description: "Base risk per trade as decimal", kind: :value},
    current_volatility: %{
      description: "Current volatility measure (e.g., ATR, std dev)",
      kind: :value
    },
    target_volatility: %{
      description: "Target/baseline volatility for normal sizing",
      kind: :value
    }
  },
  returns: %{
    type: :float,
    description: "Volatility-adjusted risk amount in account currency"
  },
  returns_example: 0.1095
}