Skip to content

Commit b7968e4

Browse files
authored
change FmpCharts to FmpChartData (#19)
1 parent ca633ac commit b7968e4

File tree

2 files changed

+319
-3
lines changed

2 files changed

+319
-3
lines changed
Lines changed: 242 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,23 @@
66
from fmp_py.fmp_historical_data import FmpHistoricalData
77
from ta.trend import SMAIndicator, EMAIndicator, WMAIndicator, ADXIndicator
88
from ta.momentum import RSIIndicator
9-
from ta.volume import VolumeWeightedAveragePrice, MFIIndicator, AccDistIndexIndicator
9+
from ta.volume import (
10+
VolumeWeightedAveragePrice,
11+
MFIIndicator,
12+
AccDistIndexIndicator,
13+
OnBalanceVolumeIndicator,
14+
ChaikinMoneyFlowIndicator,
15+
ForceIndexIndicator,
16+
EaseOfMovementIndicator,
17+
VolumePriceTrendIndicator,
18+
NegativeVolumeIndexIndicator,
19+
)
1020
from ta.volatility import AverageTrueRange, BollingerBands
1121

1222
load_dotenv()
1323

1424

15-
class FmpCharts(FmpBase):
25+
class FmpChartData(FmpBase):
1626
def __init__(
1727
self,
1828
symbol: str,
@@ -30,6 +40,234 @@ def __init__(
3040
########################### VOLUME INDICATORS ############################
3141
##########################################################################
3242

43+
####################################
44+
# Negative Volume Index Indicator
45+
####################################
46+
def nvi(self) -> None:
47+
"""
48+
Calculates the Negative Volume Index (NVI) for the chart data.
49+
50+
The Negative Volume Index (NVI) is a technical indicator that uses volume to predict
51+
changes in stock prices. It is calculated by summing the percentage changes in price
52+
on days with declining volume and subtracting the sum of the percentage changes on
53+
days with increasing volume.
54+
55+
This method modifies the `chart` attribute of the object by adding a new column
56+
called "nvi" that contains the NVI values.
57+
58+
Returns:
59+
None
60+
61+
Example:
62+
>>> fmp = FmpCharts(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
63+
>>> fmp.nvi()
64+
>>> print(fmp.return_chart())
65+
"""
66+
chart = self.chart.copy()
67+
chart["nvi"] = (
68+
NegativeVolumeIndexIndicator(
69+
close=chart["close"], volume=chart["volume"], fillna=True
70+
)
71+
.negative_volume_index()
72+
.round(2)
73+
.astype(float)
74+
)
75+
self.chart = chart
76+
77+
####################################
78+
# Volume Price Trend Indicator
79+
####################################
80+
def vpt(self) -> None:
81+
"""
82+
Calculates the Volume Price Trend (VPT) indicator for the chart data.
83+
84+
The Volume Price Trend (VPT) indicator measures the strength of a price trend by
85+
analyzing the relationship between volume and price. It is used to identify
86+
potential reversals or confirm the strength of a trend.
87+
88+
This method modifies the `chart` attribute of the object by adding a new column
89+
called "vpt" that contains the calculated VPT values.
90+
91+
Returns:
92+
None
93+
94+
Example:
95+
>>> fmp = FmpCharts(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
96+
>>> fmp.vpt()
97+
>>> print(fmp.return_chart())
98+
"""
99+
chart = self.chart.copy()
100+
chart["vpt"] = (
101+
VolumePriceTrendIndicator(
102+
close=chart["close"],
103+
volume=chart["volume"],
104+
fillna=True,
105+
).volume_price_trend()
106+
).astype(int)
107+
self.chart = chart
108+
109+
####################################
110+
# SMA Ease of Movement Indicator
111+
####################################
112+
def sma_eom(self, period: int = 14) -> None:
113+
"""
114+
Calculates the Simple Moving Average (SMA) of the Ease of Movement (EOM) indicator.
115+
116+
Args:
117+
period (int): The number of periods to consider for calculating the SMA. Default is 14.
118+
119+
Returns:
120+
None
121+
122+
"""
123+
chart = self.chart.copy()
124+
chart[f"sma_eom{period}"] = (
125+
EaseOfMovementIndicator(
126+
high=chart["high"],
127+
low=chart["low"],
128+
volume=chart["volume"],
129+
window=period,
130+
fillna=True,
131+
)
132+
.sma_ease_of_movement()
133+
.round(2)
134+
.astype(float)
135+
)
136+
137+
self.chart = chart
138+
139+
##################################
140+
# Ease of Movement Indicator
141+
##################################
142+
def eom(self, period: int = 14) -> None:
143+
"""
144+
Calculates the Ease of Movement (EOM) indicator for the given chart data.
145+
146+
Parameters:
147+
period (int): The number of periods to consider for the EOM calculation. Default is 14.
148+
149+
Returns:
150+
None
151+
152+
Notes:
153+
- The EOM indicator measures the relationship between price change and volume.
154+
- It helps identify potential price reversals and divergences.
155+
156+
Example:
157+
>>> fmp = FmpCharts(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
158+
>>> fmp.eom(14)
159+
>>> print(fmp.return_chart())
160+
"""
161+
chart = self.chart.copy()
162+
chart[f"eom{period}"] = (
163+
EaseOfMovementIndicator(
164+
high=chart["high"],
165+
low=chart["low"],
166+
volume=chart["volume"],
167+
window=period,
168+
fillna=True,
169+
)
170+
.ease_of_movement()
171+
.round(2)
172+
.astype(float)
173+
)
174+
175+
self.chart = chart
176+
177+
##################################
178+
# Force Index Indicator
179+
##################################
180+
def fi(self, period: int = 13) -> None:
181+
"""
182+
Calculates and adds the Force Index (FI) to the chart data.
183+
184+
The Force Index is a technical indicator that measures the force behind price movements based on the combination of
185+
price change and trading volume. It helps identify strong trends and potential reversals.
186+
187+
Args:
188+
period (int, optional): The period used to calculate the Force Index. Defaults to 13.
189+
190+
Returns:
191+
None
192+
193+
Example:
194+
>>> fmp = FmpCharts(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
195+
>>> fmp.fi(13)
196+
>>> print(fmp.return_chart())
197+
"""
198+
chart = self.chart.copy()
199+
chart[f"fi{period}"] = (
200+
ForceIndexIndicator(
201+
close=chart["close"], volume=chart["volume"], window=period
202+
)
203+
.force_index()
204+
.round(2)
205+
).astype(float)
206+
self.chart = chart
207+
208+
#################################
209+
# Chaikin Money Flow Indicator
210+
#################################
211+
def cmf(self, period: int = 20) -> None:
212+
"""
213+
Calculates the Chaikin Money Flow (CMF) indicator for the chart data.
214+
215+
Args:
216+
period (int): The number of periods to consider for the CMF calculation. Default is 20.
217+
218+
Returns:
219+
None. The CMF values are added as a new column 'cmf' to the chart data.
220+
221+
Example:
222+
>>> fmp = FmpCharts(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
223+
>>> fmp.cmf()
224+
>>> print(fmp.return_chart())
225+
"""
226+
chart = self.chart.copy()
227+
chart["cmf"] = (
228+
ChaikinMoneyFlowIndicator(
229+
high=chart["high"],
230+
low=chart["low"],
231+
close=chart["close"],
232+
volume=chart["volume"],
233+
window=period,
234+
fillna=True,
235+
)
236+
.chaikin_money_flow()
237+
.round(2)
238+
).astype(float)
239+
240+
self.chart = chart
241+
242+
#################################
243+
# On Balance Volume Indicator
244+
#################################
245+
def obv(self) -> None:
246+
"""
247+
Calculates the On-Balance Volume (OBV) indicator for the chart data.
248+
249+
The On-Balance Volume (OBV) indicator measures the cumulative buying and selling pressure based on the volume of trades.
250+
It is used to identify the strength of a trend and potential reversals.
251+
252+
Returns:
253+
None
254+
255+
Example:
256+
>>> fmp = FmpCharts(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
257+
>>> fmp.obv()
258+
>>> print(fmp.return_chart())
259+
"""
260+
chart = self.chart.copy()
261+
chart["obv"] = (
262+
OnBalanceVolumeIndicator(
263+
close=chart["close"],
264+
volume=chart["volume"],
265+
fillna=True,
266+
).on_balance_volume()
267+
).astype(int)
268+
269+
self.chart = chart
270+
33271
#################################
34272
# Accumulated Distribution Index
35273
#################################
@@ -389,7 +627,8 @@ def adx(self, period: int = 14) -> None:
389627
)
390628
.adx_neg()
391629
.round(2)
392-
).astype(float)
630+
.astype(float)
631+
)
393632

