mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-06-27 16:10:07 +08:00
ENH #342 jma indicator MAINT jma ext TST DOC
This commit is contained in:
@@ -55,9 +55,9 @@ Category = {
|
||||
# Overlap
|
||||
"overlap": [
|
||||
"alma", "dema", "ema", "fwma", "hilo", "hl2", "hlc3", "hma", "ichimoku",
|
||||
"kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4", "pwma", "rma",
|
||||
"sinwma", "sma", "ssf", "supertrend", "swma", "t3", "tema", "trima",
|
||||
"vidya", "vwap", "vwma", "wcp", "wma", "zlma"
|
||||
"jma", "kama", "linreg", "mcgd", "midpoint", "midprice", "ohlc4",
|
||||
"pwma", "rma", "sinwma", "sma", "ssf", "supertrend", "swma", "t3",
|
||||
"tema", "trima", "vidya", "vwap", "vwma", "wcp", "wma", "zlma"
|
||||
],
|
||||
# Performance
|
||||
"performance": ["log_return", "percent_return"],
|
||||
|
||||
@@ -1194,6 +1194,11 @@ class AnalysisIndicators(BasePandasObject):
|
||||
result = hwma(close=close, na=na, nb=nb, nc=nc, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def jma(self, length=None, phase=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = jma(close=close, length=length, phase=phase, offset=offset, **kwargs)
|
||||
return self._post_process(result, **kwargs)
|
||||
|
||||
def kama(self, length=None, fast=None, slow=None, offset=None, **kwargs):
|
||||
close = self._get_column(kwargs.pop("close", "close"))
|
||||
result = kama(close=close, length=length, fast=fast, slow=slow, offset=offset, **kwargs)
|
||||
|
||||
@@ -9,6 +9,7 @@ from .hlc3 import hlc3
|
||||
from .hma import hma
|
||||
from .hwma import hwma
|
||||
from .ichimoku import ichimoku
|
||||
from .jma import jma
|
||||
from .kama import kama
|
||||
from .linreg import linreg
|
||||
from .ma import ma
|
||||
|
||||
+65
-49
@@ -1,67 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
from pandas import Series
|
||||
import numpy as np
|
||||
from numpy import average as npAverage
|
||||
from numpy import nan as npNaN
|
||||
import math
|
||||
from numpy import log as npLog
|
||||
from numpy import power as npPower
|
||||
from numpy import sqrt as npSqrt
|
||||
from numpy import zeros_like as npZeroslike
|
||||
from pandas import Series
|
||||
from pandas_ta.utils import get_offset, verify_series
|
||||
|
||||
def jma(close, length=None, phase=0, offset=None, **kwargs):
|
||||
"""
|
||||
Indicator: Jurik Moving Average (JMA)
|
||||
Implementation of: https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
|
||||
Jurik Volty from: https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
|
||||
"""
|
||||
|
||||
def jma(close, length=None, phase=None, offset=None, **kwargs):
|
||||
"""Indicator: Jurik Moving Average (JMA)"""
|
||||
# Validate Arguments
|
||||
length = int(length) if length and length > 0 else 7
|
||||
close = verify_series(close, length)
|
||||
_length = int(length) if length and length > 0 else 7
|
||||
phase = float(phase) if phase and phase != 0 else 0
|
||||
close = verify_series(close, _length)
|
||||
offset = get_offset(offset)
|
||||
if close is None: return
|
||||
|
||||
# Define base variables
|
||||
jma = np.zeros_like(close)
|
||||
Volty = np.zeros_like(close)
|
||||
vSum = np.zeros_like(close)
|
||||
Kv = det0 = det1 = ma2 = 0.0
|
||||
jma = npZeroslike(close)
|
||||
volty = npZeroslike(close)
|
||||
v_sum = npZeroslike(close)
|
||||
|
||||
kv = det0 = det1 = ma2 = 0.0
|
||||
jma[0] = ma1 = uBand = lBand = close[0]
|
||||
|
||||
# Static variables
|
||||
SumLen = 10
|
||||
len = 0.5*(length-1)
|
||||
PR = 0.5 if phase<-100 else 2.5 if phase>100 else phase*0.01+1.5
|
||||
len1 = max((math.log(math.sqrt(len))/math.log(2.0))+2.0, 0)
|
||||
pow1 = max(len1-2.0, 0.5)
|
||||
len2 = math.sqrt(len)*len1
|
||||
bet = len2/(len2+1)
|
||||
beta = 0.45*(length-1)/(0.45*(length-1)+2.0)
|
||||
for i in range(1, close.shape[0]):
|
||||
sum_length = 10
|
||||
length = 0.5 * (_length - 1)
|
||||
pr = 0.5 if phase < -100 else 2.5 if phase > 100 else 1.5 + phase * 0.01
|
||||
length1 = max((npLog(npSqrt(length)) / npLog(2.0)) + 2.0, 0)
|
||||
pow1 = max(length1 - 2.0, 0.5)
|
||||
length2 = length1 * npSqrt(length)
|
||||
bet = length2 / (length2 + 1)
|
||||
beta = 0.45 * (length - 1) / (0.45 * (length - 1) + 2.0)
|
||||
|
||||
m = close.shape[0]
|
||||
for i in range(1, m):
|
||||
price = close[i]
|
||||
|
||||
# Price volatility
|
||||
del1 = price-uBand
|
||||
del2 = price-lBand
|
||||
Volty[i] = max(abs(del1),abs(del2)) if abs(del1)!=abs(del2) else 0
|
||||
del1 = price - uBand
|
||||
del2 = price - lBand
|
||||
volty[i] = max(abs(del1),abs(del2)) if abs(del1)!=abs(del2) else 0
|
||||
|
||||
# Relative price volatility factor
|
||||
vSum[i] = vSum[i-1] + (Volty[i]-Volty[max(i-SumLen,0)])/SumLen
|
||||
avgVolty = np.average(vSum[max(i-65,0):i+1])
|
||||
dVolty = 0 if avgVolty==0 else Volty[i]/avgVolty
|
||||
rVolty = max(1.0, min(math.pow(len1, 1/pow1), dVolty))
|
||||
v_sum[i] = v_sum[i - 1] + (volty[i] - volty[max(i - sum_length, 0)]) / sum_length
|
||||
avg_volty = npAverage(v_sum[max(i - 65, 0):i + 1])
|
||||
d_volty = 0 if avg_volty ==0 else volty[i] / avg_volty
|
||||
r_volty = max(1.0, min(npPower(length1, 1 / pow1), d_volty))
|
||||
|
||||
# Jurik volatility bands
|
||||
pow2 = math.pow(rVolty, pow1)
|
||||
Kv = math.pow(bet, math.sqrt(pow2))
|
||||
uBand = price if (del1 > 0) else price - (Kv*del1)
|
||||
lBand = price if (del2 < 0) else price - (Kv*del2)
|
||||
pow2 = npPower(r_volty, pow1)
|
||||
kv = npPower(bet, npSqrt(pow2))
|
||||
uBand = price if (del1 > 0) else price - (kv * del1)
|
||||
lBand = price if (del2 < 0) else price - (kv * del2)
|
||||
|
||||
# Jurik Dynamic Factor
|
||||
power = math.pow(rVolty, pow1)
|
||||
alpha = math.pow(beta, power)
|
||||
power = npPower(r_volty, pow1)
|
||||
alpha = npPower(beta, power)
|
||||
|
||||
# 1st stage - prelimimary smoothing by adaptive EMA
|
||||
ma1 = ((1-alpha)*price)+(alpha*ma1) #
|
||||
ma1 = ((1 - alpha) * price) + (alpha * ma1)
|
||||
|
||||
# 2nd stage - one more prelimimary smoothing by Kalman filter
|
||||
det0 = ((price-ma1)*(1-beta))+(beta*det0)
|
||||
ma2 = ma1+PR*det0
|
||||
det0 = ((price - ma1) * (1 - beta)) + (beta * det0)
|
||||
ma2 = ma1 + pr * det0
|
||||
|
||||
# 3rd stage - final smoothing by unique Jurik adaptive filter
|
||||
det1 = ((ma2-jma[i-1])*(1-alpha)*(1-alpha))+(alpha*alpha*det1)
|
||||
det1 = ((ma2 - jma[i - 1]) * (1 - alpha) * (1 - alpha)) + (alpha * alpha * det1)
|
||||
jma[i] = jma[i-1] + det1
|
||||
|
||||
# Remove initial lookback data and convert to pandas frame
|
||||
jma[0:length-1] = npNaN
|
||||
jma[0:_length - 1] = npNaN
|
||||
jma = Series(jma, index=close.index)
|
||||
|
||||
# Offset
|
||||
@@ -75,27 +87,31 @@ def jma(close, length=None, phase=0, offset=None, **kwargs):
|
||||
jma.fillna(method=kwargs["fill_method"], inplace=True)
|
||||
|
||||
# Name & Category
|
||||
jma.name = f"JMA_{length}"
|
||||
jma.name = f"JMA_{_length}_{phase}"
|
||||
jma.category = "overlap"
|
||||
|
||||
return jma
|
||||
|
||||
|
||||
jma.__doc__ = \
|
||||
""" Jurik Moving Average Average (JMA)
|
||||
"""Jurik Moving Average Average (JMA)
|
||||
|
||||
Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the "true"
|
||||
underlying activity. It has extremely low lag, is very smooth and is responsive
|
||||
to market gaps.
|
||||
|
||||
Sources:
|
||||
Implementation of: https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
|
||||
https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
|
||||
https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
|
||||
|
||||
Calculation:
|
||||
Default Inputs:
|
||||
length=7
|
||||
phase=0
|
||||
length=7, phase=0
|
||||
|
||||
Args:
|
||||
close (pd.Series): Series of 'close's
|
||||
length (int): Period of calculation. Default: 7
|
||||
phase (float): how heavy/light the average is [-100, 100] Default: 0
|
||||
phase (float): How heavy/light the average is [-100, 100]. Default: 0
|
||||
offset (int): How many lengths to offset the result. Default: 0
|
||||
|
||||
Kwargs:
|
||||
|
||||
@@ -19,7 +19,7 @@ setup(
|
||||
"pandas_ta.volatility",
|
||||
"pandas_ta.volume"
|
||||
],
|
||||
version=".".join(("0", "3", "10b")),
|
||||
version=".".join(("0", "3", "11b")),
|
||||
description=long_description,
|
||||
long_description=long_description,
|
||||
author="Kevin Johnson",
|
||||
|
||||
@@ -63,6 +63,11 @@ class TestOverlapExtension(TestCase):
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "HWMA_0.2_0.1_0.1")
|
||||
|
||||
def test_jma_ext(self):
|
||||
self.data.ta.jma(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
self.assertEqual(self.data.columns[-1], "JMA_7_0")
|
||||
|
||||
def test_kama_ext(self):
|
||||
self.data.ta.kama(append=True)
|
||||
self.assertIsInstance(self.data, DataFrame)
|
||||
|
||||
@@ -139,6 +139,11 @@ class TestOverlap(TestCase):
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "KAMA_10_2_30")
|
||||
|
||||
def test_jma(self):
|
||||
result = pandas_ta.jma(self.close)
|
||||
self.assertIsInstance(result, Series)
|
||||
self.assertEqual(result.name, "JMA_7_0")
|
||||
|
||||
def test_ichimoku(self):
|
||||
ichimoku, span = pandas_ta.ichimoku(self.high, self.low, self.close)
|
||||
self.assertIsInstance(ichimoku, DataFrame)
|
||||
|
||||
Reference in New Issue
Block a user