mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-08-03 13:00:43 +08:00
276 KiB
276 KiB
In [1]:
#!pip install numpy
#!pip install pandas
#!pip install mplfinance
#!pip install pandas-datareader
#!pip install requests_cache
#!pip install tqdm
#!pip install alphaVantage-api # Required for WatchlistIn [2]:
%pylab inline
import datetime as dt
import random as rnd
from sys import float_info as sflt
from tqdm import tqdm
import numpy as np
import pandas as pd
pd.set_option("max_rows", 100)
pd.set_option("max_columns", 20)
import mplfinance as mpf
import pandas_ta as ta
from tqdm.notebook import trange, tqdm
from watchlist import colors, Watchlist # Is this failing? If so, copy it locally. See above.
print(f"Numpy v{np.__version__}")
print(f"Pandas v{pd.__version__}")
print(f"mplfinance v{mpf.__version__}")
print(f"\nPandas TA v{ta.version}\nTo install the Latest Version:\n$ pip install -U git+https://github.com/twopirllc/pandas-ta\n")
%matplotlib inlinePopulating the interactive namespace from numpy and matplotlib Numpy v1.20.3 Pandas v1.3.0 mplfinance v0.12.7a17 Pandas TA v0.3.63b0 To install the Latest Version: $ pip install -U git+https://github.com/twopirllc/pandas-ta
In [3]:
def recent_bars(df, tf: str = "1y"):
# All Data: 0, Last Four Years: 0.25, Last Two Years: 0.5, This Year: 1, Last Half Year: 2, Last Quarter: 4
yearly_divisor = {"all": 0, "10y": 0.1, "5y": 0.2, "4y": 0.25, "3y": 1./3, "2y": 0.5, "1y": 1, "6mo": 2, "3mo": 4}
yd = yearly_divisor[tf] if tf in yearly_divisor.keys() else 0
return int(ta.RATE["TRADING_DAYS_PER_YEAR"] / yd) if yd > 0 else df.shape[0]In [4]:
tf = "D"
tickers = ["SPY", "QQQ", "AAPL", "TSLA", "BTC-USD"]
watch = Watchlist(tickers, tf=tf, ds_name="yahoo", timed=True)
# watch.study = ta.CommonStudy # If you have a Custom Study, you can use it here.
watch.load(tickers, analyze=True, verbose=False)[!] Loading All: SPY, QQQ, AAPL, TSLA, BTC-USD [+] Downloading[yahoo]: SPY[D] [+] yf | SPY(7367, 7): 3196.9914 ms (3.1970 s) [+] Saving: /Users/kj/av_data/SPY_D.csv [i] Analysis Time: 34.3883 ms (0.0344 s) for 5 columns (avg 6.8791 ms / col) [+] Downloading[yahoo]: QQQ[D] [+] yf | QQQ(5825, 7): 4333.8306 ms (4.3338 s) [+] Saving: /Users/kj/av_data/QQQ_D.csv [i] Analysis Time: 3.3304 ms (0.0033 s) for 5 columns (avg 0.6667 ms / col) [+] Downloading[yahoo]: AAPL[D] [+] yf | AAPL(10434, 7): 4274.9140 ms (4.2749 s) [+] Saving: /Users/kj/av_data/AAPL_D.csv [i] Analysis Time: 3.6997 ms (0.0037 s) for 5 columns (avg 0.7406 ms / col) [+] Downloading[yahoo]: TSLA[D] [+] yf | TSLA(2981, 7): 3129.0620 ms (3.1291 s) [+] Saving: /Users/kj/av_data/TSLA_D.csv [i] Analysis Time: 3.0117 ms (0.0030 s) for 5 columns (avg 0.6030 ms / col) [+] Downloading[yahoo]: BTC-USD[D] [+] yf | BTC-USD(2784, 7): 3533.1249 ms (3.5331 s) [+] Saving: /Users/kj/av_data/BTC-USD_D.csv [i] Analysis Time: 3.6089 ms (0.0036 s) for 5 columns (avg 0.7226 ms / col)
In [5]:
ticker = tickers[1] # change tickers by changing the index
print(f"{ticker} {watch.data[ticker].shape}\nColumns: {', '.join(list(watch.data[ticker].columns))}")QQQ (5825, 12) Columns: Open, High, Low, Close, Volume, Dividends, Stock Splits, SMA_10, SMA_20, SMA_50, SMA_200, VOL_SMA_20
In [6]:
duration = "5y"
asset = watch.data[ticker]
recent = recent_bars(asset, duration)
asset.columns = asset.columns.str.lower()
asset.drop(columns=["dividends", "split"], errors="ignore", inplace=True)
asset = asset.copy().tail(recent)
assetOut [6]:
| open | high | low | close | volume | stock splits | sma_10 | sma_20 | sma_50 | sma_200 | vol_sma_20 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||||
| 2017-05-01 | 131.702961 | 132.610327 | 131.645046 | 132.436569 | 24815500 | 0.0 | 129.452889 | 128.293103 | 127.098378 | 117.352839 | 20653180.0 |
| 2017-05-02 | 132.600685 | 132.716529 | 132.262846 | 132.658600 | 18345100 | 0.0 | 130.046537 | 128.540698 | 127.250689 | 117.480589 | 20385420.0 |
| 2017-05-03 | 132.359333 | 132.407600 | 131.876692 | 132.233856 | 23827600 | 0.0 | 130.577444 | 128.756921 | 127.382175 | 117.602671 | 20906800.0 |
| 2017-05-04 | 132.214573 | 132.658594 | 131.818804 | 132.282135 | 14630100 | 0.0 | 131.006993 | 129.001620 | 127.513663 | 117.726958 | 20037745.0 |
| 2017-05-05 | 132.619938 | 132.764725 | 132.127651 | 132.764725 | 19330700 | 0.0 | 131.487700 | 129.267070 | 127.664244 | 117.847383 | 20062670.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2022-04-25 | 323.730011 | 329.899994 | 322.429993 | 329.579987 | 101755900 | 0.0 | 338.041000 | 349.745001 | 344.924885 | 367.586838 | 67700730.0 |
| 2022-04-26 | 327.470001 | 327.660004 | 316.859985 | 317.140015 | 105819600 | 0.0 | 335.666000 | 347.356502 | 344.335056 | 367.366986 | 70150015.0 |
| 2022-04-27 | 317.239990 | 322.880005 | 315.000000 | 316.760010 | 111204200 | 0.0 | 333.397000 | 344.635002 | 343.729037 | 367.145234 | 72306575.0 |
| 2022-04-28 | 321.850006 | 329.890015 | 317.519989 | 328.010010 | 99450000 | 0.0 | 331.563000 | 342.681003 | 343.175432 | 366.976494 | 73841190.0 |
| 2022-04-29 | 323.700012 | 327.230011 | 312.600006 | 313.250000 | 91856700 | 0.0 | 329.045001 | 340.216502 | 342.328425 | 366.746658 | 75083455.0 |
1260 rows × 11 columns
In [7]:
# Example Long Trends
# long = ta.sma(asset.close, 50) > ta.sma(asset.close, 200) # SMA(50) > SMA(200) "Golden/Death Cross"
long = ta.sma(asset.close, 20) > ta.sma(asset.close, 50) # SMA(20) > SMA(50)
# long = ta.ema(asset.close, 8) > ta.ema(asset.close, 21) # EMA(8) > EMA(21)
# long = ta.increasing(ta.ema(asset.close, 20))
# long = ta.macd(asset.close).iloc[:,1] > 0 # MACD Histogram is positive
# long &= ta.increasing(ta.ema(asset.close, 50), 2) # Uncomment for further long restrictions, in this case when EMA(50) is increasing/sloping upwards
# long = 1 - long # uncomment to create a short signal of the trend
asset.ta.ema(length=8, sma=False, append=True)
asset.ta.ema(length=21, sma=False, append=True)
asset.ta.ema(length=50, sma=False, append=True)
asset.ta.percent_return(append=True, cumulative=False)
print("TA Columns Added:")
asset[asset.columns[5:]].tail()Out [7]:
TA Columns Added:
| stock splits | sma_10 | sma_20 | sma_50 | sma_200 | vol_sma_20 | EMA_8 | EMA_21 | EMA_50 | PCTRET_1 | |
|---|---|---|---|---|---|---|---|---|---|---|
| Date | ||||||||||
| 2022-04-25 | 0.0 | 338.041000 | 349.745001 | 344.924885 | 367.586838 | 67700730.0 | 336.456901 | 343.546748 | 348.865113 | 0.012846 |
| 2022-04-26 | 0.0 | 335.666000 | 347.356502 | 344.335056 | 367.366986 | 70150015.0 | 332.164260 | 341.146136 | 347.620992 | -0.037745 |
| 2022-04-27 | 0.0 | 333.397000 | 344.635002 | 343.729037 | 367.145234 | 72306575.0 | 328.741093 | 338.929215 | 346.410757 | -0.001198 |
| 2022-04-28 | 0.0 | 331.563000 | 342.681003 | 343.175432 | 366.976494 | 73841190.0 | 328.578630 | 337.936560 | 345.689159 | 0.035516 |
| 2022-04-29 | 0.0 | 329.045001 | 340.216502 | 342.328425 | 366.746658 | 75083455.0 | 325.172268 | 335.692328 | 344.417035 | -0.044999 |
In [8]:
trendy = asset.ta.tsignals(long, asbool=False, append=True)
trendy.tail()Out [8]:
tsignals
| TS_Trends | TS_Trades | TS_Entries | TS_Exits | |
|---|---|---|---|---|
| Date | ||||
| 2022-04-25 | 1 | 0 | 0 | 0 |
| 2022-04-26 | 1 | 0 | 0 | 0 |
| 2022-04-27 | 1 | 0 | 0 | 0 |
| 2022-04-28 | 0 | -1 | 0 | 1 |
| 2022-04-29 | 0 | 0 | 0 | 0 |
In [9]:
entries = trendy.TS_Entries * asset.close
entries = entries[~np.isclose(entries, 0)]
entries.dropna(inplace=True)
entries.name = "Entry"
exits = trendy.TS_Exits * asset.close
exits = exits[~np.isclose(exits, 0)]
exits.dropna(inplace=True)
exits.name = "Exit"
total_trades = trendy.TS_Trades.abs().sum()
rt_trades = int(trendy.TS_Trades.abs().sum() // 2)
all_trades = trendy.TS_Trades.copy().fillna(0)
all_trades = all_trades[all_trades != 0]
trades = pd.DataFrame({
"Signal": all_trades,
entries.name: entries,
exits.name: exits
})
# Show some stats if there is an active trade (when there is an odd number of round trip trades)
if total_trades % 2 != 0:
unrealized_pnl = asset.close.iloc[-1] - entries.iloc[-1]
unrealized_pnl_pct_change = 100 * ((asset.close.iloc[-1] / entries.iloc[-1]) - 1)
print("Current Trade:")
print(f"Price Entry | Last:\t{entries.iloc[-1]:.4f} | {asset.close.iloc[-1]:.4f}")
print(f"Unrealized PnL | %:\t{unrealized_pnl:.4f} | {unrealized_pnl_pct_change:.4f}%")
print(f"\nTrades Total | Round Trip:\t{total_trades} | {rt_trades}")
print(f"Trade Coverage: {100 * asset.TS_Trends.sum() / asset.shape[0]:.2f}%")
tradelist = trades
if rt_trades > 10:
tradelist = trades.tail(10)
tradelistOut [9]:
Trades Total | Round Trip: 22 | 11 Trade Coverage: 71.19%
| Signal | Entry | Exit | |
|---|---|---|---|
| Date | |||
| 2020-10-16 | 1 | 286.253357 | NaN |
| 2021-03-11 | -1 | NaN | 316.124359 |
| 2021-04-13 | 1 | 338.976044 | NaN |
| 2021-05-26 | -1 | NaN | 332.536896 |
| 2021-06-16 | 1 | 339.384125 | NaN |
| 2021-10-05 | -1 | NaN | 356.483398 |
| 2021-11-02 | 1 | 388.073944 | NaN |
| 2022-01-07 | -1 | NaN | 379.390961 |
| 2022-04-05 | 1 | 361.100006 | NaN |
| 2022-04-28 | -1 | NaN | 328.010010 |
In [ ]:
In [10]:
extime = ta.get_time(to_string=True)
first_date, last_date = asset.index[0], asset.index[-1]
last_ohlcv = f"Last OHLCV: ({asset.iloc[-1].open:.4f}, {asset.iloc[-1].high:.4f}, {asset.iloc[-1].low:.4f}, {asset.iloc[-1].close:.4f}, {int(asset.iloc[-1].volume)})"
_oc_change = asset.iloc[-1].open - asset.iloc[-1].close
_oc_change_pct = _oc_change / asset.iloc[-1].open
oc_change = f"{_oc_change:.4f} ({100 * _oc_change_pct:.4f} %)"
ptitle = f"\n{ticker} [{tf} for {duration}({recent} bars)]\n{last_ohlcv}, Change (%): {oc_change}\n{extime}"In [11]:
# chart = asset["close"] #asset[["close", "SMA_10", "SMA_20", "SMA_50", "SMA_200"]]
# chart = asset[["close", "SMA_10", "SMA_20"]]
chart = asset[["close", "EMA_8", "EMA_21", "EMA_50"]]
chart.plot(figsize=(16, 10), color=colors("BkGrOrRd"), title=ptitle, grid=True)Out [11]:
<AxesSubplot:title={'center':'\nQQQ [D for 5y(1260 bars)]\nLast OHLCV: (323.7000, 327.2300, 312.6000, 313.2500, 91856700), Change (%): 10.4500 (3.2283 %)\nSunday May 1, 2022, NYSE: 14:15:43, Local: 18:15:43 PDT, Day 121/365 (33.00%)'}, xlabel='Date'>In [12]:
long_trend = trendy.TS_Trends
short_trend = 1 - long_trend
long_trend.plot(figsize=(16, 0.85), kind="area", stacked=True, color=["limegreen"], alpha=0.65) # Green Area
short_trend.plot(figsize=(16, 0.85), kind="area", stacked=True, color=["orangered"], alpha=0.65) # Red AreaOut [12]:
<AxesSubplot:xlabel='Date'>
In [13]:
trendy.TS_Trades.plot(figsize=(16, 1.5), color=colors("BkBl")[0], grid=True)Out [13]:
<AxesSubplot:xlabel='Date'>
In [14]:
asset["ACTRET_1"] = trendy.TS_Trends.shift(1) * asset.PCTRET_1
asset[["PCTRET_1", "ACTRET_1"]].plot(figsize=(16, 3), color=["gray", "limegreen"], alpha=1, grid=True).axhline(0, color="black")Out [14]:
<matplotlib.lines.Line2D at 0x132855d00>
In [15]:
((asset.PCTRET_1 + 1).cumprod() - 1).plot(figsize=(16, 3), kind="area", stacked=False, color=["limegreen"], title="B&H Percent Returns", alpha=0.9, grid=True).axhline(0, color="black")Out [15]:
<matplotlib.lines.Line2D at 0x13206da60>
In [16]:
# ((asset.ACTRET_1 + 1).cumprod() - 1).plot(figsize=(16, 3), kind="area", stacked=False, color=colors("GyOr")[-1], title="B&H Cum. Active Returns", alpha=0.4, grid=True).axhline(0, color="black")
((asset.ACTRET_1 + 1).cumprod() - 1).plot(figsize=(16, 3), kind="area", stacked=False, color=["limegreen"], title="B&H Cum. Active Returns", alpha=0.65, grid=True).axhline(0, color="black")Out [16]:
<matplotlib.lines.Line2D at 0x133835ee0>