394633
chart[f"adx{period}_pos"] = (
395634
ADXIndicator(

tests/test_fmp_chart_data.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import pandas as pd
2+
import pytest
3+
from fmp_py.fmp_chart_data import FmpChartData
4+
5+
6+
@pytest.fixture
7+
def fmp():
8+
return FmpChartData(symbol="AAPL", from_date="2021-01-01", to_date="2021-01-10")
9+
10+
11+
def test_fmp_chart_data_init(fmp):
12+
assert isinstance(fmp, FmpChartData)
13+
14+
15+
def test_fmp_chart_data_return_chart(fmp):
16+
fmp_chart = fmp.return_chart()
17+
assert isinstance(fmp_chart, pd.DataFrame)
18+
assert "close" in fmp_chart.columns
19+
assert "volume" in fmp_chart.columns
20+
assert "open" in fmp_chart.columns
21+
assert "high" in fmp_chart.columns
22+
assert "low" in fmp_chart.columns
23+
24+
25+
def test_fmp_chart_data_nvi(fmp):
26+
fmp.nvi()
27+
fmp_chart = fmp.return_chart()
28+
assert isinstance(fmp_chart, pd.DataFrame)
29+
assert "nvi" in fmp_chart.columns
30+
31+
32+
def test_fmp_chart_data_sma(fmp):
33+
fmp.sma(14)
34+
fmp_chart = fmp.return_chart()
35+
assert isinstance(fmp_chart, pd.DataFrame)
36+
assert "sma14" in fmp_chart.columns
37+
38+
39+
def test_fmp_chart_data_ema(fmp):
40+
fmp.ema(14)
41+
fmp_chart = fmp.return_chart()
42+
assert isinstance(fmp_chart, pd.DataFrame)
43+
assert "ema14" in fmp_chart.columns
44+
45+
46+
def test_fmp_chart_data_rsi(fmp):
47+
fmp.rsi(14)
48+
fmp_chart = fmp.return_chart()
49+
assert isinstance(fmp_chart, pd.DataFrame)
50+
assert "rsi14" in fmp_chart.columns
51+
52+
53+
def test_fmp_chart_data_vwap(fmp):
54+
fmp.vwap()
55+
fmp_chart = fmp.return_chart()
56+
assert isinstance(fmp_chart, pd.DataFrame)
57+
assert "vwap" in fmp_chart.columns
58+
59+
60+
def test_fmp_chart_data_bb(fmp):
61+
fmp.bb(20, 2)
62+
fmp_chart = fmp.return_chart()
63+
assert isinstance(fmp_chart, pd.DataFrame)
64+
assert "bb_h20" in fmp_chart.columns
65+
assert "bb_l20" in fmp_chart.columns
66+
assert "bb_m20" in fmp_chart.columns
67+
assert "bb_w20" in fmp_chart.columns
68+
assert "bb_p20" in fmp_chart.columns
69+
assert "bb_h20_ind" in fmp_chart.columns
70+
assert "bb_l20_ind" in fmp_chart.columns
71+
72+
73+
def test_fmp_chart_data_mfi(fmp):
74+
fmp.mfi(14)
75+
fmp_chart = fmp.return_chart()
76+
assert isinstance(fmp_chart, pd.DataFrame)
77+
assert "mfi14" in fmp_chart.columns

0 commit comments

Comments
 (0)