openbacktesting 0.2.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.
- openbacktesting/__init__.py +85 -0
- openbacktesting/aggregation.py +8 -0
- openbacktesting/broker/__init__.py +54 -0
- openbacktesting/broker/commission.py +57 -0
- openbacktesting/broker/core.py +1122 -0
- openbacktesting/broker/execution.py +62 -0
- openbacktesting/broker/instrument.py +106 -0
- openbacktesting/broker/ledger.py +60 -0
- openbacktesting/broker/models.py +236 -0
- openbacktesting/broker/observations.py +99 -0
- openbacktesting/broker/requests.py +192 -0
- openbacktesting/broker/sizing.py +76 -0
- openbacktesting/colors.py +175 -0
- openbacktesting/data/__init__.py +20 -0
- openbacktesting/data/aggregation.py +39 -0
- openbacktesting/data/context.py +30 -0
- openbacktesting/data/core.py +218 -0
- openbacktesting/data/generators.py +54 -0
- openbacktesting/data/strategy_data.py +103 -0
- openbacktesting/data/timeframe.py +69 -0
- openbacktesting/engine.py +34 -0
- openbacktesting/helpers.py +77 -0
- openbacktesting/indicator_api.py +10 -0
- openbacktesting/indicator_methods.py +123 -0
- openbacktesting/indicator_types.py +19 -0
- openbacktesting/indicators/__init__.py +7 -0
- openbacktesting/indicators/api.py +97 -0
- openbacktesting/indicators/calculus.py +75 -0
- openbacktesting/indicators/candles/__init__.py +0 -0
- openbacktesting/indicators/candles/cdl_doji.py +17 -0
- openbacktesting/indicators/candles/cdl_engulfing.py +14 -0
- openbacktesting/indicators/candles/cdl_eveningstar.py +15 -0
- openbacktesting/indicators/candles/cdl_hammer.py +14 -0
- openbacktesting/indicators/candles/cdl_harami.py +14 -0
- openbacktesting/indicators/candles/cdl_inside.py +14 -0
- openbacktesting/indicators/candles/cdl_marubozu.py +14 -0
- openbacktesting/indicators/candles/cdl_morningstar.py +15 -0
- openbacktesting/indicators/candles/cdl_shootingstar.py +14 -0
- openbacktesting/indicators/candles/cdl_z.py +28 -0
- openbacktesting/indicators/candles/ha.py +19 -0
- openbacktesting/indicators/catalog.json +8348 -0
- openbacktesting/indicators/common.py +94 -0
- openbacktesting/indicators/cycles/__init__.py +0 -0
- openbacktesting/indicators/cycles/dsp.py +10 -0
- openbacktesting/indicators/cycles/ebsw.py +10 -0
- openbacktesting/indicators/cycles/ht_dcperiod.py +10 -0
- openbacktesting/indicators/cycles/ht_dcphase.py +10 -0
- openbacktesting/indicators/cycles/ht_phasor.py +17 -0
- openbacktesting/indicators/cycles/ht_sine.py +17 -0
- openbacktesting/indicators/cycles/ht_trendmode.py +10 -0
- openbacktesting/indicators/cycles/msw.py +19 -0
- openbacktesting/indicators/methods.py +5762 -0
- openbacktesting/indicators/momentum/__init__.py +0 -0
- openbacktesting/indicators/momentum/ac.py +9 -0
- openbacktesting/indicators/momentum/ao.py +10 -0
- openbacktesting/indicators/momentum/apo.py +10 -0
- openbacktesting/indicators/momentum/bias.py +10 -0
- openbacktesting/indicators/momentum/bop.py +10 -0
- openbacktesting/indicators/momentum/brar.py +26 -0
- openbacktesting/indicators/momentum/cci.py +10 -0
- openbacktesting/indicators/momentum/cfo.py +10 -0
- openbacktesting/indicators/momentum/cg.py +10 -0
- openbacktesting/indicators/momentum/cmo.py +10 -0
- openbacktesting/indicators/momentum/coppock.py +10 -0
- openbacktesting/indicators/momentum/crsi.py +28 -0
- openbacktesting/indicators/momentum/cti.py +10 -0
- openbacktesting/indicators/momentum/dm.py +17 -0
- openbacktesting/indicators/momentum/er.py +10 -0
- openbacktesting/indicators/momentum/eri.py +17 -0
- openbacktesting/indicators/momentum/fisher.py +17 -0
- openbacktesting/indicators/momentum/fosc.py +10 -0
- openbacktesting/indicators/momentum/gator.py +13 -0
- openbacktesting/indicators/momentum/ibs.py +7 -0
- openbacktesting/indicators/momentum/inertia.py +22 -0
- openbacktesting/indicators/momentum/kdj.py +18 -0
- openbacktesting/indicators/momentum/kst.py +30 -0
- openbacktesting/indicators/momentum/lrsi.py +10 -0
- openbacktesting/indicators/momentum/macd.py +27 -0
- openbacktesting/indicators/momentum/macdext.py +27 -0
- openbacktesting/indicators/momentum/macdfix.py +18 -0
- openbacktesting/indicators/momentum/mom.py +10 -0
- openbacktesting/indicators/momentum/pgo.py +10 -0
- openbacktesting/indicators/momentum/pmo.py +13 -0
- openbacktesting/indicators/momentum/po.py +10 -0
- openbacktesting/indicators/momentum/ppo.py +20 -0
- openbacktesting/indicators/momentum/psl.py +12 -0
- openbacktesting/indicators/momentum/pvo.py +20 -0
- openbacktesting/indicators/momentum/qqe.py +31 -0
- openbacktesting/indicators/momentum/rci.py +20 -0
- openbacktesting/indicators/momentum/rmi.py +7 -0
- openbacktesting/indicators/momentum/roc.py +10 -0
- openbacktesting/indicators/momentum/rocp.py +10 -0
- openbacktesting/indicators/momentum/rocr.py +10 -0
- openbacktesting/indicators/momentum/rocr100.py +10 -0
- openbacktesting/indicators/momentum/rsi.py +10 -0
- openbacktesting/indicators/momentum/rsx.py +10 -0
- openbacktesting/indicators/momentum/rvgi.py +26 -0
- openbacktesting/indicators/momentum/slope.py +17 -0
- openbacktesting/indicators/momentum/smc_sweep.py +18 -0
- openbacktesting/indicators/momentum/smi.py +21 -0
- openbacktesting/indicators/momentum/smi_stochastic.py +15 -0
- openbacktesting/indicators/momentum/squeeze.py +47 -0
- openbacktesting/indicators/momentum/squeeze_pro.py +53 -0
- openbacktesting/indicators/momentum/stc.py +20 -0
- openbacktesting/indicators/momentum/stoch.py +19 -0
- openbacktesting/indicators/momentum/stochf.py +19 -0
- openbacktesting/indicators/momentum/stochrsi.py +19 -0
- openbacktesting/indicators/momentum/td_seq.py +17 -0
- openbacktesting/indicators/momentum/trix.py +19 -0
- openbacktesting/indicators/momentum/trixh.py +20 -0
- openbacktesting/indicators/momentum/tsi.py +26 -0
- openbacktesting/indicators/momentum/uo.py +22 -0
- openbacktesting/indicators/momentum/vwmacd.py +20 -0
- openbacktesting/indicators/momentum/wavetrend.py +15 -0
- openbacktesting/indicators/momentum/willr.py +10 -0
- openbacktesting/indicators/overlap/__init__.py +0 -0
- openbacktesting/indicators/overlap/alligator.py +13 -0
- openbacktesting/indicators/overlap/alma.py +33 -0
- openbacktesting/indicators/overlap/anchored_vwap.py +50 -0
- openbacktesting/indicators/overlap/anchored_vwap_bands.py +13 -0
- openbacktesting/indicators/overlap/avgprice.py +10 -0
- openbacktesting/indicators/overlap/dema.py +10 -0
- openbacktesting/indicators/overlap/ema.py +12 -0
- openbacktesting/indicators/overlap/frama.py +29 -0
- openbacktesting/indicators/overlap/fwma.py +10 -0
- openbacktesting/indicators/overlap/hilo.py +26 -0
- openbacktesting/indicators/overlap/hl2.py +10 -0
- openbacktesting/indicators/overlap/hlc3.py +10 -0
- openbacktesting/indicators/overlap/hma.py +10 -0
- openbacktesting/indicators/overlap/ht_trendline.py +10 -0
- openbacktesting/indicators/overlap/hwma.py +10 -0
- openbacktesting/indicators/overlap/ichimoku.py +44 -0
- openbacktesting/indicators/overlap/jma.py +10 -0
- openbacktesting/indicators/overlap/kama.py +10 -0
- openbacktesting/indicators/overlap/linreg.py +15 -0
- openbacktesting/indicators/overlap/linregangle.py +10 -0
- openbacktesting/indicators/overlap/linregintercept.py +10 -0
- openbacktesting/indicators/overlap/linregslope.py +10 -0
- openbacktesting/indicators/overlap/ma.py +10 -0
- openbacktesting/indicators/overlap/ma_envelopes.py +16 -0
- openbacktesting/indicators/overlap/mama.py +17 -0
- openbacktesting/indicators/overlap/mavp.py +17 -0
- openbacktesting/indicators/overlap/mcgd.py +10 -0
- openbacktesting/indicators/overlap/medprice.py +10 -0
- openbacktesting/indicators/overlap/midpoint.py +10 -0
- openbacktesting/indicators/overlap/midprice.py +10 -0
- openbacktesting/indicators/overlap/mmar.py +21 -0
- openbacktesting/indicators/overlap/ohlc4.py +10 -0
- openbacktesting/indicators/overlap/pwma.py +10 -0
- openbacktesting/indicators/overlap/rainbow.py +25 -0
- openbacktesting/indicators/overlap/rma.py +10 -0
- openbacktesting/indicators/overlap/sinwma.py +10 -0
- openbacktesting/indicators/overlap/sma.py +14 -0
- openbacktesting/indicators/overlap/ssf.py +10 -0
- openbacktesting/indicators/overlap/supertrend.py +21 -0
- openbacktesting/indicators/overlap/swma.py +10 -0
- openbacktesting/indicators/overlap/t3.py +10 -0
- openbacktesting/indicators/overlap/tema.py +10 -0
- openbacktesting/indicators/overlap/trima.py +10 -0
- openbacktesting/indicators/overlap/tsf.py +10 -0
- openbacktesting/indicators/overlap/typprice.py +10 -0
- openbacktesting/indicators/overlap/vidya.py +10 -0
- openbacktesting/indicators/overlap/vwap.py +10 -0
- openbacktesting/indicators/overlap/vwma.py +10 -0
- openbacktesting/indicators/overlap/wcp.py +10 -0
- openbacktesting/indicators/overlap/wma.py +10 -0
- openbacktesting/indicators/overlap/zlma.py +10 -0
- openbacktesting/indicators/performance/__init__.py +0 -0
- openbacktesting/indicators/performance/drawdown.py +18 -0
- openbacktesting/indicators/performance/log_return.py +10 -0
- openbacktesting/indicators/performance/percent_return.py +10 -0
- openbacktesting/indicators/predicates.py +88 -0
- openbacktesting/indicators/registry.py +571 -0
- openbacktesting/indicators/runtime.py +290 -0
- openbacktesting/indicators/statistics/__init__.py +0 -0
- openbacktesting/indicators/statistics/beta.py +10 -0
- openbacktesting/indicators/statistics/correl.py +10 -0
- openbacktesting/indicators/statistics/entropy.py +10 -0
- openbacktesting/indicators/statistics/kurtosis.py +10 -0
- openbacktesting/indicators/statistics/mad.py +10 -0
- openbacktesting/indicators/statistics/md.py +10 -0
- openbacktesting/indicators/statistics/median.py +10 -0
- openbacktesting/indicators/statistics/mode.py +48 -0
- openbacktesting/indicators/statistics/quantile.py +10 -0
- openbacktesting/indicators/statistics/skew.py +10 -0
- openbacktesting/indicators/statistics/stderr.py +10 -0
- openbacktesting/indicators/statistics/stdev.py +10 -0
- openbacktesting/indicators/statistics/variance.py +10 -0
- openbacktesting/indicators/statistics/zscore.py +10 -0
- openbacktesting/indicators/trend/__init__.py +0 -0
- openbacktesting/indicators/trend/adx.py +28 -0
- openbacktesting/indicators/trend/adxr.py +28 -0
- openbacktesting/indicators/trend/amat.py +19 -0
- openbacktesting/indicators/trend/aroon.py +18 -0
- openbacktesting/indicators/trend/atr_stop.py +33 -0
- openbacktesting/indicators/trend/chop.py +20 -0
- openbacktesting/indicators/trend/cksp.py +17 -0
- openbacktesting/indicators/trend/cpr.py +57 -0
- openbacktesting/indicators/trend/decay.py +10 -0
- openbacktesting/indicators/trend/decreasing.py +18 -0
- openbacktesting/indicators/trend/dpo.py +12 -0
- openbacktesting/indicators/trend/dx.py +19 -0
- openbacktesting/indicators/trend/edecay.py +10 -0
- openbacktesting/indicators/trend/increasing.py +18 -0
- openbacktesting/indicators/trend/long_run.py +10 -0
- openbacktesting/indicators/trend/minus_dm.py +10 -0
- openbacktesting/indicators/trend/pivot_points.py +89 -0
- openbacktesting/indicators/trend/pivothigh.py +23 -0
- openbacktesting/indicators/trend/pivotlow.py +23 -0
- openbacktesting/indicators/trend/plus_dm.py +10 -0
- openbacktesting/indicators/trend/pmax.py +18 -0
- openbacktesting/indicators/trend/psar.py +19 -0
- openbacktesting/indicators/trend/qstick.py +10 -0
- openbacktesting/indicators/trend/sarext.py +35 -0
- openbacktesting/indicators/trend/short_run.py +10 -0
- openbacktesting/indicators/trend/tsignals.py +26 -0
- openbacktesting/indicators/trend/ttm_trend.py +16 -0
- openbacktesting/indicators/trend/vhf.py +10 -0
- openbacktesting/indicators/trend/volatility_stop.py +33 -0
- openbacktesting/indicators/trend/vortex.py +17 -0
- openbacktesting/indicators/trend/xsignals.py +29 -0
- openbacktesting/indicators/types.py +344 -0
- openbacktesting/indicators/utility/__init__.py +0 -0
- openbacktesting/indicators/utility/barssince.py +21 -0
- openbacktesting/indicators/utility/change.py +7 -0
- openbacktesting/indicators/utility/cross.py +12 -0
- openbacktesting/indicators/utility/crossover.py +11 -0
- openbacktesting/indicators/utility/crossunder.py +11 -0
- openbacktesting/indicators/utility/cum.py +7 -0
- openbacktesting/indicators/utility/falling.py +10 -0
- openbacktesting/indicators/utility/highest.py +7 -0
- openbacktesting/indicators/utility/highestbars.py +29 -0
- openbacktesting/indicators/utility/lowest.py +7 -0
- openbacktesting/indicators/utility/lowestbars.py +29 -0
- openbacktesting/indicators/utility/percentile_linear_interpolation.py +12 -0
- openbacktesting/indicators/utility/percentile_nearest_rank.py +16 -0
- openbacktesting/indicators/utility/percentrank.py +7 -0
- openbacktesting/indicators/utility/range.py +8 -0
- openbacktesting/indicators/utility/rising.py +10 -0
- openbacktesting/indicators/utility/rolling_count.py +12 -0
- openbacktesting/indicators/utility/rolling_sum.py +7 -0
- openbacktesting/indicators/utility/running_max.py +7 -0
- openbacktesting/indicators/utility/running_min.py +7 -0
- openbacktesting/indicators/utility/shift.py +7 -0
- openbacktesting/indicators/utility/valuewhen.py +25 -0
- openbacktesting/indicators/volatility/__init__.py +0 -0
- openbacktesting/indicators/volatility/aberration.py +21 -0
- openbacktesting/indicators/volatility/accbands.py +20 -0
- openbacktesting/indicators/volatility/adr.py +7 -0
- openbacktesting/indicators/volatility/atr.py +12 -0
- openbacktesting/indicators/volatility/avolume.py +10 -0
- openbacktesting/indicators/volatility/bbands.py +20 -0
- openbacktesting/indicators/volatility/ce.py +25 -0
- openbacktesting/indicators/volatility/cvi.py +10 -0
- openbacktesting/indicators/volatility/donchian.py +20 -0
- openbacktesting/indicators/volatility/hvol.py +10 -0
- openbacktesting/indicators/volatility/hwc.py +27 -0
- openbacktesting/indicators/volatility/kc.py +27 -0
- openbacktesting/indicators/volatility/massi.py +10 -0
- openbacktesting/indicators/volatility/natr.py +19 -0
- openbacktesting/indicators/volatility/pdist.py +10 -0
- openbacktesting/indicators/volatility/rvi.py +21 -0
- openbacktesting/indicators/volatility/starc.py +11 -0
- openbacktesting/indicators/volatility/thermo.py +28 -0
- openbacktesting/indicators/volatility/true_range.py +31 -0
- openbacktesting/indicators/volatility/ui.py +10 -0
- openbacktesting/indicators/volume/__init__.py +0 -0
- openbacktesting/indicators/volume/ad.py +10 -0
- openbacktesting/indicators/volume/adosc.py +19 -0
- openbacktesting/indicators/volume/aobv.py +31 -0
- openbacktesting/indicators/volume/cmf.py +12 -0
- openbacktesting/indicators/volume/efi.py +12 -0
- openbacktesting/indicators/volume/emv.py +10 -0
- openbacktesting/indicators/volume/eom.py +19 -0
- openbacktesting/indicators/volume/iii.py +9 -0
- openbacktesting/indicators/volume/kvo.py +28 -0
- openbacktesting/indicators/volume/marketfi.py +10 -0
- openbacktesting/indicators/volume/mfi.py +12 -0
- openbacktesting/indicators/volume/nvi.py +26 -0
- openbacktesting/indicators/volume/obv.py +10 -0
- openbacktesting/indicators/volume/pvi.py +26 -0
- openbacktesting/indicators/volume/pvol.py +10 -0
- openbacktesting/indicators/volume/pvr.py +10 -0
- openbacktesting/indicators/volume/pvt.py +10 -0
- openbacktesting/indicators/volume/rvol.py +8 -0
- openbacktesting/indicators/volume/vfi.py +18 -0
- openbacktesting/indicators/volume/vosc.py +10 -0
- openbacktesting/indicators/volume/wad.py +10 -0
- openbacktesting/indicators/volume/wvad.py +9 -0
- openbacktesting/inputs.py +51 -0
- openbacktesting/lib.py +31 -0
- openbacktesting/logs.py +129 -0
- openbacktesting/optimization.py +8 -0
- openbacktesting/optimizer/__init__.py +25 -0
- openbacktesting/optimizer/_semantics.py +155 -0
- openbacktesting/optimizer/identity.py +45 -0
- openbacktesting/optimizer/models.py +92 -0
- openbacktesting/optimizer/plan.py +129 -0
- openbacktesting/optimizer/portfolio-result.schema.json +4984 -0
- openbacktesting/optimizer/query.py +257 -0
- openbacktesting/optimizer/runner.py +98 -0
- openbacktesting/optimizer/storage.py +261 -0
- openbacktesting/optimizer/validation.py +64 -0
- openbacktesting/parallel.py +9 -0
- openbacktesting/plotting/__init__.py +23 -0
- openbacktesting/plotting/collector.py +509 -0
- openbacktesting/plotting/encoding.py +102 -0
- openbacktesting/plotting/types.py +92 -0
- openbacktesting/portfolio/__init__.py +15 -0
- openbacktesting/portfolio/analysis.py +245 -0
- openbacktesting/portfolio/builder.py +381 -0
- openbacktesting/portfolio/catalog.json +1404 -0
- openbacktesting/portfolio/helpers.py +92 -0
- openbacktesting/portfolio/metrics.py +186 -0
- openbacktesting/portfolio/models.py +63 -0
- openbacktesting/portfolio/periods.py +164 -0
- openbacktesting/portfolio/rates.py +14 -0
- openbacktesting/portfolio/snapshot.py +111 -0
- openbacktesting/portfolio/stats.py +272 -0
- openbacktesting/portfolio/trades.py +136 -0
- openbacktesting/portfolio/trading.py +215 -0
- openbacktesting/py.typed +0 -0
- openbacktesting/runtime.py +330 -0
- openbacktesting/simulation/__init__.py +17 -0
- openbacktesting/simulation/collection.py +13 -0
- openbacktesting/simulation/config.py +241 -0
- openbacktesting/simulation/core.py +528 -0
- openbacktesting/simulation/optimization.py +326 -0
- openbacktesting/simulation/parallel.py +145 -0
- openbacktesting/simulation/variants.py +107 -0
- openbacktesting/strategy/__init__.py +19 -0
- openbacktesting/strategy/bar_state.py +14 -0
- openbacktesting/strategy/base.py +810 -0
- openbacktesting/strategy/declaration.py +90 -0
- openbacktesting/strategy/helpers.py +198 -0
- openbacktesting/strategy/inputs.py +460 -0
- openbacktesting/strategy/sizing.py +80 -0
- openbacktesting/strategy/templates.py +160 -0
- openbacktesting/strategy_data.py +10 -0
- openbacktesting/test/BTCUSD.csv +157 -0
- openbacktesting/test/EURUSD.csv +5001 -0
- openbacktesting/test/GOOG.csv +2149 -0
- openbacktesting/test/__init__.py +29 -0
- openbacktesting/test/__main__.py +11 -0
- openbacktesting/test/_test.py +1312 -0
- openbacktesting/util.py +31 -0
- openbacktesting-0.2.0.dist-info/METADATA +151 -0
- openbacktesting-0.2.0.dist-info/RECORD +350 -0
- openbacktesting-0.2.0.dist-info/WHEEL +4 -0
- openbacktesting-0.2.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Compatibility exports for old type paths; implemented in the indicators subpackage."""
|
|
2
|
+
|
|
3
|
+
from .indicators.types import (
|
|
4
|
+
IndicatorCursor,
|
|
5
|
+
IndicatorError,
|
|
6
|
+
IndicatorHandle,
|
|
7
|
+
IndicatorSpec,
|
|
8
|
+
Parameter,
|
|
9
|
+
immutable,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"IndicatorCursor",
|
|
14
|
+
"IndicatorError",
|
|
15
|
+
"IndicatorHandle",
|
|
16
|
+
"IndicatorSpec",
|
|
17
|
+
"Parameter",
|
|
18
|
+
"immutable",
|
|
19
|
+
]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Public entry points for built-in indicators; computation implementations are maintained by category."""
|
|
2
|
+
|
|
3
|
+
from .runtime import DEFAULT_CACHE_BYTES as DEFAULT_CACHE_BYTES
|
|
4
|
+
from .runtime import IndicatorCache as IndicatorCache
|
|
5
|
+
from .runtime import catalog as catalog
|
|
6
|
+
from .runtime import compute as compute
|
|
7
|
+
from .runtime import describe as describe
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Lightweight adapter for method-style indicator entry points; strategies still handle computation and registration."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
4
|
+
|
|
5
|
+
from .predicates import CrossPredicates
|
|
6
|
+
from .types import IndicatorError, IndicatorHandle
|
|
7
|
+
|
|
8
|
+
Source = str | IndicatorHandle
|
|
9
|
+
Inputs = Mapping[str, Source]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class IndicatorResult:
|
|
13
|
+
"""Read-only attribute container for multiple outputs; channel views are created only during initialization."""
|
|
14
|
+
|
|
15
|
+
__slots__ = ("_channels", "_handle")
|
|
16
|
+
|
|
17
|
+
def __init__(self, handle: IndicatorHandle):
|
|
18
|
+
self._handle = handle
|
|
19
|
+
self._channels = {name: handle[name] for name in handle.name}
|
|
20
|
+
|
|
21
|
+
def __getitem__(self, name: str) -> IndicatorHandle:
|
|
22
|
+
return self._channels[name]
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def ready(self):
|
|
26
|
+
"""Minimum-history mask shared by all outputs."""
|
|
27
|
+
return self._handle.ready
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def valid(self):
|
|
31
|
+
"""Underlying validity masks for each channel; check the selected channel before trading."""
|
|
32
|
+
return self._handle.valid
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def metadata(self):
|
|
36
|
+
"""Return an independent copy of the underlying handle's provenance metadata."""
|
|
37
|
+
return self._handle.metadata
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def df(self):
|
|
41
|
+
"""Return a pandas DataFrame copy of the currently visible prefix of all channels."""
|
|
42
|
+
return self._handle.df
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class IndicatorNamespace(CrossPredicates):
|
|
46
|
+
"""Bind a registration callback to one strategy, avoiding an indicator-layer dependency on strategy implementations."""
|
|
47
|
+
|
|
48
|
+
def __init__(self, register: Callable[..., IndicatorHandle]):
|
|
49
|
+
self._register = register
|
|
50
|
+
|
|
51
|
+
def _call(
|
|
52
|
+
self,
|
|
53
|
+
indicator: str,
|
|
54
|
+
primary: str,
|
|
55
|
+
source: Source | None,
|
|
56
|
+
inputs: Inputs | None,
|
|
57
|
+
backend: str | None,
|
|
58
|
+
required_outputs: Sequence[str] | None,
|
|
59
|
+
parameters: dict,
|
|
60
|
+
) -> IndicatorHandle:
|
|
61
|
+
if source is not None:
|
|
62
|
+
if inputs is not None:
|
|
63
|
+
raise IndicatorError(
|
|
64
|
+
"invalid-parameter", indicator, "source and inputs cannot both be specified"
|
|
65
|
+
)
|
|
66
|
+
if not isinstance(source, (str, IndicatorHandle)):
|
|
67
|
+
raise IndicatorError(
|
|
68
|
+
"missing-input", indicator, "source must be a column name or single-channel handle; select a channel from multi-output handles first"
|
|
69
|
+
)
|
|
70
|
+
inputs = {primary: source}
|
|
71
|
+
return self._register(
|
|
72
|
+
indicator,
|
|
73
|
+
inputs=inputs,
|
|
74
|
+
backend=backend,
|
|
75
|
+
required_outputs=required_outputs,
|
|
76
|
+
**parameters,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def _call_inputs(
|
|
80
|
+
self,
|
|
81
|
+
indicator: str,
|
|
82
|
+
sources: dict[str, Source | None],
|
|
83
|
+
inputs: Inputs | None,
|
|
84
|
+
backend: str | None,
|
|
85
|
+
required_outputs: Sequence[str] | None,
|
|
86
|
+
parameters: dict,
|
|
87
|
+
) -> IndicatorHandle:
|
|
88
|
+
bound = {name: source for name, source in sources.items() if source is not None}
|
|
89
|
+
if bound and inputs is not None:
|
|
90
|
+
raise IndicatorError("invalid-parameter", indicator, "Named inputs and inputs cannot both be specified")
|
|
91
|
+
return self._register(
|
|
92
|
+
indicator,
|
|
93
|
+
inputs=bound if bound else inputs,
|
|
94
|
+
backend=backend,
|
|
95
|
+
required_outputs=required_outputs,
|
|
96
|
+
**parameters,
|
|
97
|
+
)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Shared finite-history mathematics for local indicators, independent of registration, caches, and strategies."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from .types import IndicatorError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def clean(source):
|
|
10
|
+
return source.astype(float).where(np.isfinite(source))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def segments(valid):
|
|
14
|
+
"""Return contiguous valid segments; recursive state must be rebuilt after missing data."""
|
|
15
|
+
edges = np.diff(np.r_[False, valid, False].astype(np.int8))
|
|
16
|
+
return zip(np.flatnonzero(edges == 1), np.flatnonzero(edges == -1))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def average(source, length, *, alpha=None, seeded=True):
|
|
20
|
+
"""Recursive average seeded by an SMA or the first value; warm up again after missing data."""
|
|
21
|
+
source = clean(source)
|
|
22
|
+
out = np.full(len(source), np.nan)
|
|
23
|
+
alpha = 2 / (length + 1) if alpha is None else alpha
|
|
24
|
+
for start, end in segments(source.notna().to_numpy()):
|
|
25
|
+
part = source.iloc[start:end].to_numpy(copy=True)
|
|
26
|
+
skip = length - 1 if seeded else 0
|
|
27
|
+
if len(part) <= skip:
|
|
28
|
+
continue
|
|
29
|
+
if seeded:
|
|
30
|
+
part[skip] = part[:length].mean()
|
|
31
|
+
out[start + skip : end] = pd.Series(part[skip:]).ewm(alpha=alpha, adjust=False).mean()
|
|
32
|
+
return pd.Series(out, index=source.index)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def ratio(numerator, denominator):
|
|
36
|
+
return numerator / denominator.where(denominator != 0)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def atr(high, low, close, length):
|
|
40
|
+
previous = clean(close).shift(1)
|
|
41
|
+
ranges = np.maximum.reduce(
|
|
42
|
+
[(clean(high) - clean(low)).to_numpy(), (high - previous).abs(), (low - previous).abs()]
|
|
43
|
+
)
|
|
44
|
+
return average(pd.Series(ranges, index=close.index), length, alpha=1 / length)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def strength(delta, length):
|
|
48
|
+
gains = average(delta.clip(lower=0), length, alpha=1 / length)
|
|
49
|
+
losses = average(-delta.clip(upper=0), length, alpha=1 / length)
|
|
50
|
+
total = gains + losses
|
|
51
|
+
return ratio(100 * gains, total).mask(total == 0, 50.0)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def condition(source, indicator):
|
|
55
|
+
source = clean(source)
|
|
56
|
+
if not source.dropna().isin([0, 1]).all():
|
|
57
|
+
raise IndicatorError("invalid-input", indicator, "Condition inputs allow only 0, 1, or missing values")
|
|
58
|
+
return source
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def pattern_result(calculate, indicator, inputs, minimum, **options):
|
|
62
|
+
"""Call native patterns on valid OHLC segments, preserving integer scores and validity masks separately."""
|
|
63
|
+
frame = pd.DataFrame(inputs)
|
|
64
|
+
values = np.zeros(len(frame), dtype=np.int16)
|
|
65
|
+
valid = np.zeros(len(frame), dtype=bool)
|
|
66
|
+
for start, end in segments(np.isfinite(frame.to_numpy()).all(axis=1)):
|
|
67
|
+
if end - start < minimum:
|
|
68
|
+
continue
|
|
69
|
+
part = frame.iloc[start:end]
|
|
70
|
+
result = calculate(**{key: part[key] for key in inputs}, **options)
|
|
71
|
+
values[start:end] = result.to_numpy(dtype=np.int16)
|
|
72
|
+
valid[start + minimum - 1 : end] = True
|
|
73
|
+
result = pd.Series(values, index=frame.index, name=indicator)
|
|
74
|
+
result.attrs["indicator_valid"] = valid
|
|
75
|
+
return result
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Doji: Threshold based on mean historical range; explicit local implementation avoids implicit TA-Lib and full-sample epsilon."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from ..calculus import clean
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, length, factor):
|
|
9
|
+
width = clean(high) - clean(low)
|
|
10
|
+
body = (clean(close) - clean(open_)).abs()
|
|
11
|
+
threshold = width.rolling(length).mean().shift(1) * factor / 100
|
|
12
|
+
history = np.isfinite(np.column_stack([open_, high, low, close])).all(axis=1)
|
|
13
|
+
valid = body.notna() & threshold.notna()
|
|
14
|
+
valid &= clean(close).where(history).rolling(length + 1).count() == length + 1
|
|
15
|
+
result = ((body <= threshold).astype(np.int16) * 100).rename("cdl_doji")
|
|
16
|
+
result.attrs["indicator_valid"] = valid.to_numpy()
|
|
17
|
+
return result
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""cdl_engulfing: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_engulfing import cdl_engulfing as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_engulfing",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
3,
|
|
14
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""cdl_eveningstar: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_eveningstar import cdl_eveningstar as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, penetration, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_eveningstar",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
13,
|
|
14
|
+
penetration=penetration,
|
|
15
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""cdl_hammer: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_hammer import cdl_hammer as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_hammer",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
12,
|
|
14
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""cdl_harami: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_harami import cdl_harami as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_harami",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
12,
|
|
14
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""cdl_inside: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_inside import cdl_inside as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_inside",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
2,
|
|
14
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""cdl_marubozu: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_marubozu import cdl_marubozu as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_marubozu",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
11,
|
|
14
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""cdl_morningstar: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_morningstar import cdl_morningstar as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, penetration, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_morningstar",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
13,
|
|
14
|
+
penetration=penetration,
|
|
15
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""cdl_shootingstar: Fixed native pattern with a separate validity mask."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_shootingstar import cdl_shootingstar as _calculate
|
|
4
|
+
|
|
5
|
+
from ..calculus import pattern_result
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
return pattern_result(
|
|
10
|
+
_calculate,
|
|
11
|
+
"cdl_shootingstar",
|
|
12
|
+
{"open_": open_, "high": high, "low": low, "close": close},
|
|
13
|
+
12,
|
|
14
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""ta.cdl_z: Computation wrapper for the pinned dependency with canonical outputs."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.cdl_z import cdl_z as _calculate
|
|
4
|
+
|
|
5
|
+
from ..common import named_frame
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, length, ddof, full, talib):
|
|
9
|
+
result = _calculate(
|
|
10
|
+
open_=open_,
|
|
11
|
+
high=high,
|
|
12
|
+
low=low,
|
|
13
|
+
close=close,
|
|
14
|
+
length=length,
|
|
15
|
+
ddof=ddof,
|
|
16
|
+
full=full,
|
|
17
|
+
talib=talib,
|
|
18
|
+
)
|
|
19
|
+
return named_frame(
|
|
20
|
+
result,
|
|
21
|
+
"ta.cdl_z",
|
|
22
|
+
{
|
|
23
|
+
f"open_Z_{length}_{ddof or 1}": "open",
|
|
24
|
+
f"high_Z_{length}_{ddof or 1}": "high",
|
|
25
|
+
f"low_Z_{length}_{ddof or 1}": "low",
|
|
26
|
+
f"close_Z_{length}_{ddof or 1}": "close",
|
|
27
|
+
},
|
|
28
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""ta.ha: Computation wrapper for the pinned dependency with canonical outputs."""
|
|
2
|
+
|
|
3
|
+
from pandas_ta_classic.candles.ha import ha as _calculate
|
|
4
|
+
|
|
5
|
+
from ..common import named_frame
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def compute(*, open_, high, low, close, talib):
|
|
9
|
+
result = _calculate(open_=open_, high=high, low=low, close=close, talib=talib)
|
|
10
|
+
return named_frame(
|
|
11
|
+
result,
|
|
12
|
+
"ta.ha",
|
|
13
|
+
{
|
|
14
|
+
"HA_open": "open",
|
|
15
|
+
"HA_high": "high",
|
|
16
|
+
"HA_low": "low",
|
|
17
|
+
"HA_close": "close",
|
|
18
|
+
},
|
|
19
|
+
)
|