|
1 | 1 | """Allocation and plan helpers for LongBridgePlatform.""" |
2 | 2 |
|
3 | | -from __future__ import annotations |
4 | | - |
5 | | -import numpy as np |
6 | | - |
7 | | - |
8 | | -def get_dynamic_allocation( |
9 | | - total_equity_usd, |
10 | | - *, |
11 | | - small_account_deploy_ratio, |
12 | | - mid_account_deploy_ratio, |
13 | | - large_account_deploy_ratio, |
14 | | - trade_layer_decay_coeff, |
15 | | -): |
16 | | - if total_equity_usd <= 10000: |
17 | | - return small_account_deploy_ratio |
18 | | - |
19 | | - if total_equity_usd <= 80000: |
20 | | - return float( |
21 | | - np.interp( |
22 | | - total_equity_usd, |
23 | | - [10000, 80000], |
24 | | - [small_account_deploy_ratio, mid_account_deploy_ratio], |
25 | | - ) |
26 | | - ) |
27 | | - |
28 | | - if total_equity_usd <= 180000: |
29 | | - return float( |
30 | | - np.interp( |
31 | | - total_equity_usd, |
32 | | - [80000, 180000], |
33 | | - [mid_account_deploy_ratio, large_account_deploy_ratio], |
34 | | - ) |
35 | | - ) |
36 | | - |
37 | | - decayed_ratio = large_account_deploy_ratio - ( |
38 | | - trade_layer_decay_coeff * np.log10(total_equity_usd / 180000) |
39 | | - ) |
40 | | - return max(0.0, decayed_ratio) |
41 | | - |
42 | | - |
43 | | -def get_income_layer_ratio( |
44 | | - total_equity_usd, |
45 | | - *, |
46 | | - income_layer_start_usd, |
47 | | - income_layer_max_ratio, |
48 | | -): |
49 | | - if total_equity_usd <= income_layer_start_usd: |
50 | | - return 0.0 |
51 | | - |
52 | | - if total_equity_usd <= (income_layer_start_usd * 2): |
53 | | - return float( |
54 | | - np.interp( |
55 | | - total_equity_usd, |
56 | | - [income_layer_start_usd, income_layer_start_usd * 2], |
57 | | - [0.0, income_layer_max_ratio], |
58 | | - ) |
59 | | - ) |
60 | | - |
61 | | - return income_layer_max_ratio |
62 | | - |
63 | | - |
64 | | -def build_rebalance_plan( |
65 | | - indicators, |
66 | | - account_state, |
67 | | - *, |
68 | | - trend_ma_window, |
69 | | - translator, |
70 | | - cash_reserve_ratio, |
71 | | - min_trade_ratio, |
72 | | - min_trade_floor, |
73 | | - rebalance_threshold_ratio, |
74 | | - small_account_deploy_ratio, |
75 | | - mid_account_deploy_ratio, |
76 | | - large_account_deploy_ratio, |
77 | | - trade_layer_decay_coeff, |
78 | | - income_layer_start_usd, |
79 | | - income_layer_max_ratio, |
80 | | - income_layer_qqqi_weight, |
81 | | - income_layer_spyi_weight, |
82 | | -): |
83 | | - strategy_assets = ["SOXL", "SOXX", "BOXX", "QQQI", "SPYI"] |
84 | | - available_cash = account_state["available_cash"] |
85 | | - market_values = account_state["market_values"] |
86 | | - quantities = account_state["quantities"] |
87 | | - sellable_quantities = account_state["sellable_quantities"] |
88 | | - total_strategy_equity = account_state["total_strategy_equity"] |
89 | | - current_min_trade = max(min_trade_floor, total_strategy_equity * min_trade_ratio) |
90 | | - |
91 | | - current_income_layer_value = market_values["QQQI"] + market_values["SPYI"] |
92 | | - income_layer_ratio = get_income_layer_ratio( |
93 | | - total_strategy_equity, |
94 | | - income_layer_start_usd=income_layer_start_usd, |
95 | | - income_layer_max_ratio=income_layer_max_ratio, |
96 | | - ) |
97 | | - desired_income_layer_value = total_strategy_equity * income_layer_ratio |
98 | | - locked_income_layer_value = max(current_income_layer_value, desired_income_layer_value) |
99 | | - income_layer_add_value = max(0.0, locked_income_layer_value - current_income_layer_value) |
100 | | - core_equity = max(0.0, total_strategy_equity - locked_income_layer_value) |
101 | | - deploy_ratio = get_dynamic_allocation( |
102 | | - core_equity, |
103 | | - small_account_deploy_ratio=small_account_deploy_ratio, |
104 | | - mid_account_deploy_ratio=mid_account_deploy_ratio, |
105 | | - large_account_deploy_ratio=large_account_deploy_ratio, |
106 | | - trade_layer_decay_coeff=trade_layer_decay_coeff, |
107 | | - ) |
108 | | - deployed_capital = core_equity * deploy_ratio |
109 | | - deploy_ratio_text = f"{deploy_ratio * 100:.1f}%" |
110 | | - income_ratio_text = f"{income_layer_ratio * 100:.1f}%" |
111 | | - income_locked_ratio_text = ( |
112 | | - f"{(locked_income_layer_value / total_strategy_equity) * 100:.1f}%" |
113 | | - if total_strategy_equity > 0 |
114 | | - else "0.0%" |
115 | | - ) |
116 | | - |
117 | | - soxl_price = indicators["soxl"]["price"] |
118 | | - soxl_ma_trend = indicators["soxl"]["ma_trend"] |
119 | | - active_risk_asset = "SOXL" if soxl_price > soxl_ma_trend else "SOXX" |
120 | | - market_status = ( |
121 | | - f"🚀 RISK-ON ({active_risk_asset})" |
122 | | - if active_risk_asset == "SOXL" |
123 | | - else "🛡️ DE-LEVER (SOXX)" |
124 | | - ) |
125 | | - signal_message = ( |
126 | | - translator("signal_risk_on", window=trend_ma_window, ratio=deploy_ratio_text) |
127 | | - if active_risk_asset == "SOXL" |
128 | | - else translator("signal_delever", window=trend_ma_window, ratio=deploy_ratio_text) |
129 | | - ) |
130 | | - |
131 | | - targets = { |
132 | | - "SOXL": deployed_capital if active_risk_asset == "SOXL" else 0.0, |
133 | | - "SOXX": deployed_capital if active_risk_asset == "SOXX" else 0.0, |
134 | | - "QQQI": market_values["QQQI"] + (income_layer_add_value * income_layer_qqqi_weight), |
135 | | - "SPYI": market_values["SPYI"] + (income_layer_add_value * income_layer_spyi_weight), |
136 | | - "BOXX": max(0.0, core_equity - deployed_capital), |
137 | | - } |
138 | | - |
139 | | - return { |
140 | | - "strategy_assets": strategy_assets, |
141 | | - "available_cash": available_cash, |
142 | | - "market_values": market_values, |
143 | | - "quantities": quantities, |
144 | | - "sellable_quantities": sellable_quantities, |
145 | | - "total_strategy_equity": total_strategy_equity, |
146 | | - "current_min_trade": current_min_trade, |
147 | | - "targets": targets, |
148 | | - "market_status": market_status, |
149 | | - "signal_message": signal_message, |
150 | | - "deploy_ratio_text": deploy_ratio_text, |
151 | | - "income_ratio_text": income_ratio_text, |
152 | | - "income_locked_ratio_text": income_locked_ratio_text, |
153 | | - "active_risk_asset": active_risk_asset, |
154 | | - "investable_cash": max(0, available_cash - (total_strategy_equity * cash_reserve_ratio)), |
155 | | - "threshold_value": total_strategy_equity * rebalance_threshold_ratio, |
156 | | - } |
157 | | - |
| 3 | +from us_equity_strategies.strategies.semiconductor_rotation_income import ( |
| 4 | + build_rebalance_plan, |
| 5 | + get_dynamic_allocation, |
| 6 | + get_income_layer_ratio, |
| 7 | +) |
| 8 | + |
| 9 | +__all__ = [ |
| 10 | + "build_rebalance_plan", |
| 11 | + "get_dynamic_allocation", |
| 12 | + "get_income_layer_ratio", |
| 13 | +] |
0 commit comments