research: add per-year trade counts + turnover to trackD_timing
This commit is contained in:
@@ -77,7 +77,9 @@ def run_asset(df, bars_per_day, target_vol=TARGET_VOL, leverage=LEVERAGE,
|
||||
direction = sig_tsmom_blend(c, horizons=(h1, h3, h6))
|
||||
tgt = build_target(direction, vol, target_vol, leverage, long_only)
|
||||
equity, net = equity_from_target(tgt, r, fee_side)
|
||||
return dict(net=net, ts=df["datetime"], equity=equity, bpy=bpy)
|
||||
# discrete position SIGN for trade counting (entry = sign change to a new non-zero state)
|
||||
sign = np.sign(tgt)
|
||||
return dict(net=net, ts=df["datetime"], equity=equity, bpy=bpy, sign=sign, target=tgt)
|
||||
|
||||
|
||||
def portfolio_series(sleeves):
|
||||
@@ -118,6 +120,20 @@ def per_year(idx, equity):
|
||||
return out
|
||||
|
||||
|
||||
def trades_per_year(sleeves):
|
||||
"""Count entries per year, summed across both sleeves. An 'entry' = the position SIGN
|
||||
changing to a new non-zero value (flat->long, flat->short, or a direction flip)."""
|
||||
counts: dict[int, int] = {}
|
||||
for a in ASSETS:
|
||||
sign = sleeves[a]["sign"]
|
||||
ts = pd.to_datetime(sleeves[a]["ts"].values)
|
||||
for i in range(1, len(sign)):
|
||||
s, prev = sign[i], sign[i - 1]
|
||||
if s != 0 and s != prev: # entry: from flat or opposite into a non-zero state
|
||||
counts[ts[i].year] = counts.get(ts[i].year, 0) + 1
|
||||
return counts
|
||||
|
||||
|
||||
ALL_YEARS = list(range(2018, 2027))
|
||||
|
||||
|
||||
@@ -139,14 +155,18 @@ def main():
|
||||
ov = overall_metrics(idx, combo, equity, sleeves["BTC"]["bpy"])
|
||||
py = per_year(idx, equity)
|
||||
|
||||
tpy = trades_per_year(sleeves)
|
||||
total_trades = sum(tpy.values())
|
||||
print(f"\n ── TF {tf_key:<3s} │ ret {ov['total']*100:>+8.0f}% CAGR {ov['cagr']*100:>+6.1f}% "
|
||||
f"Sharpe {ov['sharpe']:>4.2f} maxDD {ov['max_dd']*100:>4.1f}% "
|
||||
f"€/day(2k) {ov['daily_2k']:>+6.2f}")
|
||||
# per-year PnL row
|
||||
f"€/day(2k) {ov['daily_2k']:>+6.2f} trades {total_trades}")
|
||||
# per-year PnL / DD / trades rows
|
||||
print(f" {'PnL %':<8s}" + "".join(
|
||||
(" . " if y not in py else f"{py[y][0]*100:>+7.0f}") for y in ALL_YEARS))
|
||||
print(f" {'maxDD %':<8s}" + "".join(
|
||||
(" . " if y not in py else f"{py[y][1]*100:>7.1f}") for y in ALL_YEARS))
|
||||
print(f" {'trades':<8s}" + "".join(
|
||||
(" . " if y not in py else f"{tpy.get(y,0):>7d}") for y in ALL_YEARS))
|
||||
# year header for reference
|
||||
print("\n " + "year ".ljust(8) + "".join(f"{y:>7d}" for y in ALL_YEARS))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user