mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 20:42:26 +00:00
Merge pull request #387 from alokan/main
Stocktwits, reddit, and eda integration and added ta options to charts.
This commit is contained in:
@@ -85,6 +85,10 @@ def due_diligence(other_args: List[str], ticker: str):
|
||||
"News",
|
||||
"Advice",
|
||||
"Chart",
|
||||
"Charts and Setups",
|
||||
"Fundamental Analysis",
|
||||
"forex",
|
||||
"Trade Idea",
|
||||
]
|
||||
l_sub_reddits = [
|
||||
"pennystocks",
|
||||
@@ -94,6 +98,8 @@ def due_diligence(other_args: List[str], ticker: str):
|
||||
"stocks",
|
||||
"investing",
|
||||
"wallstreetbets",
|
||||
"forex",
|
||||
"Forexstrategy",
|
||||
]
|
||||
|
||||
submissions = psaw_api.search_submissions(
|
||||
|
||||
@@ -30,6 +30,14 @@ This menu utilizes oanda to enable support for trading forex.
|
||||
* Display the orderbook if Oanda provides one for the forex instrument
|
||||
* [positionbook](#positionbook)
|
||||
* Display the positionbook if Oanda provides one for the forex instrument
|
||||
* [news](#news)
|
||||
* Latest news of the currency provided by [News API]
|
||||
* [reddit](#reddit)
|
||||
* Gets due diligence from another user's post [Reddit]
|
||||
* [eda](#eda)
|
||||
* This menu aims to perform exploratory data analysis on a pre-loaded forex instrument.
|
||||
* [ba](#ba)
|
||||
* This menu aims to extrapolate behavioural analysis regarding a pre-loaded forex instrument.
|
||||
|
||||
## summary <a name ="summary"></a>
|
||||
```text
|
||||
@@ -108,13 +116,21 @@ Specify the instrument to use in the format EUR_USD
|
||||
|
||||
## candles <a name="candles"></a>
|
||||
```text
|
||||
usage: candles [-g GRANULARITY] [-c CANDLECOUNT]
|
||||
usage: candles [-g GRANULARITY] [-c CANDLECOUNT] [-abcCeorsv]
|
||||
```
|
||||
|
||||
Retrieve a candlestick chart for the currently loaded instrument. Not a live chart.
|
||||
|
||||
* -g : Specify the granularity, which is the timeframe each candle represents. The available granularities are Seconds: S5, S10, S15, S30 Minutes: M1, M2, M4, M5, M10, M15, M30 Hours: H1, H2, H3, H4, H6, H8, H12 Day: D, Week: W Month: M. (default=D)
|
||||
* -c : Specify the number of candles to retrieve. (default=180)
|
||||
* -a : Adds AD (Accumulation/Distribution Index) to the chart. AD is a cumulative indicator that uses volume and price to assess whether a stock is being accumulated or distributed. This provides insight into how strong a trend is. [Investopedia](#https://www.investopedia.com/terms/a/accumulationdistribution.asp)
|
||||
* -b : Adds Bollinger Bands to the chart. Bollinger bands are a set of trendlines plotted two standard deviations (positively and negatively) away from a simple moving average of a security's price. [Investopedia](#https://www.investopedia.com/terms/b/bollingerbands.asp)
|
||||
* -C : Adds CCI (Commodity Channel Index) to the chart. CCI is a momentum-based oscillator used to help determine when an investment vehicle is reaching a condition of being overbought or oversold. (default=14) [Investopedia](#https://www.investopedia.com/terms/c/commoditychannelindex.asp)
|
||||
* -e : Adds EMA (Exponential Moving Average) to the chart. EMA is a moving average that places a greater weight and significance on the most recent data points. (default=10) [Investopedia](#https://www.investopedia.com/terms/e/ema.asp)
|
||||
* -o : Adds OBV (On Balance Volume) to the chart. OBV is a momentum indicator that uses volume flow to predict changes in price. [Investopedia](#https://www.investopedia.com/terms/o/onbalancevolume.asp)
|
||||
* -r : Adds RSI (Relative Strength Index) to the chart. RSI is a momentum indicator that measures the magnitude of recent price changes to evaluate overbought or oversold conditions. (default=14) [Investopedia](#https://www.investopedia.com/terms/r/rsi.asp)
|
||||
* -s : Adds SMA (Simple Moving Average) to the chart. SMA calculates the average of a selected range of prices, usually closing prices, by the number of periods in that range. (defaults= 20, 50) [Investopedia](#https://www.investopedia.com/terms/s/sma.asp)
|
||||
* -v : Adds VWAP (Volume Weighted Average Price) to the chart. VWAP gives the average price a security has traded at throughout the day, based on both volume and price. [Investopedia](#https://www.investopedia.com/terms/v/vwap.asp)
|
||||
|
||||
## price <a name="price"></a>
|
||||
```text
|
||||
@@ -144,3 +160,38 @@ Plots the current orderbook for loaded instrument if one is provided by Oanda. N
|
||||
usage: positionbook
|
||||
```
|
||||
Plots the current positionbook for the loaded instrument if one is provided by Oanda. Not a live chart.
|
||||
|
||||
## news <a name="news"></a>
|
||||
|
||||
```text
|
||||
news [-n N_NUM]
|
||||
```
|
||||
|
||||
Prints latest news about currency, including date, title and web link. [Source: News API]
|
||||
|
||||
* -n : Number of latest news being printed. Default 10.
|
||||
|
||||
## reddit <a name="reddit"></a>
|
||||
|
||||
```text
|
||||
usage: red [-l N_LIMIT] [-d N_DAYS] [-a]
|
||||
```
|
||||
|
||||
Print top stock's due diligence from other users. [Source: Reddit]
|
||||
|
||||
* -l : limit of posts to retrieve
|
||||
* -d : number of prior days to look for
|
||||
* -a : "search through all flairs (apart from Yolo and Meme). Default False (i.e. use flairs: DD, technical analysis, Catalyst, News, Advice, Chart, Charts and Setups, Fundamental Analysis, Forex, Trade Idea)
|
||||
|
||||
## eda <a name="eda"></a>
|
||||
```text
|
||||
usage: eda
|
||||
```
|
||||
|
||||
Access the exploratory data analysis menu.
|
||||
|
||||
## ba <a name="ba"></a>
|
||||
```text
|
||||
usage: ba
|
||||
```
|
||||
Access the behavioural analysis menu.
|
||||
|
||||
@@ -6,6 +6,11 @@ from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.menu import session
|
||||
from gamestonk_terminal.forex import fx_view
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.due_diligence import news_view, reddit_view
|
||||
from gamestonk_terminal.behavioural_analysis import ba_controller
|
||||
from gamestonk_terminal.exploratory_data_analysis import eda_controller
|
||||
import pandas as pd
|
||||
|
||||
|
||||
account = cfg.OANDA_ACCOUNT
|
||||
|
||||
@@ -31,6 +36,10 @@ class ForexController:
|
||||
"candles",
|
||||
"pending",
|
||||
"calendar",
|
||||
"news",
|
||||
"reddit",
|
||||
"eda",
|
||||
"ba",
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
@@ -69,6 +78,16 @@ class ForexController:
|
||||
print(" order place limit order -u # of units -p price")
|
||||
print(" orderbook print orderbook")
|
||||
print(" positionbook print positionbook")
|
||||
print(" news print news [News API]")
|
||||
print(
|
||||
" reddit search reddit for posts about the loaded instrument"
|
||||
)
|
||||
print(
|
||||
" eda > exploratory data analysis, e.g.: decompose, cusum, residuals analysis"
|
||||
)
|
||||
print(
|
||||
" ba > behavioural analysis, from: reddit, stocktwits, twitter, google"
|
||||
)
|
||||
print("")
|
||||
|
||||
def switch(self, an_input: str):
|
||||
@@ -152,6 +171,28 @@ class ForexController:
|
||||
"""Call calendar"""
|
||||
fx_view.calendar(self.instrument, other_args)
|
||||
|
||||
def call_news(self, other_args: List[str]):
|
||||
"""Call news [News API]"""
|
||||
news_view.news(other_args, self.instrument)
|
||||
|
||||
def call_reddit(self, other_args: List[str]):
|
||||
instrument = fx_view.format_instrument(self.instrument, " ")
|
||||
reddit_view.due_diligence(other_args, instrument)
|
||||
|
||||
def call_eda(self, other_args):
|
||||
df = fx_view.get_candles_dataframe(account, self.instrument, None)
|
||||
df = df.rename(columns={"Close": "5. adjusted close"})
|
||||
instrument = self.instrument
|
||||
s_start = pd.to_datetime(df.index.values[0])
|
||||
s_interval = "1440min"
|
||||
eda_controller.menu(df, instrument, s_start, s_interval)
|
||||
|
||||
def call_ba(self, other_args: List[str]):
|
||||
instrument = fx_view.format_instrument(self.instrument, " ")
|
||||
df = fx_view.get_candles_dataframe(account, self.instrument, None)
|
||||
s_start = pd.to_datetime(df.index.values[0])
|
||||
ba_controller.menu(instrument, s_start)
|
||||
|
||||
|
||||
def menu():
|
||||
"""Oanda Menu"""
|
||||
|
||||
@@ -12,8 +12,13 @@ from oandapyV20.exceptions import V20Error
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal import config_plot as cfgPlot
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn, plot_autoscale
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
parse_known_args_and_warn,
|
||||
plot_autoscale,
|
||||
check_non_negative,
|
||||
)
|
||||
import pandas as pd
|
||||
import pandas_ta as ta
|
||||
import mplfinance as mpf
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.ticker as mticker
|
||||
@@ -236,6 +241,11 @@ def create_order(accountID, instrument, other_args: List[str]):
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
if "JPY" or "THB" or "HUF" in instrument:
|
||||
ns_parser.price = round(ns_parser.price, 3)
|
||||
else:
|
||||
ns_parser.price = round(ns_parser.price, 5)
|
||||
check_non_negative(ns_parser.price)
|
||||
|
||||
data = {
|
||||
"order": {
|
||||
@@ -250,37 +260,25 @@ def create_order(accountID, instrument, other_args: List[str]):
|
||||
try:
|
||||
request = orders.OrderCreate(accountID, data)
|
||||
response = client.request(request)
|
||||
order_data = []
|
||||
order_data.append(
|
||||
{
|
||||
"Order ID": response["orderCreateTransaction"]["id"],
|
||||
"Instrument": response["orderCreateTransaction"]["instrument"],
|
||||
"Price": response["orderCreateTransaction"]["price"],
|
||||
"Units": response["orderCreateTransaction"]["units"],
|
||||
}
|
||||
)
|
||||
|
||||
if "orderFillTransaction" in response["orderCreateTransaction"]:
|
||||
order_id = response["orderCreateTransaction"]["orderFillTransaction"]["id"]
|
||||
order_instrument = response["orderCreateTransaction"][
|
||||
"orderFillTransaction"
|
||||
]["instrument"]
|
||||
units = response["orderCreateTransaction"]["orderFillTransaction"]["units"]
|
||||
price = response["orderCreateTransaction"]["orderFillTransaction"]["price"]
|
||||
print("Order Filled:")
|
||||
print(f"ID: {order_id}")
|
||||
print(f"Instrument: {order_instrument}")
|
||||
print(f"Units: {units}")
|
||||
print(f"Price: {price}")
|
||||
print("")
|
||||
else:
|
||||
order_creation_id = response["orderCreateTransaction"]["id"]
|
||||
order_instrument = response["orderCreateTransaction"]["instrument"]
|
||||
units = response["orderCreateTransaction"]["units"]
|
||||
price = response["orderCreateTransaction"]["price"]
|
||||
print("Order created:")
|
||||
print(f"ID: {order_creation_id}")
|
||||
print(f"Instrument: {order_instrument}")
|
||||
print(f"Units: {units}")
|
||||
print(f"Price: {price}")
|
||||
print("")
|
||||
df = pd.DataFrame.from_dict(order_data)
|
||||
print(df.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
except V20Error as e:
|
||||
d_error = eval(e.msg)
|
||||
print(d_error["message"], "\n")
|
||||
print(d_error["errorMessage"], "\n")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def cancel_pending_order(accountID, other_args: List[str]):
|
||||
@@ -327,21 +325,28 @@ def get_pending_orders(accountID, other_args):
|
||||
try:
|
||||
request = orders.OrdersPending(accountID)
|
||||
response = client.request(request)
|
||||
pending_data = []
|
||||
for i in range(len(response["orders"])):
|
||||
order_id = response["orders"][i]["id"]
|
||||
instrument = response["orders"][i]["instrument"]
|
||||
price = response["orders"][i]["price"]
|
||||
units = response["orders"][i]["units"]
|
||||
create_time = response["orders"][i]["createTime"]
|
||||
time_in_force = response["orders"][i]["timeInForce"]
|
||||
print(f"Order ID: {order_id}")
|
||||
print(f"Instrument: {instrument}")
|
||||
print(f"Price: {price}")
|
||||
print(f"Units: {units}")
|
||||
print(f"Time created: {create_time}")
|
||||
print(f"Time in force: {time_in_force}")
|
||||
print("-" * 30)
|
||||
pending_data.append(
|
||||
{
|
||||
"Order ID": response["orders"][i]["id"],
|
||||
"Instrument": response["orders"][i]["instrument"],
|
||||
"Price": response["orders"][i]["price"],
|
||||
"Units": response["orders"][i]["units"],
|
||||
"Time Created": response["orders"][i]["createTime"][:10]
|
||||
+ " "
|
||||
+ response["orders"][i]["createTime"][11:19],
|
||||
"Time In Force": response["orders"][i]["timeInForce"],
|
||||
}
|
||||
)
|
||||
|
||||
df = pd.DataFrame.from_dict(pending_data)
|
||||
if not pending_data:
|
||||
print("No pending orders")
|
||||
else:
|
||||
print(df.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except V20Error as e:
|
||||
d_error = eval(e.msg)
|
||||
print(d_error["errorMessage"], "\n")
|
||||
@@ -359,22 +364,26 @@ def get_open_positions(accountID, other_args):
|
||||
try:
|
||||
request = positions.OpenPositions(accountID)
|
||||
response = client.request(request)
|
||||
position_data = []
|
||||
for i in range(len(response["positions"])):
|
||||
instrument = response["positions"][i]["instrument"]
|
||||
long_units = response["positions"][i]["long"]["units"]
|
||||
long_pl = response["positions"][i]["long"]["pl"]
|
||||
long_upl = response["positions"][i]["long"]["unrealizedPL"]
|
||||
short_units = response["positions"][i]["short"]["units"]
|
||||
short_pl = response["positions"][i]["short"]["pl"]
|
||||
short_upl = response["positions"][i]["short"]["unrealizedPL"]
|
||||
print(f"Instrument: {instrument}\n")
|
||||
print(f"Long Units: {long_units}")
|
||||
print(f"Total Long P/L: {long_pl}")
|
||||
print(f"Long Unrealized P/L: {long_upl}\n")
|
||||
print(f"Short Units: {short_units}")
|
||||
print(f"Total Short P/L: {short_pl}")
|
||||
print(f"Short Unrealized P/L: {short_upl}")
|
||||
print("-" * 30 + "\n")
|
||||
position_data.append(
|
||||
{
|
||||
"Instrument": response["positions"][i]["instrument"],
|
||||
"Long Units": response["positions"][i]["long"]["units"],
|
||||
"Total Long P/L": response["positions"][i]["long"]["units"],
|
||||
"Unrealized Long P/L": response["positions"][i]["long"][
|
||||
"unrealizedPL"
|
||||
],
|
||||
"Short Units": response["positions"][i]["short"]["units"],
|
||||
"Total Short P/L": response["positions"][i]["short"]["pl"],
|
||||
"Short Unrealized P/L": response["positions"][i]["short"][
|
||||
"unrealizedPL"
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
df = pd.DataFrame.from_dict(position_data)
|
||||
print(df.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except V20Error as e:
|
||||
@@ -417,8 +426,10 @@ def get_open_trades(accountID, other_args):
|
||||
"unrealizedPL": "Unrealized P/L",
|
||||
}
|
||||
)
|
||||
print(df)
|
||||
|
||||
print(df.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except KeyError:
|
||||
print("No trades were found")
|
||||
print("")
|
||||
@@ -467,24 +478,25 @@ def close_trade(accountID, other_args: List[str]):
|
||||
request = trades.TradeClose(accountID, ns_parser.orderID, data)
|
||||
response = client.request(request)
|
||||
|
||||
order_id = response["orderCreateTransaction"]["tradeClose"]["tradeID"]
|
||||
order_instrument = response["orderFillTransaction"]["instrument"]
|
||||
units = response["orderCreateTransaction"]["units"]
|
||||
price = response["orderFillTransaction"]["price"]
|
||||
pl = response["orderFillTransaction"]["pl"]
|
||||
print("Order closed:")
|
||||
print(f"ID: {order_id}")
|
||||
print(f"Instrument: {order_instrument}")
|
||||
print(f"Units: {units}")
|
||||
print(f"Price: {price}")
|
||||
print(f"P/L: {pl}")
|
||||
close_data = []
|
||||
close_data.append(
|
||||
{
|
||||
"OrderID": response["orderCreateTransaction"]["tradeClose"]["tradeID"],
|
||||
"Instrument": response["orderFillTransaction"]["instrument"],
|
||||
"Units": response["orderCreateTransaction"]["units"],
|
||||
"Price": response["orderFillTransaction"]["price"],
|
||||
"P/L": response["orderFillTransaction"]["pl"],
|
||||
}
|
||||
)
|
||||
df = pd.DataFrame.from_dict(close_data)
|
||||
print(df.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
except V20Error as e:
|
||||
d_error = eval(e.msg)
|
||||
print(d_error["errorMessage"], "\n")
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def show_candles(accountID, instrument, other_args: List[str]):
|
||||
@@ -515,71 +527,164 @@ def show_candles(accountID, instrument, other_args: List[str]):
|
||||
required=False,
|
||||
help="The number of candles to retrieve. Default:180 ",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--ad",
|
||||
dest="ad",
|
||||
action="store_true",
|
||||
help="Adds ad (Accumulation/Distribution Indicator) to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--bbands",
|
||||
dest="bbands",
|
||||
action="store_true",
|
||||
help="Adds Bollinger Bands to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-C",
|
||||
"--cci",
|
||||
dest="cci",
|
||||
action="store_true",
|
||||
help="Adds cci (Commodity Channel Index) to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"--ema",
|
||||
dest="ema",
|
||||
action="store_true",
|
||||
help="Adds ema (Exponential Moving Average) to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--obv",
|
||||
dest="obv",
|
||||
action="store_true",
|
||||
help="Adds obv (On Balance Volume) to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--rsi",
|
||||
dest="rsi",
|
||||
action="store_true",
|
||||
help="Adds rsi (Relative Strength Index) to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--sma",
|
||||
dest="sma",
|
||||
action="store_true",
|
||||
help="Adds sma (Simple Moving Average) to the chart",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--vwap",
|
||||
dest="vwap",
|
||||
action="store_true",
|
||||
help="Adds vwap (Volume Weighted Average Price) to the chart",
|
||||
)
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
parameters = {}
|
||||
parameters["granularity"] = ns_parser.granularity
|
||||
parameters["granularity"] = ns_parser.granularity.upper()
|
||||
parameters["count"] = ns_parser.candlecount
|
||||
try:
|
||||
instrument = format_instrument(instrument, "_")
|
||||
request = instruments.InstrumentsCandles(instrument, params=parameters)
|
||||
response = client.request(request)
|
||||
process_candle_response(response)
|
||||
oanda_fix_date(".temp_candles.csv")
|
||||
df = pd.read_csv(".candles.csv", index_col=0)
|
||||
df.index = pd.to_datetime(df.index)
|
||||
df.columns = ["Open", "High", "Low", "Close", "Volume"]
|
||||
df = get_candles_dataframe(accountID, instrument, parameters)
|
||||
|
||||
plots_to_add, legends, subplot_legends = add_plots(df, ns_parser)
|
||||
|
||||
if gtff.USE_ION:
|
||||
plt.ion()
|
||||
mpf.plot(
|
||||
|
||||
fig, ax = mpf.plot(
|
||||
df,
|
||||
type="candle",
|
||||
style="charles",
|
||||
volume=True,
|
||||
title=f"{instrument} {ns_parser.granularity}",
|
||||
returnfig=True,
|
||||
addplot=plots_to_add,
|
||||
)
|
||||
|
||||
ax[0].set_title(f"{instrument} {ns_parser.granularity}")
|
||||
ax[0].legend(legends)
|
||||
for i in range(0, len(subplot_legends), 2):
|
||||
ax[subplot_legends[i]].legend(subplot_legends[i + 1])
|
||||
|
||||
print("")
|
||||
except V20Error as e:
|
||||
d_error = eval(e.msg)
|
||||
print(d_error["errorMessage"], "\n")
|
||||
except TypeError as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def process_candle_response(response):
|
||||
with open(".temp_candles.csv", "w") as out:
|
||||
for i in range(len(response["candles"])):
|
||||
time = response["candles"][i]["time"]
|
||||
volume = response["candles"][i]["volume"]
|
||||
o = response["candles"][i]["mid"]["o"]
|
||||
h = response["candles"][i]["mid"]["h"]
|
||||
low = response["candles"][i]["mid"]["l"]
|
||||
c = response["candles"][i]["mid"]["c"]
|
||||
out.write(
|
||||
str(time)
|
||||
+ ","
|
||||
+ str(o)
|
||||
+ ","
|
||||
+ str(h)
|
||||
+ ","
|
||||
+ str(low)
|
||||
+ ","
|
||||
+ str(c)
|
||||
+ ","
|
||||
+ str(volume)
|
||||
+ "\n"
|
||||
)
|
||||
def add_plots(df, ns_parser):
|
||||
panel_number = 2
|
||||
plots_to_add = []
|
||||
legends = []
|
||||
subplot_legends = []
|
||||
|
||||
if ns_parser.ad:
|
||||
ad = ta.ad(df["High"], df["Low"], df["Close"], df["Volume"])
|
||||
ad_plot = mpf.make_addplot(ad, panel=panel_number)
|
||||
plots_to_add.append(ad_plot)
|
||||
subplot_legends.extend([panel_number * 2, ["AD"]])
|
||||
panel_number += 1
|
||||
|
||||
def oanda_fix_date(file):
|
||||
with open(file) as candle_file:
|
||||
lines = candle_file.readlines()
|
||||
with open(".candles.csv", "w") as out:
|
||||
out.write("Datetime, Open, High, Low, Close, Volume\n")
|
||||
for line in lines:
|
||||
with open(".candles.csv", "a") as output:
|
||||
output.write(line[:10] + " " + line[11:19] + line[30:])
|
||||
if ns_parser.bbands:
|
||||
bbands = ta.bbands(df["Close"])
|
||||
bbands = bbands.drop("BBB_5_2.0", axis=1)
|
||||
bbands_plot = mpf.make_addplot(bbands, panel=0)
|
||||
plots_to_add.append(bbands_plot)
|
||||
legends.extend(["Lower BBand", "Middle BBand", "Upper BBand"])
|
||||
|
||||
if ns_parser.cci:
|
||||
cci = ta.cci(df["High"], df["Low"], df["Close"])
|
||||
cci_plot = mpf.make_addplot(cci, panel=panel_number)
|
||||
plots_to_add.append(cci_plot)
|
||||
subplot_legends.extend([panel_number * 2, ["CCI"]])
|
||||
panel_number += 1
|
||||
|
||||
if ns_parser.ema:
|
||||
ema = ta.ema(df["Close"])
|
||||
ema_plot = mpf.make_addplot(ema, panel=0)
|
||||
plots_to_add.append(ema_plot)
|
||||
legends.append("10 EMA")
|
||||
|
||||
if ns_parser.rsi:
|
||||
rsi = ta.rsi(df["Close"])
|
||||
rsi_plot = mpf.make_addplot(rsi, panel=panel_number)
|
||||
plots_to_add.append(rsi_plot)
|
||||
subplot_legends.extend([panel_number * 2, ["RSI"]])
|
||||
panel_number += 1
|
||||
|
||||
if ns_parser.obv:
|
||||
obv = ta.obv(df["Close"], df["Volume"])
|
||||
obv_plot = mpf.make_addplot(obv, panel=panel_number)
|
||||
plots_to_add.append(obv_plot)
|
||||
subplot_legends.extend([panel_number * 2, ["OBV"]])
|
||||
panel_number += 1
|
||||
|
||||
if ns_parser.sma:
|
||||
sma_length = [20, 50]
|
||||
for length in sma_length:
|
||||
sma = ta.sma(df["Close"], length=length)
|
||||
sma_plot = mpf.make_addplot(sma, panel=0)
|
||||
plots_to_add.append(sma_plot)
|
||||
legends.append(f"{length} SMA")
|
||||
|
||||
if ns_parser.vwap:
|
||||
vwap = ta.vwap(df["High"], df["Low"], df["Close"], df["Volume"])
|
||||
vwap_plot = mpf.make_addplot(vwap, panel=0)
|
||||
plots_to_add.append(vwap_plot)
|
||||
legends.append("vwap")
|
||||
|
||||
return plots_to_add, legends, subplot_legends
|
||||
|
||||
|
||||
def calendar(instrument, other_args: List[str]):
|
||||
@@ -665,6 +770,38 @@ def calendar(instrument, other_args: List[str]):
|
||||
print(d_error["message"], "\n")
|
||||
|
||||
|
||||
def get_candles_dataframe(accountID, instrument, parameters):
|
||||
if not parameters:
|
||||
parameters = {
|
||||
"granularity": "D",
|
||||
"count": "1500",
|
||||
}
|
||||
try:
|
||||
request = instruments.InstrumentsCandles(instrument, params=parameters)
|
||||
response = client.request(request)
|
||||
candles_data = []
|
||||
for i in range(len(response["candles"])):
|
||||
candles_data.append(
|
||||
{
|
||||
"Date": response["candles"][i]["time"][:10]
|
||||
+ " "
|
||||
+ response["candles"][i]["time"][11:19],
|
||||
"Open": float(response["candles"][i]["mid"]["o"]),
|
||||
"High": float(response["candles"][i]["mid"]["h"]),
|
||||
"Low": float(response["candles"][i]["mid"]["l"]),
|
||||
"Close": float(response["candles"][i]["mid"]["c"]),
|
||||
"Volume": response["candles"][i]["volume"],
|
||||
}
|
||||
)
|
||||
df = pd.DataFrame(candles_data)
|
||||
df.set_index("Date", inplace=True)
|
||||
df.index = pd.to_datetime(df.index)
|
||||
return df
|
||||
except V20Error as e:
|
||||
d_error = eval(e.msg)
|
||||
print(d_error["errorMessage"], "\n")
|
||||
|
||||
|
||||
def load(other_args: List[str]):
|
||||
"""Load a forex instrument to use"""
|
||||
parser = argparse.ArgumentParser(
|
||||
@@ -740,9 +877,16 @@ def book_plot(df, instrument, book_type):
|
||||
|
||||
|
||||
def format_instrument(instrument, char):
|
||||
if char not in instrument:
|
||||
instrument_list = list(instrument)
|
||||
instrument_list.pop(3)
|
||||
instrument_list.insert(3, char)
|
||||
instrument = "".join(map(str, instrument_list))
|
||||
return instrument
|
||||
try:
|
||||
if char not in instrument:
|
||||
instrument_list = list(instrument)
|
||||
instrument_list.pop(3)
|
||||
if char == " ":
|
||||
instrument = "".join(map(str, instrument_list))
|
||||
else:
|
||||
instrument_list.insert(3, char)
|
||||
instrument = "".join(map(str, instrument_list))
|
||||
return instrument
|
||||
except TypeError:
|
||||
print("Please load an instrument")
|
||||
print("")
|
||||
|
||||
Reference in New Issue
Block a user