We can determine different constraints with a formatted csv file as follows:
          
Constraints can be established on a top-down level, i.e. factor loading constraints or bottom-up aggregations. Columns (2) and (3) are used to distinguish if a constraint is bottom-up (aggregation) or top-down (projection). Use either column, but the same constraint cannot have entries on both columns.
Please note that the order of the provided constraints does not affect the optimizer. "Top-Down" constraints do not interfere with others as they are a linear combination of asset weights. Similarly, "Bottom-up" constraints that are grouped (Group=TRUE) also don't interfere with others because they are a linear combination of asset weights ("energy stocks limited to 10% as a group", as an example).
Additionally, specific constraints in single security in the group will always supersede grouped constraints. For example:
On a hypothetical portfolio, assuming that each technology stock is limited to 3% of the portfolio (Aggregation=sector, Type=technology, Group=FALSE) and at any place in the file AAPL is set to have a 6% maximum weight, the more specific AAPL constraint will prevail over the group constrain (reinforcing that it is not related with the order in the file). Logically the system will process the group, set AAPL to have a maximum of 3% as AAPL is a technology stock, and then reset it to 6%.
In order to specify an aggregation constraint, the following parameters have to be provided:
- Aggregation type (column 3): Currently only "aggregation_label" and "position" supported. Position-specific constraints always take precedence over more generic constraints.
- Type (column 4): "aggregation_label" can be any string associated with the position and is provided during portfolio upload. When "position" is used, the stock ticker is the relevant property.
- Group (column 5): if True, the constraint is considered on the aggregate. If omitted, it is imposed on each security of the aggregation. Please see the examples below.
- Sell / Buy (columns 6 and 7): These are relative constraints in terms of the percent of the existing position. A 100 on "Sell" means that any security belonging to this aggregation can be sold in full. Always provide both Sell/Buy. When columns 6 and 7 are filled, columns 8 to 11 need to be empty
- lower_weight / upper_weight (columns 8 and 9): These are absolute constraints. When used, do not use relative constraints, i.e. columns 6 and 7 need to be empty
- slack-/slack+ (columns 10 and 11): Use these to establish non-binding constraints. Currently can only be used with Grouped constraints or factors, as explained below.
- enabled (column 12): Boolean to turn constraints on and off.
Let's describe the aggregation constraints in the table above:
Constraint 0: (No cash increase)
All the cash positions need to be labelled in the portfolio. Each security representing cash can be sold in its entirety and each cash position cannot be increased:
Constraint 1: (No tradable positions)
Positions that cannot be traded. All the positions subjected to this constraint need to be labelled in the portfolio with the same "Type" used in the constraint specification:
The portfolio to be optimized would require the labels for positions that are not supposed to be traded to be "non_tradable". Any label can be used but users need to enforce consistency with the constraint specification file:
Constraint 2: (Absolute limit on each security from a Type)
Every position labelled as "new_stock" is limited to 2% of the portfolio.
Constraint 3: (Absolute limit on the aggregate of all securities from a Type)
This constraint specifies the combined target allocation for all the securities belonging to an aggregation. In the example below, it specifies that "new_stock" should be 7% as a whole. When different lower and upper weights are provided, the combined allocation is constrained in the range.
Also, group constraints can be non-binding. Slacks can be provided. In the example, the target for new stocks in the portfolio should be 7%, but we accept no inclusion (7% negative slack) to 12% (5% positive slack):
Constraint 5: (Absolute limits on single security)
In the example, VIG is constrained to be between 2% and 10% of the portfolio. If VIG was part of a more generic constraint, this individual constraint will super seed.
Constraints 8-11: (Absolute limits on a factor model)
Constraints on a single multi-factor model can be specified. Factor targets are specified in multiple lines. When lower and upper weights differ, the factor loadings are constrained in the ranges. These constraints can be non-binding (similarly to groups - constrain 3)
The targets do not need to add to 100%.