Constraints & Objectives
The optimizer solves a mathematical problem: given your universe, what weights maximise your objective subject to your constraints? This page explains every option, when to use it, and the exact JSON format for bulk upload.
How Constraints and Objectives Work Together
Objective— what you're optimising for (e.g. maximise Sharpe ratio). The optimizer finds weights that score highest on this metric.
Constraints— boundaries the optimizer must stay within (e.g. no single stock > 10%). Think of them as the rules of the game. The optimizer can do anything as long as it doesn't break these rules.
Without constraints, a Sharpe-maximising optimizer will often put everything in one or two stocks. Good constraints make the portfolio realistic and tradeable.
Constraints
Position Size Bound
Sets a floor and ceiling on how much of the portfolio any single stock can hold. Prevents over-concentration and ensures minimum diversification.
When to use: Without this, the optimizer may put 80%+ in one stock if it has the best risk-adjusted return. Typical range: 2%–10% per position.
Parameters
| Field | Example Value | Description |
|---|---|---|
| min_weight | "0.02" | Minimum allocation per stock (2%) |
| max_weight | "0.10" | Maximum allocation per stock (10%) |
JSON
{
"name": "Position Size Bound",
"type": "Position Size Bound",
"params": {
"min_weight": "0.02",
"max_weight": "0.10"
},
"status": "active"
}Maximum Number of Positions
Caps the total number of stocks held at any one time. Forces the optimizer to concentrate in the highest-conviction names.
When to use: Portfolios with 100+ positions often resemble the index. 15–30 positions gives meaningful active exposure while keeping transaction costs manageable.
Parameters
| Field | Example Value | Description |
|---|---|---|
| max_positions | "20" | Maximum number of distinct holdings |
JSON
{
"name": "Maximum Number of Positions",
"type": "Maximum Number of Positions",
"params": {
"max_positions": "20"
},
"status": "active"
}Maximum Capital
Limits the total allocated weight across all positions. Setting this below 1.0 keeps some cash in reserve.
When to use: Useful if you want to hold 10% cash at all times (set max_capital: 0.9) or to simulate strategies that don't fully deploy capital.
Parameters
| Field | Example Value | Description |
|---|---|---|
| max_capital | "0.95" | Fraction of portfolio to deploy (0–1) |
JSON
{
"name": "Maximum Capital",
"type": "Maximum Capital",
"params": {
"max_capital": "0.95"
},
"status": "active"
}Beta Exposure Constraint
Keeps the portfolio's overall market sensitivity (beta) within a target band. Beta 1.0 = moves with market; <1.0 = defensive; >1.0 = aggressive.
When to use: If you want a market-neutral strategy, target beta near 0. If you want a low-vol defensive portfolio, set max_beta: 0.8.
Parameters
| Field | Example Value | Description |
|---|---|---|
| min_beta | "0.7" | Lower bound on portfolio beta |
| max_beta | "1.2" | Upper bound on portfolio beta |
JSON
{
"name": "Beta Exposure Constraint",
"type": "Beta Exposure Constraint",
"params": {
"min_beta": "0.7",
"max_beta": "1.2"
},
"status": "active"
}Portfolio Turnover Constraint
Limits how much of the portfolio is traded at each rebalance. High turnover = high transaction costs that eat into returns.
When to use: At 30bps per trade (our default), turning over 100% monthly costs ~3.6% per year just in costs. Limiting turnover to 30–50% per rebalance can significantly improve net returns.
Parameters
| Field | Example Value | Description |
|---|---|---|
| max_turnover | "0.30" | Maximum portfolio traded per rebalance (30%) |
JSON
{
"name": "Portfolio Turnover Constraint",
"type": "Portfolio Turnover Constraint",
"params": {
"max_turnover": "0.30"
},
"status": "active"
}Minimum Position Size Constraint
Ensures every included stock has a minimum meaningful allocation. Prevents the optimizer from holding a stock at 0.1% — too small to matter.
When to use: If a stock is worth holding, it should be held at a size that actually impacts returns. 1–3% minimum ensures every position counts.
Parameters
| Field | Example Value | Description |
|---|---|---|
| min_position_size | "0.01" | Minimum weight if a stock is included (1%) |
JSON
{
"name": "Minimum Position Size Constraint",
"type": "Minimum Position Size Constraint",
"params": {
"min_position_size": "0.01"
},
"status": "active"
}Portfolio Risk Budget Constraint
Sets a target for the portfolio's total annualised volatility. Forces the optimizer to stay within a risk envelope.
When to use: If your mandate is 'low-risk income', cap volatility at 10%. If you're running an aggressive growth fund, you might allow up to 25%.
Parameters
| Field | Example Value | Description |
|---|---|---|
| risk_budget | "0.15" | Target annualised volatility (15%) |
JSON
{
"name": "Portfolio Risk Budget Constraint",
"type": "Portfolio Risk Budget Constraint",
"params": {
"risk_budget": "0.15"
},
"status": "active"
}Objectives
Only one objective is active at a time. The optimizer solves for this single goal while respecting all active constraints.
Risk-Adjusted Return Objective
Maximises the Sharpe ratio — return per unit of risk. The most common objective for long-only equity portfolios.
Why: A portfolio returning 20% with 30% volatility (Sharpe 0.67) is worse than one returning 15% with 12% volatility (Sharpe 1.25). Sharpe maximisation finds the best risk-return trade-off.
When to use: Use for general-purpose portfolios where you want the best risk-adjusted outcome.
Parameters
| Field | Example Value | Description |
|---|---|---|
| weight | "1" | Relative importance when combining multiple objectives |
JSON
{
"name": "Risk-Adjusted Return Objective",
"type": "Risk-Adjusted Return Objective",
"params": {
"weight": "1"
},
"status": "active"
}Risk Minimization Objective
Finds the minimum variance portfolio — the allocation with the lowest possible volatility, regardless of return.
Why: Useful for capital preservation mandates, retiree portfolios, or when the universe is volatile and you want stability first.
When to use: Use when drawdown protection matters more than maximising return. Often combined with a Position Size Bound constraint.
Parameters
| Field | Example Value | Description |
|---|---|---|
| risk_type | "variance" | variance or std_dev |
| weight | "1" | Relative importance |
JSON
{
"name": "Risk Minimization Objective",
"type": "Risk Minimization Objective",
"params": {
"risk_type": "variance",
"weight": "1"
},
"status": "active"
}Return Maximization Objective
Maximises expected portfolio return without regard for risk. Produces concentrated, aggressive portfolios.
Why: In practice, pure return maximisation puts everything in the single highest-expected-return asset. Always combine with Position Size Bound and Beta constraints.
When to use: Use for high-conviction, high-risk-tolerance strategies. Requires strong constraints to stay diversified.
Parameters
| Field | Example Value | Description |
|---|---|---|
| weight | "1" | Relative importance |
JSON
{
"name": "Return Maximization Objective",
"type": "Return Maximization Objective",
"params": {
"weight": "1"
},
"status": "active"
}Tracking Error Minimization
Minimises deviation from a benchmark index. Produces a portfolio that closely tracks the benchmark while maintaining some active positions.
Why: For fund managers measured against an index (NIFTY 50, NIFTY 500), large tracking error means large active bets. Minimising TE reduces career risk.
When to use: Use for enhanced index funds, benchmark-aware strategies, or when mandate requires staying close to an index.
Parameters
| Field | Example Value | Description |
|---|---|---|
| benchmark | "NIFTY 50" | The index to track |
| weight | "1" | Relative importance |
JSON
{
"name": "Tracking Error Minimization",
"type": "Tracking Error Minimization",
"params": {
"benchmark": "NIFTY 50",
"weight": "1"
},
"status": "active"
}Bulk Upload Format
Use the ↑ upload button on the Constraints or Objectives card in the Strategy Builder to load a JSON file directly. All existing entries are replaced. Download your current setup with the ↓ download button to use as a starting template.
constraints.json
[
{
"name": "Position Size Bound",
"type": "Position Size Bound",
"params": {
"min_weight": "0.02",
"max_weight": "0.10"
},
"status": "active"
},
{
"name": "Maximum Number of Positions",
"type": "Maximum Number of Positions",
"params": {
"max_positions": "20"
},
"status": "active"
},
{
"name": "Beta Exposure Constraint",
"type": "Beta Exposure Constraint",
"params": {
"min_beta": "0.7",
"max_beta": "1.2"
},
"status": "active"
},
{
"name": "Portfolio Turnover Constraint",
"type": "Portfolio Turnover Constraint",
"params": {
"max_turnover": "0.30"
},
"status": "active"
}
]objectives.json
[
{
"name": "Risk-Adjusted Return Objective",
"type": "Risk-Adjusted Return Objective",
"params": {
"weight": "1"
},
"status": "active"
}
]JSON Schema Rules
- Top-level must be a JSON array
[ ... ] - Each entry requires:
name,type,params,status statusmust be"active"or"inactive"- All
paramsvalues must be strings even if numeric — e.g."0.10"not0.10 - Duplicate types are automatically removed on upload (first occurrence kept)
idis optional — ignored on upload, auto-assigned
Recommended Setups
Balanced Growth
Objective
Risk-Adjusted Return (Sharpe)
Constraints
- Position Size Bound 2–10%
- Max 25 positions
- Beta 0.8–1.2
- Max turnover 40%
Low Volatility
Objective
Risk Minimization
Constraints
- Position Size Bound 3–8%
- Max 30 positions
- Beta 0.5–0.9
- Risk Budget 12%
Index Hugger
Objective
Tracking Error Minimization
Constraints
- Position Size Bound 1–6%
- Max 50 positions
- Beta 0.9–1.1
- Max turnover 20%