mirror of
https://github.com/wassname/pandas-ta.git
synced 2026-07-25 13:21:01 +08:00
286 KiB
286 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.32b0 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] [+] Saving: /Users/kj/av_data/SPY_D.csv [i] Runtime: 707.3915 ms (0.7074 s) [+] Downloading[yahoo]: QQQ[D] [+] Saving: /Users/kj/av_data/QQQ_D.csv [i] Runtime: 696.6895 ms (0.6967 s) [+] Downloading[yahoo]: AAPL[D] [+] Saving: /Users/kj/av_data/AAPL_D.csv [i] Runtime: 856.9906 ms (0.8570 s) [+] Downloading[yahoo]: TSLA[D] [+] Saving: /Users/kj/av_data/TSLA_D.csv [i] Runtime: 719.1806 ms (0.7192 s) [+] Downloading[yahoo]: BTC-USD[D] [+] Saving: /Users/kj/av_data/BTC-USD_D.csv [i] Runtime: 811.2178 ms (0.8112 s)
In [5]:
ticker = tickers[0] # change tickers by changing the index
print(f"{ticker} {watch.data[ticker].shape}\nColumns: {', '.join(list(watch.data[ticker].columns))}")SPY (7299, 12) Columns: open, high, low, close, volume, dividends, stock splits, SMA_10, SMA_20, SMA_50, SMA_200, VOL_SMA_20
In [6]:
duration = "1y"
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 | |||||||||||
| 2021-01-25 | 378.623058 | 379.708564 | 373.481570 | 379.333588 | 70402000 | 0 | 375.540128 | 371.941592 | 363.642487 | 325.851111 | 63120030.0 |
| 2021-01-26 | 380.340140 | 380.774354 | 378.494744 | 378.741455 | 42665300 | 0 | 376.043420 | 372.671364 | 364.207632 | 326.389357 | 63930400.0 |
| 2021-01-27 | 375.218403 | 375.317093 | 367.116410 | 369.484833 | 123351100 | 0 | 375.613156 | 372.781891 | 364.655645 | 326.893695 | 68147935.0 |
| 2021-01-28 | 371.409193 | 376.905930 | 370.945404 | 372.662506 | 94198100 | 0 | 375.400000 | 373.086334 | 365.071107 | 327.374311 | 70173815.0 |
| 2021-01-29 | 370.688763 | 371.715090 | 363.425564 | 365.201904 | 126765100 | 0 | 374.572037 | 372.991595 | 365.249507 | 327.847003 | 74039305.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2022-01-14 | 461.190002 | 465.089996 | 459.899994 | 464.720001 | 95849600 | 0 | 469.319998 | 469.606500 | 465.989207 | 438.476059 | 78776895.0 |
| 2022-01-18 | 459.739990 | 459.959991 | 455.309998 | 456.489990 | 109709100 | 0 | 467.197998 | 469.437500 | 465.813499 | 438.746869 | 77486770.0 |
| 2022-01-19 | 458.130005 | 459.609985 | 451.459991 | 451.750000 | 109357600 | 0 | 464.617999 | 469.275999 | 465.510704 | 438.995168 | 77597910.0 |
| 2022-01-20 | 453.750000 | 458.739990 | 444.500000 | 446.750000 | 122379700 | 0 | 462.454999 | 468.460500 | 465.099938 | 439.216139 | 80226580.0 |
| 2022-01-21 | 445.559998 | 448.059998 | 437.950012 | 437.980011 | 201913500 | 0 | 459.459000 | 466.975000 | 464.544664 | 439.383707 | 87377745.0 |
252 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, 10) > ta.sma(asset.close, 20) # SMA(10) > SMA(20)
long = ta.ema(asset.close, 8) > ta.ema(asset.close, 21) # EMA(8) > EMA(21)
# long = ta.increasing(ta.ema(asset.close, 50))
# long = ta.macd(asset.close).iloc[:,1] > 0 # MACD Histogram is positive
# long = ta.amat(asset.close, 50, 200).AMATe_LR_2 # Long Run of AMAT(50, 200) with lookback of 2 bars
# 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)
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-01-14 | 0 | 469.319998 | 469.606500 | 465.989207 | 438.476059 | 78776895.0 | 467.864562 | 468.366344 | 464.226269 | 0.000409 |
| 2022-01-18 | 0 | 467.197998 | 469.437500 | 465.813499 | 438.746869 | 77486770.0 | 465.336880 | 467.286675 | 463.922886 | -0.017710 |
| 2022-01-19 | 0 | 464.617999 | 469.275999 | 465.510704 | 438.995168 | 77597910.0 | 462.317573 | 465.874250 | 463.445517 | -0.010384 |
| 2022-01-20 | 0 | 462.454999 | 468.460500 | 465.099938 | 439.216139 | 80226580.0 | 458.858112 | 464.135682 | 462.790791 | -0.011068 |
| 2022-01-21 | 0 | 459.459000 | 466.975000 | 464.544664 | 439.383707 | 87377745.0 | 454.218534 | 461.757894 | 461.817820 | -0.019631 |
In [8]:
trendy = asset.ta.tsignals(long, asbool=False, append=True)
trendy.tail()Out [8]:
| TS_Trends | TS_Trades | TS_Entries | TS_Exits | |
|---|---|---|---|---|
| date | ||||
| 2022-01-14 | 0 | -1 | 0 | 1 |
| 2022-01-18 | 0 | 0 | 0 | 0 |
| 2022-01-19 | 0 | 0 | 0 | 0 |
| 2022-01-20 | 0 | 0 | 0 | 0 |
| 2022-01-21 | 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}%")
tradesOut [9]:
Trades Total | Round Trip: 12 | 6 Trade Coverage: 77.78%
| Signal | Entry | Exit | |
|---|---|---|---|
| date | |||
| 2021-02-23 | 1 | 382.402618 | NaN |
| 2021-03-04 | -1 | NaN | 371.744690 |
| 2021-03-10 | 1 | 384.455292 | NaN |
| 2021-05-19 | -1 | NaN | 406.783295 |
| 2021-05-20 | 1 | 411.159454 | NaN |
| 2021-09-17 | -1 | NaN | 439.854675 |
| 2021-10-15 | 1 | 444.309021 | NaN |
| 2021-12-01 | -1 | NaN | 448.922821 |
| 2021-12-08 | 1 | 467.876221 | NaN |
| 2021-12-20 | -1 | NaN | 454.980011 |
| 2021-12-21 | 1 | 463.059998 | NaN |
| 2022-01-14 | -1 | NaN | 464.720001 |
In [ ]:
In [10]:
extime = ta.get_time(to_string=True)
first_date, last_date = asset.index[0], asset.index[-1]
f_date = f"{first_date.day_name()} {first_date.month}-{first_date.day}-{first_date.year}"
l_date = f"{last_date.day_name()} {last_date.month}-{last_date.day}-{last_date.year}"
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)})"
ptitle = f"\n{ticker} [{tf} for {duration}({recent} bars)] from {f_date} to {l_date}\n{last_ohlcv}\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':'\nSPY [D for 1y(252 bars)] from Monday 1-25-2021 to Friday 1-21-2022\nLast OHLCV: (445.5600, 448.0600, 437.9500, 437.9800, 201913500)\nSunday January 23, 2022, NYSE: 11:44:28, Local: 15:44:28 PST, Day 23/365 (6.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=colors()[0], alpha=0.25) # Green Area
short_trend.plot(figsize=(16, 0.85), kind="area", stacked=True, color=colors()[1], alpha=0.25) # 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=colors("GyOr"), alpha=1, grid=True).axhline(0, color="black")Out [14]:
<matplotlib.lines.Line2D at 0x130230a60>
In [15]:
((asset[["PCTRET_1", "ACTRET_1"]] + 1).cumprod() - 1).plot(figsize=(16, 3), kind="area", stacked=False, color=colors("GyOr"), title="B&H vs. Cum. Active Returns", alpha=.4, grid=True).axhline(0, color="black")Out [15]:
<matplotlib.lines.Line2D at 0x1304c2610>
In [ ]: