Fix portfolio construction NaN handling
This commit is contained in:
@@ -47,18 +47,16 @@ def continuous_targets(
|
||||
"""
|
||||
alpha = np.asarray(alpha, dtype=np.float64)
|
||||
price = np.asarray(price, dtype=np.float64)
|
||||
a = np.where(np.isfinite(alpha), alpha, 0.0)
|
||||
tradable = np.isfinite(price) & (price > 0)
|
||||
a = np.where(np.isfinite(alpha) & tradable, alpha, 0.0)
|
||||
gross = np.abs(a).sum()
|
||||
if gross <= 0:
|
||||
zeros = np.zeros_like(a)
|
||||
return zeros, zeros.copy(), zeros.copy()
|
||||
w = a / gross
|
||||
v_target = booksize * w
|
||||
tradable = np.isfinite(price) & (price > 0)
|
||||
q_target = np.where(tradable, v_target / np.where(tradable, price, 1.0), 0.0)
|
||||
# Names without a tradable price get no target exposure.
|
||||
w = np.where(tradable, w, 0.0)
|
||||
v_target = np.where(tradable, v_target, 0.0)
|
||||
q_target = np.zeros_like(v_target)
|
||||
np.divide(v_target, price, out=q_target, where=tradable)
|
||||
return w, v_target, q_target
|
||||
|
||||
|
||||
@@ -86,7 +84,7 @@ def construct_positions(
|
||||
vector. Each date: continuous targets → state-dependent lot rounding →
|
||||
two-stage exposure repair. Names absent on a date get weight 0 (which closes
|
||||
any stale holding). An empty / zero-gross cross-section carries the book
|
||||
unchanged.
|
||||
unchanged in ``position_shares`` while leaving the target fields at 0.
|
||||
|
||||
Args:
|
||||
weights_df: Long frame with ``symbol_id, date, weight`` (ALPHA/COMBO).
|
||||
@@ -136,13 +134,20 @@ def construct_positions(
|
||||
)
|
||||
|
||||
w, v_target, q_target = continuous_targets(alpha, price, booksize)
|
||||
q_round = round_to_valid_lot(q_target, prev_shares, min_open, increment, odd_full)
|
||||
pos = repair_exposure(
|
||||
q_round, q_target, price, increment, min_open, prev_shares, odd_full,
|
||||
booksize=booksize, net_tol=net_tol, gross_tol=gross_tol,
|
||||
)
|
||||
if np.abs(w).sum() <= 0:
|
||||
logger.warning(
|
||||
"Portfolio '%s': zero-gross target on %s; carrying previous positions.",
|
||||
portfolio_name, d,
|
||||
)
|
||||
pos = prev_shares.copy()
|
||||
else:
|
||||
q_round = round_to_valid_lot(q_target, prev_shares, min_open, increment, odd_full)
|
||||
pos = repair_exposure(
|
||||
q_round, q_target, price, increment, min_open, prev_shares, odd_full,
|
||||
booksize=booksize, net_tol=net_tol, gross_tol=gross_tol,
|
||||
)
|
||||
|
||||
safe_price = np.where(np.isfinite(price), price, 0.0)
|
||||
safe_price = np.where(np.isfinite(price) & (price > 0), price, 0.0)
|
||||
blocks.append(pd.DataFrame({
|
||||
"symbol_id": symbols,
|
||||
"date": d,
|
||||
|
||||
Reference in New Issue
Block a user