File size: 2,203 Bytes
b54319d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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,
        }