mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-10 11:21:12 +00:00
Merge pull request #429 from DidierRLopes/pattern-recognition
Add pattern recognition to technical analysis
This commit is contained in:
@@ -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:
|
||||
```
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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'.
|
||||
|
||||

|
||||
|
||||
<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>
|
||||
|
||||
185
gamestonk_terminal/technical_analysis/finnhub_view.py
Normal file
185
gamestonk_terminal/technical_analysis/finnhub_view.py
Normal 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")
|
||||
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user