quant-ai / src /execution /implementation_shortfall.py
Ypeng12's picture
feat: 10/10 HRT style point-in-time alpha research platform, purged walk-forward CV, risk parity & test suite
b54319d
Raw
History Blame Contribute Delete
2.2 kB
import pandas as pd
import numpy as np
from typing import Dict, Any
class TransactionCostModel:
"""
Simulates Transaction Costs and Slippage:
- Base Fee: bps (default 2 bps)
- Bid-Ask Spread & Slippage: bps (default 3 bps) -> Total Baseline Friction: 5 bps (0.05%)
- Support for Sensitivity Matrices [2 bps, 5 bps, 10 bps, 15 bps]
"""
def __init__(self, cost_bps: float = 5.0, slippage_bps: float = 2.0):
self.cost_bps = cost_bps
self.slippage_bps = slippage_bps
self.total_bps = cost_bps + slippage_bps
def apply_cost_to_return(self, gross_return: float, turnover: float) -> float:
"""
Subtracts transaction costs from gross rebalance return:
Net Return = Gross Return - Turnover * Total_BPS / 10000
"""
cost = turnover * (self.total_bps / 10_000.0)
return gross_return - cost
class ImplementationShortfallDecomposer:
"""
Implementation Shortfall (Perold 1988):
IS = side * (P_fill - P_decision) / P_decision + Fees
Decomposed into:
1. Delay Cost: (P_submission - P_decision) / P_decision
2. Execution Cost: (P_fill - P_submission) / P_decision
3. Fee / Slippage Cost
"""
def __init__(self, fee_bps: float = 2.0):
self.fee_bps = fee_bps
def decompose(
self,
side: int, # +1 for Buy, -1 for Sell
p_decision: float,
p_submission: float,
p_fill: float,
quantity: float,
) -> Dict[str, float]:
if p_decision <= 0:
return {}
delay_cost = side * (p_submission - p_decision) / p_decision
execution_cost = side * (p_fill - p_submission) / p_decision
fee_cost = self.fee_bps / 10_000.0
total_is = delay_cost + execution_cost + fee_cost
return {
"side": side,
"quantity": quantity,
"p_decision": p_decision,
"p_submission": p_submission,
"p_fill": p_fill,
"delay_cost_bps": delay_cost * 10_000.0,
"execution_cost_bps": execution_cost * 10_000.0,
"fee_cost_bps": fee_cost * 10_000.0,
"total_is_bps": total_is * 10_000.0,
}