Merge pull request #429 from DidierRLopes/pattern-recognition

Add pattern recognition to technical analysis
This commit is contained in:
DidierRLopes
2021-05-02 22:39:07 +01:00
committed by GitHub
7 changed files with 218 additions and 4 deletions

View File

@@ -227,10 +227,11 @@ These are the ones where a key is necessary:
* Tradier: https://developer.tradier.com/getting_started
* Oanda API: https://developer.oanda.com
* CoinMarketCap API: https://coinmarketcap.com/api/
* Finhub API: https://finnhub.io
When these are obtained, don't forget to update [config_terminal.py](/gamestonk_terminal/config_terminal.py).
Alternatively, you can also set them to the following environment variables: GT_API_KEY_ALPHAVANTAGE, GT_API_KEY_FINANCIALMODELINGPREP, GT_API_KEY_QUANDL, GT_API_REDDIT_CLIENT_ID, GT_API_REDDIT_CLIENT_SECRET, GT_API_REDDIT_USERNAME, GT_API_REDDIT_USER_AGENT, GT_API_REDDIT_PASSWORD, GT_API_TWITTER_KEY, GT_API_TWITTER_SECRET_KEY, GT_API_TWITTER_BEARER_TOKEN, GT_API_POLYGON_KEY, GT_FRED_API_KEY, GT_API_NEWS_TOKEN, GT_OANDA_TOKEN, GT_OANDA_ACCOUNT, GT_TRADIER_TOKEN, GT_CMC_API_KEY.
Alternatively, you can also set them to the following environment variables: GT_API_KEY_ALPHAVANTAGE, GT_API_KEY_FINANCIALMODELINGPREP, GT_API_KEY_QUANDL, GT_API_REDDIT_CLIENT_ID, GT_API_REDDIT_CLIENT_SECRET, GT_API_REDDIT_USERNAME, GT_API_REDDIT_USER_AGENT, GT_API_REDDIT_PASSWORD, GT_API_TWITTER_KEY, GT_API_TWITTER_SECRET_KEY, GT_API_TWITTER_BEARER_TOKEN, GT_API_POLYGON_KEY, GT_FRED_API_KEY, GT_API_NEWS_TOKEN, GT_OANDA_TOKEN, GT_OANDA_ACCOUNT, GT_TRADIER_TOKEN, GT_CMC_API_KEY, GT_CMC_API_KEY, API_FINNHUB_KEY.
Example:
```

View File

@@ -78,9 +78,10 @@
* [x] Add technical summary report provided by FinBrain (@didier) - [PR #294](https://github.com/DidierRLopes/GamestonkTerminal/pull/294)
* [x] Add recommendation based on technical indicators from Tradingview (@didier) - [PR #301](https://github.com/DidierRLopes/GamestonkTerminal/pull/301)
* [x] Add view of stock historical price with trendlines (support, resistance) by Finviz (@didier) - [PR #317](https://github.com/DidierRLopes/GamestonkTerminal/pull/317)
* [x] Add auto-recognition of major TA patterns (@didier) - [PR #429](https://github.com/DidierRLopes/GamestonkTerminal/pull/429)
**NEXT**
* [ ] Add auto-recognition of major TA patterns (@didier)
---

View File

@@ -183,6 +183,7 @@ Command | Description | Sources
`view` | view historical data and trendlines| [Finviz](https://finviz.com/quote.ashx?t=tsla)
`summary` | technical summary report| [FinBrain](https://finbrain.tech)
`recom` | recommendation based on Technical Indicators| [Tradingview](https://uk.tradingview.com/widget/technical-analysis/)
`pr` | pattern recognition| [Finnhub](https://finnhub.io)
[overlap](https://github.com/twopirllc/pandas-ta/tree/master/pandas_ta/overlap) |
`ema` | exponential moving average | [Wikipedia](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average), [Investopedia](https://www.investopedia.com/terms/e/ema.asp)
`sma` |simple moving average | [Wikipedia](https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average_(boxcar_filter)), [Investopedia](https://www.investopedia.com/terms/s/sma.asp)
@@ -397,7 +398,7 @@ positionbook |display the positionbook if Oanda provides one for the forex instr
Command|Description
------ | --------
`ema` | buy when price exceeds EMA(l)
`ema_cross` | buy when EMA(short) > EMA(long)
`ema_cross` | buy when EMA(short) > EMA(long)
`rsi` | buy when RSI < low and sell when RSI > high

View File

@@ -33,7 +33,7 @@ API_TWITTER_SECRET_KEY = os.getenv("GT_API_TWITTER_SECRET_KEY") or "REPLACE_ME"
API_TWITTER_BEARER_TOKEN = os.getenv("GT_API_TWITTER_BEARER_TOKEN") or "REPLACE_ME"
# https://fred.stlouisfed.org/docs/api/api_key.html
API_FRED_KEY = os.getenv("GT_FRED_API_KEY") or "REPLACE_ME"
API_FRED_KEY = os.getenv("GT_FRED_API_KEY") or "b98e15f1fde39212bce9213f2e3e5afb"
# https://newsapi.org
API_NEWS_TOKEN = os.getenv("GT_API_NEWS_TOKEN") or "REPLACE_ME"
@@ -59,3 +59,6 @@ PATH_TO_SELENIUM_DRIVER = None # Replace with "PATH"
# https://coinmarketcap.com/api/
COINMARKETCAP_KEY = os.getenv("GT_CMC_API_KEY") or "REPLACE_ME"
# https://finnhub.io
API_FINNHUB_KEY = os.getenv("GT_API_FINNHUB_KEY") or "REPLACE_ME"

View File

@@ -8,6 +8,8 @@ This menu aims to perform a technical analysis on a pre-loaded ticker chart, and
- technical summary report [FinBrain API]
* [recom](#recom)
- recommendation based on Technical Indicators [Tradingview API]
* [pr](#pr)
- pattern recognition [Finnhub]
[OVERLAP](#OVERLAP)
* [ema](#ema)
@@ -79,6 +81,19 @@ Print tradingview recommendation based on technical indicators. [Source: https:/
<img width="977" alt="Captura de ecrã 2021-03-31, às 00 14 41" src="https://user-images.githubusercontent.com/25267873/113069531-76ea2b00-91b8-11eb-8934-9f693d3b4ffa.png">
## pr <a name="pr"></a>
```
usage: pr [-r {1,5,15,30,60,D,W,M}]
```
Display pattern recognition signals on the data. [Source: https://finnhub.io]
* -r : Plot resolution to look for pattern signals. Default 'D'.
![pr](https://user-images.githubusercontent.com/25267873/116812520-06338700-ab47-11eb-8db4-8f5e940507ed.png)
<img width="985" alt="Captura de ecrã 2021-05-02, às 02 27 10" src="https://user-images.githubusercontent.com/25267873/116812505-f6b43e00-ab46-11eb-9776-fa469dc3d3f0.png">
# OVERLAP <a name="OVERLAP"></a>
## ema <a name="ema"></a>

View File

@@ -0,0 +1,185 @@
import argparse
from typing import List
import math
from datetime import datetime
import requests
import yfinance as yf
import mplfinance as mpf
import pandas as pd
from gamestonk_terminal import config_terminal as cfg
from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
plot_autoscale,
)
def get_pattern_recognition(ticker: str, resolution: str) -> pd.DataFrame:
"""Get pattern recognition data
Parameters
----------
ticker : str
Ticker to get pattern recognition data
resolution : str
Resolution of data to get pattern recognition from
Returns
-------
pd.DataFrame
Get datapoints corresponding to pattern signal data
"""
response = requests.get(
f"https://finnhub.io/api/v1/scan/pattern?symbol={ticker}&resolution={resolution}&token={cfg.API_FINNHUB_KEY}"
)
if response.status_code == 200:
d_data = response.json()
if "points" in d_data:
return pd.DataFrame(d_data["points"]).T
return pd.DataFrame()
def plot_pattern_recognition(ticker: str, pattern: pd.DataFrame):
"""Plot pattern recognition signal
Parameters
----------
ticker : str
Ticker to display pattern recognition on top of the data
pattern : pd.DataFrame
Pattern recognition signal data
"""
l_segments = list()
for i in pattern:
a_part = ("", "")
if "aprice" in pattern[i]:
if pattern[i]["aprice"] != 0 and not math.isnan(pattern[i]["aprice"]):
a_part = (
datetime.utcfromtimestamp(pattern[i]["atime"]).strftime("%Y-%m-%d"),
pattern[i]["aprice"],
)
b_part = ("", "")
if "bprice" in pattern[i]:
if pattern[i]["bprice"] != 0 and not math.isnan(pattern[i]["bprice"]):
b_part = (
datetime.utcfromtimestamp(pattern[i]["btime"]).strftime("%Y-%m-%d"),
pattern[i]["bprice"],
)
c_part = ("", "")
if "cprice" in pattern[i]:
if pattern[i]["cprice"] != 0 and not math.isnan(pattern[i]["cprice"]):
c_part = (
datetime.utcfromtimestamp(pattern[i]["ctime"]).strftime("%Y-%m-%d"),
pattern[i]["cprice"],
)
d_part = ("", "")
if "dprice" in pattern[i]:
if pattern[i]["dprice"] != 0 and not math.isnan(pattern[i]["dprice"]):
d_part = (
datetime.utcfromtimestamp(pattern[i]["dtime"]).strftime("%Y-%m-%d"),
pattern[i]["dprice"],
)
segment = (a_part, b_part, c_part, d_part)
l_segment = list(segment)
while ("", "") in l_segment:
l_segment.remove(("", ""))
segm = tuple(l_segment)
l_segments.append(segm)
start_time = 999999999999
for i in pattern:
if pattern[i]["atime"] < start_time:
start_time = pattern[i]["atime"]
df_stock = yf.download(
ticker,
start=datetime.utcfromtimestamp(start_time).strftime("%Y-%m-%d"),
progress=False,
)
df_stock["date_id"] = (df_stock.index.date - df_stock.index.date.min()).astype(
"timedelta64[D]"
)
df_stock["date_id"] = df_stock["date_id"].dt.days + 1
df_stock["OC_High"] = df_stock[["Open", "Close"]].max(axis=1)
df_stock["OC_Low"] = df_stock[["Open", "Close"]].min(axis=1)
mc = mpf.make_marketcolors(
up="green", down="red", edge="black", wick="black", volume="in", ohlc="i"
)
s = mpf.make_mpf_style(marketcolors=mc, gridstyle=":", y_on_right=False)
mpf.plot(
df_stock,
type="candle",
volume=False,
title=f"\n{ticker}",
alines=l_segments,
xrotation=10,
style=s,
figratio=(10, 7),
figscale=1.10,
figsize=plot_autoscale(),
update_width_config=dict(
candle_linewidth=1.0, candle_width=0.8, volume_linewidth=1.0
),
)
for ix in range(len(pattern.columns)):
print(f"From {l_segments[ix][0][0]} to {l_segments[ix][-1][0]}")
print(f"Pattern: {pattern[0]['patternname']} ({pattern[0]['patterntype']})")
print("")
def pattern_recognition_view(other_args: List[str], ticker: str):
"""Display pattern recognition signals on the data
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
ticker : str
Ticker to display pattern recognition on top of the data
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="pr",
description="""
Display pattern recognition signals on the data. [Source: https://finnhub.io]
""",
)
parser.add_argument(
"-r",
"--resolution",
action="store",
dest="resolution",
type=str,
default="D",
choices=["1", "5", "15", "30", "60", "D", "W", "M"],
help="Plot resolution to look for pattern signals",
)
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_pattern = get_pattern_recognition(ticker, ns_parser.resolution)
if df_pattern.empty:
print("No pattern identified in this data", "\n")
return
plot_pattern_recognition(ticker, df_pattern)
except Exception as e:
print(e, "\n")

View File

@@ -20,6 +20,7 @@ from gamestonk_terminal.technical_analysis import volume as ta_volume
from gamestonk_terminal.technical_analysis import finbrain_view
from gamestonk_terminal.technical_analysis import tradingview_view
from gamestonk_terminal.technical_analysis import finviz_view
from gamestonk_terminal.technical_analysis import finnhub_view
class TechnicalAnalysisController:
@@ -33,6 +34,7 @@ class TechnicalAnalysisController:
"view",
"summary",
"recom",
"pr",
"ema",
"sma",
"vwap",
@@ -88,6 +90,8 @@ class TechnicalAnalysisController:
print(
" recom recommendation based on Technical Indicators [Tradingview API]"
)
print(" pr pattern recognition [Finnhub]")
print("")
print("overlap:")
print(" ema exponential moving average")
print(" sma simple moving average")
@@ -157,6 +161,10 @@ class TechnicalAnalysisController:
"""Process recom command"""
tradingview_view.print_recommendation(other_args, self.ticker)
def call_pr(self, other_args: List[str]):
"""Process pr command"""
finnhub_view.pattern_recognition_view(other_args, self.ticker)
# OVERLAP
def call_ema(self, other_args: List[str]):
"""Process ema command"""