tensorquantlib 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tensorquantlib/__init__.py +313 -0
- tensorquantlib/__main__.py +315 -0
- tensorquantlib/backtest/__init__.py +48 -0
- tensorquantlib/backtest/engine.py +240 -0
- tensorquantlib/backtest/metrics.py +320 -0
- tensorquantlib/backtest/strategy.py +348 -0
- tensorquantlib/core/__init__.py +6 -0
- tensorquantlib/core/ops.py +70 -0
- tensorquantlib/core/second_order.py +465 -0
- tensorquantlib/core/tensor.py +928 -0
- tensorquantlib/data/__init__.py +16 -0
- tensorquantlib/data/market.py +160 -0
- tensorquantlib/finance/__init__.py +52 -0
- tensorquantlib/finance/american.py +263 -0
- tensorquantlib/finance/basket.py +291 -0
- tensorquantlib/finance/black_scholes.py +219 -0
- tensorquantlib/finance/credit.py +199 -0
- tensorquantlib/finance/exotics.py +885 -0
- tensorquantlib/finance/fx.py +204 -0
- tensorquantlib/finance/greeks.py +133 -0
- tensorquantlib/finance/heston.py +543 -0
- tensorquantlib/finance/implied_vol.py +277 -0
- tensorquantlib/finance/ir_derivatives.py +203 -0
- tensorquantlib/finance/jump_diffusion.py +203 -0
- tensorquantlib/finance/local_vol.py +146 -0
- tensorquantlib/finance/rates.py +381 -0
- tensorquantlib/finance/risk.py +344 -0
- tensorquantlib/finance/variance_reduction.py +420 -0
- tensorquantlib/finance/volatility.py +355 -0
- tensorquantlib/py.typed +0 -0
- tensorquantlib/tt/__init__.py +43 -0
- tensorquantlib/tt/decompose.py +576 -0
- tensorquantlib/tt/ops.py +386 -0
- tensorquantlib/tt/pricing.py +304 -0
- tensorquantlib/tt/surrogate.py +634 -0
- tensorquantlib/utils/__init__.py +5 -0
- tensorquantlib/utils/validation.py +126 -0
- tensorquantlib/viz/__init__.py +27 -0
- tensorquantlib/viz/plots.py +331 -0
- tensorquantlib-0.3.0.dist-info/METADATA +602 -0
- tensorquantlib-0.3.0.dist-info/RECORD +44 -0
- tensorquantlib-0.3.0.dist-info/WHEEL +5 -0
- tensorquantlib-0.3.0.dist-info/licenses/LICENSE +21 -0
- tensorquantlib-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""Abstract base strategy and concrete strategy implementations."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class Trade:
|
|
13
|
+
"""Record of a single trade."""
|
|
14
|
+
|
|
15
|
+
step: int
|
|
16
|
+
quantity: float # positive = buy, negative = sell
|
|
17
|
+
price: float
|
|
18
|
+
label: str = ""
|
|
19
|
+
slippage: float = 0.0 # slippage cost paid on this trade
|
|
20
|
+
commission: float = 0.0 # commission paid on this trade
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def notional(self) -> float:
|
|
24
|
+
"""Gross notional value of the trade."""
|
|
25
|
+
return abs(self.quantity) * self.price
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def total_cost(self) -> float:
|
|
29
|
+
"""Total execution cost (slippage + commission)."""
|
|
30
|
+
return self.slippage + self.commission
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Strategy(ABC):
|
|
34
|
+
"""Base class for backtesting strategies.
|
|
35
|
+
|
|
36
|
+
Sub-classes must implement :meth:`on_data`.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self.position: float = 0.0
|
|
41
|
+
self.trades: list[Trade] = []
|
|
42
|
+
self.cash: float = 0.0
|
|
43
|
+
self._greeks_history: dict[str, list] = {}
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def on_data(self, step: int, price: float, **kwargs) -> float:
|
|
47
|
+
"""Called each time step with current price.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
step : int
|
|
52
|
+
Current time step index.
|
|
53
|
+
price : float
|
|
54
|
+
Current asset price.
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
float
|
|
59
|
+
Desired position size (signed). The engine will trade the
|
|
60
|
+
difference between current and desired position.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def on_fill(self, trade: Trade) -> None:
|
|
64
|
+
"""Called after a trade is executed. Override for bookkeeping."""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class DeltaHedgeStrategy(Strategy):
|
|
68
|
+
"""Delta-hedge a short option position using Black-Scholes delta.
|
|
69
|
+
|
|
70
|
+
At each step compute BS delta and rebalance the hedge portfolio.
|
|
71
|
+
Also tracks per-step Delta and Gamma in ``_greeks_history`` for
|
|
72
|
+
P&L attribution via :func:`~tensorquantlib.backtest.metrics.hedge_pnl_attribution`.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
K : float
|
|
77
|
+
Option strike.
|
|
78
|
+
T_total : float
|
|
79
|
+
Total time to expiry at inception (years).
|
|
80
|
+
r : float
|
|
81
|
+
Risk-free rate.
|
|
82
|
+
sigma : float
|
|
83
|
+
Implied volatility.
|
|
84
|
+
option_type : str
|
|
85
|
+
``'call'`` or ``'put'``.
|
|
86
|
+
n_steps : int
|
|
87
|
+
Total number of rebalancing steps.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(self, K: float, T_total: float, r: float, sigma: float,
|
|
91
|
+
option_type: str = "call", n_steps: int = 252):
|
|
92
|
+
super().__init__()
|
|
93
|
+
self.K = K
|
|
94
|
+
self.T_total = T_total
|
|
95
|
+
self.r = r
|
|
96
|
+
self.sigma = sigma
|
|
97
|
+
self.option_type = option_type
|
|
98
|
+
self.n_steps = n_steps
|
|
99
|
+
self._greeks_history: dict[str, list] = {"delta": [], "gamma": [], "T_remain": []}
|
|
100
|
+
|
|
101
|
+
def _bs_delta(self, S: float, T_remain: float) -> float:
|
|
102
|
+
from scipy.stats import norm
|
|
103
|
+
if T_remain <= 0:
|
|
104
|
+
if self.option_type == "call":
|
|
105
|
+
return 1.0 if S > self.K else 0.0
|
|
106
|
+
else:
|
|
107
|
+
return -1.0 if S < self.K else 0.0
|
|
108
|
+
d1 = (np.log(S / self.K) + (self.r + 0.5 * self.sigma**2) * T_remain) / \
|
|
109
|
+
(self.sigma * np.sqrt(T_remain))
|
|
110
|
+
if self.option_type == "call":
|
|
111
|
+
return float(norm.cdf(d1))
|
|
112
|
+
return float(norm.cdf(d1) - 1.0)
|
|
113
|
+
|
|
114
|
+
def _bs_gamma(self, S: float, T_remain: float) -> float:
|
|
115
|
+
from scipy.stats import norm
|
|
116
|
+
if T_remain <= 0:
|
|
117
|
+
return 0.0
|
|
118
|
+
d1 = (np.log(S / self.K) + (self.r + 0.5 * self.sigma**2) * T_remain) / \
|
|
119
|
+
(self.sigma * np.sqrt(T_remain))
|
|
120
|
+
return float(norm.pdf(d1) / (S * self.sigma * np.sqrt(T_remain)))
|
|
121
|
+
|
|
122
|
+
def on_data(self, step: int, price: float, **kwargs) -> float:
|
|
123
|
+
T_remain = max(self.T_total * (1 - step / self.n_steps), 0.0)
|
|
124
|
+
delta = self._bs_delta(price, T_remain)
|
|
125
|
+
gamma = self._bs_gamma(price, T_remain)
|
|
126
|
+
self._greeks_history["delta"].append(delta)
|
|
127
|
+
self._greeks_history["gamma"].append(gamma)
|
|
128
|
+
self._greeks_history["T_remain"].append(T_remain)
|
|
129
|
+
return delta
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class GammaScalpingStrategy(Strategy):
|
|
133
|
+
"""Gamma scalping: delta-hedge a long straddle and harvest realized volatility.
|
|
134
|
+
|
|
135
|
+
The strategy holds a synthetic long straddle (long gamma) and
|
|
136
|
+
continuously delta-hedges to remain directionally neutral. It
|
|
137
|
+
profits when *realized* volatility exceeds the *implied* volatility
|
|
138
|
+
embedded in the initial option price.
|
|
139
|
+
|
|
140
|
+
Per-step P&L attribution (stored in ``_greeks_history``):
|
|
141
|
+
|
|
142
|
+
.. code-block:: text
|
|
143
|
+
|
|
144
|
+
Daily P&L ≈ ½Γ(ΔS)² (gamma P&L — profits from large moves)
|
|
145
|
+
+ Θ · Δt (theta P&L — loses time value daily)
|
|
146
|
+
+ residual (higher-order / hedging error)
|
|
147
|
+
|
|
148
|
+
When realized_vol > implied_vol the gamma P&L dominates and the
|
|
149
|
+
strategy is profitable over the full holding period.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
K : float
|
|
154
|
+
Straddle strike (ideally near-ATM).
|
|
155
|
+
T_total : float
|
|
156
|
+
Time to expiry at inception (years).
|
|
157
|
+
r : float
|
|
158
|
+
Risk-free rate.
|
|
159
|
+
sigma_implied : float
|
|
160
|
+
Implied volatility at inception.
|
|
161
|
+
n_steps : int
|
|
162
|
+
Total rebalancing steps.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
def __init__(self, K: float, T_total: float, r: float,
|
|
166
|
+
sigma_implied: float, n_steps: int = 252):
|
|
167
|
+
super().__init__()
|
|
168
|
+
self.K = K
|
|
169
|
+
self.T_total = T_total
|
|
170
|
+
self.r = r
|
|
171
|
+
self.sigma = sigma_implied
|
|
172
|
+
self.n_steps = n_steps
|
|
173
|
+
self._greeks_history: dict[str, list] = {
|
|
174
|
+
"delta": [], "gamma": [], "theta": [],
|
|
175
|
+
"theoretical_gamma_pnl": [], "theoretical_theta_pnl": [],
|
|
176
|
+
}
|
|
177
|
+
self._prev_price: float | None = None
|
|
178
|
+
|
|
179
|
+
def _straddle_delta(self, S: float, T_remain: float) -> float:
|
|
180
|
+
"""Straddle delta = N(d1) − N(−d1) = 2N(d1) − 1."""
|
|
181
|
+
from scipy.stats import norm
|
|
182
|
+
if T_remain <= 0:
|
|
183
|
+
return 0.0
|
|
184
|
+
d1 = (np.log(S / self.K) + (self.r + 0.5 * self.sigma ** 2) * T_remain) / \
|
|
185
|
+
(self.sigma * np.sqrt(T_remain))
|
|
186
|
+
return float(2.0 * norm.cdf(d1) - 1.0)
|
|
187
|
+
|
|
188
|
+
def _straddle_gamma(self, S: float, T_remain: float) -> float:
|
|
189
|
+
"""Straddle Gamma = 2 × call Gamma (call and put share the same Gamma)."""
|
|
190
|
+
from scipy.stats import norm
|
|
191
|
+
if T_remain <= 0:
|
|
192
|
+
return 0.0
|
|
193
|
+
d1 = (np.log(S / self.K) + (self.r + 0.5 * self.sigma ** 2) * T_remain) / \
|
|
194
|
+
(self.sigma * np.sqrt(T_remain))
|
|
195
|
+
return float(2.0 * norm.pdf(d1) / (S * self.sigma * np.sqrt(T_remain)))
|
|
196
|
+
|
|
197
|
+
def _straddle_theta(self, S: float, T_remain: float) -> float:
|
|
198
|
+
"""Straddle Theta per year (negative = time decay)."""
|
|
199
|
+
from scipy.stats import norm
|
|
200
|
+
if T_remain <= 0:
|
|
201
|
+
return 0.0
|
|
202
|
+
d1 = (np.log(S / self.K) + (self.r + 0.5 * self.sigma ** 2) * T_remain) / \
|
|
203
|
+
(self.sigma * np.sqrt(T_remain))
|
|
204
|
+
d2 = d1 - self.sigma * np.sqrt(T_remain)
|
|
205
|
+
theta_call = (-S * norm.pdf(d1) * self.sigma / (2.0 * np.sqrt(T_remain))
|
|
206
|
+
- self.r * self.K * np.exp(-self.r * T_remain) * norm.cdf(d2))
|
|
207
|
+
theta_put = (-S * norm.pdf(d1) * self.sigma / (2.0 * np.sqrt(T_remain))
|
|
208
|
+
+ self.r * self.K * np.exp(-self.r * T_remain) * norm.cdf(-d2))
|
|
209
|
+
return float(theta_call + theta_put)
|
|
210
|
+
|
|
211
|
+
def on_data(self, step: int, price: float, **kwargs) -> float:
|
|
212
|
+
T_remain = max(self.T_total * (1 - step / self.n_steps), 0.0)
|
|
213
|
+
dt = self.T_total / self.n_steps
|
|
214
|
+
delta = self._straddle_delta(price, T_remain)
|
|
215
|
+
gamma = self._straddle_gamma(price, T_remain)
|
|
216
|
+
theta = self._straddle_theta(price, T_remain)
|
|
217
|
+
|
|
218
|
+
if self._prev_price is not None:
|
|
219
|
+
dS = price - self._prev_price
|
|
220
|
+
theoretical_gamma_pnl = 0.5 * gamma * dS ** 2
|
|
221
|
+
theoretical_theta_pnl = theta * dt # negative (time decay)
|
|
222
|
+
else:
|
|
223
|
+
theoretical_gamma_pnl = 0.0
|
|
224
|
+
theoretical_theta_pnl = 0.0
|
|
225
|
+
|
|
226
|
+
self._prev_price = price
|
|
227
|
+
self._greeks_history["delta"].append(delta)
|
|
228
|
+
self._greeks_history["gamma"].append(gamma)
|
|
229
|
+
self._greeks_history["theta"].append(theta)
|
|
230
|
+
self._greeks_history["theoretical_gamma_pnl"].append(theoretical_gamma_pnl)
|
|
231
|
+
self._greeks_history["theoretical_theta_pnl"].append(theoretical_theta_pnl)
|
|
232
|
+
return delta
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class DeltaGammaHedgeStrategy(Strategy):
|
|
236
|
+
"""Delta-Gamma neutral hedge using two options and the underlying.
|
|
237
|
+
|
|
238
|
+
Holds a primary long option (strike ``K1``) and hedges **Gamma**
|
|
239
|
+
using a second option (strike ``K2``). Any residual Delta is
|
|
240
|
+
neutralised using the underlying asset.
|
|
241
|
+
|
|
242
|
+
At each rebalancing step the hedge ratios are:
|
|
243
|
+
|
|
244
|
+
.. math::
|
|
245
|
+
|
|
246
|
+
Q_{\\text{hedge}} = \\frac{\\Gamma_1(S,T)}{\\Gamma_2(S,T)}
|
|
247
|
+
\\qquad \\text{(makes net Gamma = 0)}
|
|
248
|
+
|
|
249
|
+
N_{\\text{stock}} = -(\\Delta_1 - Q_{\\text{hedge}} \\cdot \\Delta_2)
|
|
250
|
+
\\qquad \\text{(makes net Delta = 0)}
|
|
251
|
+
|
|
252
|
+
The ``_greeks_history`` dict records ``net_delta``, ``net_gamma``,
|
|
253
|
+
``hedge_ratio``, and ``stock_position`` at every step.
|
|
254
|
+
|
|
255
|
+
Parameters
|
|
256
|
+
----------
|
|
257
|
+
K1 : float
|
|
258
|
+
Strike of the *primary* (long) option.
|
|
259
|
+
K2 : float
|
|
260
|
+
Strike of the *hedge* option (must differ from K1 for the
|
|
261
|
+
gamma hedge to be non-trivial).
|
|
262
|
+
T_total : float
|
|
263
|
+
Time to expiry at inception (years).
|
|
264
|
+
r : float
|
|
265
|
+
Risk-free rate.
|
|
266
|
+
sigma : float
|
|
267
|
+
Implied volatility (flat smile assumed).
|
|
268
|
+
n_steps : int
|
|
269
|
+
Total rebalancing steps.
|
|
270
|
+
option_type : str
|
|
271
|
+
``'call'`` or ``'put'`` for both legs.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
def __init__(self, K1: float, K2: float, T_total: float, r: float,
|
|
275
|
+
sigma: float, n_steps: int = 252, option_type: str = "call"):
|
|
276
|
+
super().__init__()
|
|
277
|
+
self.K1 = K1
|
|
278
|
+
self.K2 = K2
|
|
279
|
+
self.T_total = T_total
|
|
280
|
+
self.r = r
|
|
281
|
+
self.sigma = sigma
|
|
282
|
+
self.n_steps = n_steps
|
|
283
|
+
self.option_type = option_type
|
|
284
|
+
self._greeks_history: dict[str, list] = {
|
|
285
|
+
"net_delta": [], "net_gamma": [], "hedge_ratio": [], "stock_position": []
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
def _delta(self, S: float, K: float, T_remain: float) -> float:
|
|
289
|
+
from scipy.stats import norm
|
|
290
|
+
if T_remain <= 0:
|
|
291
|
+
return 0.0
|
|
292
|
+
d1 = (np.log(S / K) + (self.r + 0.5 * self.sigma ** 2) * T_remain) / \
|
|
293
|
+
(self.sigma * np.sqrt(T_remain))
|
|
294
|
+
if self.option_type == "call":
|
|
295
|
+
return float(norm.cdf(d1))
|
|
296
|
+
return float(norm.cdf(d1) - 1.0)
|
|
297
|
+
|
|
298
|
+
def _gamma(self, S: float, K: float, T_remain: float) -> float:
|
|
299
|
+
from scipy.stats import norm
|
|
300
|
+
if T_remain <= 0:
|
|
301
|
+
return 0.0
|
|
302
|
+
d1 = (np.log(S / K) + (self.r + 0.5 * self.sigma ** 2) * T_remain) / \
|
|
303
|
+
(self.sigma * np.sqrt(T_remain))
|
|
304
|
+
return float(norm.pdf(d1) / (S * self.sigma * np.sqrt(T_remain)))
|
|
305
|
+
|
|
306
|
+
def on_data(self, step: int, price: float, **kwargs) -> float:
|
|
307
|
+
T_remain = max(self.T_total * (1 - step / self.n_steps), 0.0)
|
|
308
|
+
delta1 = self._delta(price, self.K1, T_remain)
|
|
309
|
+
gamma1 = self._gamma(price, self.K1, T_remain)
|
|
310
|
+
delta2 = self._delta(price, self.K2, T_remain)
|
|
311
|
+
gamma2 = self._gamma(price, self.K2, T_remain)
|
|
312
|
+
|
|
313
|
+
# Hedge ratio neutralises gamma
|
|
314
|
+
Q_hedge = gamma1 / gamma2 if abs(gamma2) > 1e-12 else 0.0
|
|
315
|
+
# Net delta after gamma hedge; we hold -net_delta in underlying
|
|
316
|
+
net_delta = delta1 - Q_hedge * delta2
|
|
317
|
+
stock_position = -net_delta
|
|
318
|
+
|
|
319
|
+
self._greeks_history["net_delta"].append(net_delta + stock_position) # ≈ 0
|
|
320
|
+
self._greeks_history["net_gamma"].append(gamma1 - Q_hedge * gamma2) # ≈ 0
|
|
321
|
+
self._greeks_history["hedge_ratio"].append(Q_hedge)
|
|
322
|
+
self._greeks_history["stock_position"].append(stock_position)
|
|
323
|
+
return stock_position
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class StraddleStrategy(Strategy):
|
|
327
|
+
"""Buy a straddle at regular intervals.
|
|
328
|
+
|
|
329
|
+
This is a simple strategy that opens a new straddle position every
|
|
330
|
+
``interval`` steps by buying one unit of the asset and recording
|
|
331
|
+
the entry price.
|
|
332
|
+
|
|
333
|
+
Parameters
|
|
334
|
+
----------
|
|
335
|
+
interval : int
|
|
336
|
+
Number of steps between new straddle entries.
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
def __init__(self, interval: int = 21):
|
|
340
|
+
super().__init__()
|
|
341
|
+
self.interval = interval
|
|
342
|
+
self._entries: list[float] = []
|
|
343
|
+
|
|
344
|
+
def on_data(self, step: int, price: float, **kwargs) -> float:
|
|
345
|
+
if step % self.interval == 0:
|
|
346
|
+
self._entries.append(price)
|
|
347
|
+
return self.position + 1.0 # add one unit
|
|
348
|
+
return self.position
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Public API for differentiable tensor operations.
|
|
3
|
+
|
|
4
|
+
All operations are implemented in tensor.py alongside the Tensor class
|
|
5
|
+
(they share the _unbroadcast helper and Tensor internals). This module
|
|
6
|
+
re-exports them with a clean namespace for external use.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from tensorquantlib.core import ops
|
|
10
|
+
z = ops.exp(x)
|
|
11
|
+
z = ops.norm_cdf(d1)
|
|
12
|
+
|
|
13
|
+
Note: ``tsum`` and ``tpow`` are used instead of ``sum`` / ``pow`` to avoid
|
|
14
|
+
shadowing Python built-ins when doing ``from ops import *``.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from tensorquantlib.core.tensor import tensor_abs as abs
|
|
18
|
+
from tensorquantlib.core.tensor import tensor_add as add
|
|
19
|
+
from tensorquantlib.core.tensor import tensor_clip as clip
|
|
20
|
+
from tensorquantlib.core.tensor import tensor_cos as cos
|
|
21
|
+
from tensorquantlib.core.tensor import tensor_div as div
|
|
22
|
+
from tensorquantlib.core.tensor import tensor_exp as exp
|
|
23
|
+
from tensorquantlib.core.tensor import tensor_log as log
|
|
24
|
+
from tensorquantlib.core.tensor import tensor_matmul as matmul
|
|
25
|
+
from tensorquantlib.core.tensor import tensor_maximum as maximum
|
|
26
|
+
from tensorquantlib.core.tensor import tensor_mean as mean
|
|
27
|
+
from tensorquantlib.core.tensor import tensor_mul as mul
|
|
28
|
+
from tensorquantlib.core.tensor import tensor_neg as neg
|
|
29
|
+
from tensorquantlib.core.tensor import tensor_norm_cdf as norm_cdf
|
|
30
|
+
from tensorquantlib.core.tensor import tensor_pow as tpow
|
|
31
|
+
from tensorquantlib.core.tensor import tensor_reshape as reshape
|
|
32
|
+
from tensorquantlib.core.tensor import tensor_sin as sin
|
|
33
|
+
from tensorquantlib.core.tensor import tensor_softmax as softmax
|
|
34
|
+
from tensorquantlib.core.tensor import tensor_sqrt as sqrt
|
|
35
|
+
from tensorquantlib.core.tensor import tensor_sub as sub
|
|
36
|
+
from tensorquantlib.core.tensor import tensor_sum as tsum
|
|
37
|
+
from tensorquantlib.core.tensor import tensor_tanh as tanh
|
|
38
|
+
from tensorquantlib.core.tensor import tensor_transpose as transpose
|
|
39
|
+
from tensorquantlib.core.tensor import tensor_where as where
|
|
40
|
+
|
|
41
|
+
# Legacy aliases kept for backward compatibility (do NOT use in new code —
|
|
42
|
+
# they shadow Python built-ins when imported with ``from ops import *``).
|
|
43
|
+
pow = tpow # noqa: A001
|
|
44
|
+
sum = tsum # noqa: A001
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"abs",
|
|
48
|
+
"add",
|
|
49
|
+
"clip",
|
|
50
|
+
"cos",
|
|
51
|
+
"div",
|
|
52
|
+
"exp",
|
|
53
|
+
"log",
|
|
54
|
+
"matmul",
|
|
55
|
+
"maximum",
|
|
56
|
+
"mean",
|
|
57
|
+
"mul",
|
|
58
|
+
"neg",
|
|
59
|
+
"norm_cdf",
|
|
60
|
+
"reshape",
|
|
61
|
+
"sin",
|
|
62
|
+
"softmax",
|
|
63
|
+
"sqrt",
|
|
64
|
+
"sub",
|
|
65
|
+
"tanh",
|
|
66
|
+
"tpow",
|
|
67
|
+
"tsum",
|
|
68
|
+
"transpose",
|
|
69
|
+
"where",
|
|
70
|
+
]
|