@support,
Either something about the exposure calculation is wrong or I really need clarification on the rules. About the position limit I only find rule 7. o. in the contest rules which states "The evaluation system limits the maximum position size for a single financial instrument to 10%"
I always assumed this would mean the maximum weight for an asset would be 0.1 meaning 10 % of the portfolio. However the exposure calculation suggests the following:
Either we trade no asset or at least 10 assets per trading day, regardless of the actual weights assigned to each asset.
Consider this example:
import qnt.data as qndata
import qnt.output as qnout
from qnt.filter import filter_sharpe_ratio
data = qndata.stocks.load_spx_data(min_date="2005-01-01")
weights = data.sel(field='is_liquid').fillna(0)
weights *= filter_sharpe_ratio(data, weights, 3) * .01 # assign 1 % to each asset using the top 3 assets by sharpe
qnout.check(weights, data, "stocks_s&p500")
which results in an exposure error:
Check max exposure for index stocks (nasdaq100, s&p500)…
ERROR! The max exposure is too high.
Max exposure: [0. 0. 0. ... 0.33333333 0.33333333 0.33333333] Hard limit: 0.1
Use qnt.output.cut_big_positions() or normalize_by_max_exposure() to fix.
even though the maximum weight per asset is only 0.01
abs(weights).values.max()
0.01
(By the way, the 4 functions mentioned by @Vyacheslav_B also result in weights which dont't pass the exposure check when used with this example, except drop_bad_days
which results in empty weights.)
And if we assign 100 % to every liquid asset, the exposure check passes:
weights = data.sel(field='is_liquid').fillna(0)
qnout.check(weights, data, "stocks_s&p500")
Check max exposure for index stocks (nasdaq100, s&p500)…
Ok.
So, does rule 7. o. mean we have to trade at least 10 assets or none at all each trading day to satisfy the exposure check?