diff --git a/gamestonk_terminal/oanda/oanda_controller.py b/gamestonk_terminal/oanda/oanda_controller.py index ebb446063be..8794f2f4656 100644 --- a/gamestonk_terminal/oanda/oanda_controller.py +++ b/gamestonk_terminal/oanda/oanda_controller.py @@ -1,5 +1,4 @@ import argparse -# import matplotlib.pyplot as plt from typing import List from prompt_toolkit.completion import NestedCompleter from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn @@ -28,16 +27,18 @@ class OandaController: "positions", "closetrade", "trades", - "pending"] + "candles", + "pending", + ] def __init__( self, - ): + ): """Construct Data""" self.oanda_parser = argparse.ArgumentParser(add_help=False, prog="fx") self.oanda_parser.add_argument( - "cmd", - choices=self.CHOICES, + "cmd", + choices=self.CHOICES, ) @staticmethod @@ -57,9 +58,10 @@ class OandaController: print("positionbook \t print positionbook") print("limitorder \t place limit order -u # of units -p price") print("cancel \t cancel a pending order by ID -i order ID") - print("pending \t get information on pending up to 25 pending orders") + print("pending \t get information on pending orders") print("positions \t Get open positions") print("closetrade \t Close a trade by id") + print("candles \t show candles") def switch(self, an_input: str): """Process and dispatch input @@ -72,7 +74,9 @@ class OandaController: """ (known_args, other_args) = self.oanda_parser.parse_known_args(an_input.split()) - return getattr(self, "call_" + known_args.cmd, lambda: "command not recognized!")(other_args) + return getattr( + self, "call_" + known_args.cmd, lambda: "command not recognized!" + )(other_args) def call_help(self, _): """Process Help Command""" @@ -94,23 +98,23 @@ class OandaController: """Process account summary command""" oanda_functions.get_account_summary(account) - def call_orderbook(self, other_args: List [str]): + def call_orderbook(self, other_args: List[str]): """Process Oanda Order Book""" oanda_functions.get_order_book(other_args) - def call_positionbook(self, other_args: List [str]): + def call_positionbook(self, other_args: List[str]): """Process Oanda Position Book""" oanda_functions.get_position_book(other_args) - def call_list(self, other_args: List [str]): + def call_list(self, other_args: List[str]): """Process list orders command""" oanda_functions.list_orders(account, other_args) - def call_limitorder(self, other_args: List [str]): - """Place market order""" + def call_limitorder(self, other_args: List[str]): + """Place limit order""" oanda_functions.create_limit_order(account, other_args) - def call_cancel(self, other_args: List [str]): + def call_cancel(self, other_args: List[str]): """Cancel pending order by ID""" oanda_functions.cancel_pending_order(account, other_args) @@ -122,39 +126,41 @@ class OandaController: """See up to 25 pending orders""" oanda_functions.get_pending_orders(account) - def call_closetrade(self, other_args: List [str]): + def call_closetrade(self, other_args: List[str]): """Close a trade by id""" oanda_functions.close_trade(account, other_args) + def call_candles(self, _): + oanda_functions.show_candles(account) + def call_trades(self, _): """List open trades""" oanda_functions.get_open_trades(account) def menu(): - """Oanda Menu""" - oanda_controller = OandaController() - oanda_controller.call_help(None) - while True: - if session and gtff.USE_PROMPT_TOOLKIT: - completer = NestedCompleter.from_nested_dict( - {c: None for c in oanda_controller.CHOICES} - ) + """Oanda Menu""" + oanda_controller = OandaController() + oanda_controller.call_help(None) + while True: + if session and gtff.USE_PROMPT_TOOLKIT: + completer = NestedCompleter.from_nested_dict( + {c: None for c in oanda_controller.CHOICES} + ) - an_input = session.prompt( + an_input = session.prompt( f"{get_flair()} (fx)> ", completer=completer, - ) - else: - an_input = input(f"{get_flair()} (fx)> ") + ) + else: + an_input = input(f"{get_flair()} (fx)> ") - try: - process_input = oanda_controller.switch(an_input) + try: + process_input = oanda_controller.switch(an_input) - if process_input is not None: - return process_input - - except SystemExit: - print("The command selected doesn't exit\n") - continue + if process_input is not None: + return process_input + except SystemExit: + print("The command selected doesn't exit\n") + continue diff --git a/gamestonk_terminal/oanda/oanda_functions.py b/gamestonk_terminal/oanda/oanda_functions.py index e93f6f1a3f3..fa3db84bca5 100644 --- a/gamestonk_terminal/oanda/oanda_functions.py +++ b/gamestonk_terminal/oanda/oanda_functions.py @@ -10,6 +10,10 @@ import oandapyV20.endpoints.trades as trades from oandapyV20.exceptions import V20Error from gamestonk_terminal import config_terminal as cfg from gamestonk_terminal.helper_funcs import parse_known_args_and_warn +import pandas as pd +import matplotlib.pyplot as plt +import mplfinance as mpf +import matplotlib.dates as mdates client = API(access_token=cfg.OANDA_TOKEN, environment="live") account = cfg.OANDA_ACCOUNT @@ -22,20 +26,14 @@ def get_fx_price(accountID, other_args: List[str]): description="Get price for forex", ) parser.add_argument( - "-i", - "--instrument", - dest="instrument", - action="store", - required=True + "-i", "--instrument", dest="instrument", action="store", required=True ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return try: - parameters = { - "instruments": ns_parser.instrument - } + parameters = {"instruments": ns_parser.instrument} request = pricing.PricingInfo(accountID=accountID, params=parameters) response = client.request(request) bid = response["prices"][0]["bids"][0]["price"] @@ -74,42 +72,32 @@ def get_account_summary(accountID): print(f"Margin Closeout Position Value: {margin_closeout_position_value}") -def list_orders(accountID, other_args: List [str]): +def list_orders(accountID, other_args: List[str]): parser = argparse.ArgumentParser( add_help=False, prog="listorders", description="List order history", ) parser.add_argument( - "-s", - "--state", - dest="state", - action="store", - default="ALL", - required=False + "-s", "--state", dest="state", action="store", default="ALL", required=False ) parser.add_argument( - "-c", - "--count", - dest="count", - action="store", - default=50, - required=False + "-c", "--count", dest="count", action="store", default=50, required=False ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return parameters = { -# "state": ns_parser.state, -# "count": ns_parser.count, + # "state": ns_parser.state, + # "count": ns_parser.count, } if ns_parser.state is not None: parameters["state"] = ns_parser.state if ns_parser.count is not None: parameters["count"] = ns_parser.count - request = orders.OrderList(accountID, parameters) + request = orders.OrderList(accountID, parameters) response = client.request(request) for i in range(0, int(ns_parser.count), 1): try: @@ -124,34 +112,30 @@ def list_orders(accountID, other_args: List [str]): print(f"Units: {units}") print(f"Order State: {order_state}") print(f"Order Type: {order_type}") - print("-"*30) + print("-" * 30) except KeyError: continue except IndexError: break -def get_order_book(other_args: List [str]): +def get_order_book(other_args: List[str]): parser = argparse.ArgumentParser( add_help=False, prog="get_order_book", description="Get Order book", ) parser.add_argument( - "-i", - "--instrument", - dest="instrument", - action="store", - required=True + "-i", "--instrument", dest="instrument", action="store", required=True ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return - parameters = { - "bucketWidth": 0.1 - } - request = instruments.InstrumentsOrderBook(instrument=ns_parser.instrument, params=parameters) + parameters = {"bucketWidth": 0.1} + request = instruments.InstrumentsOrderBook( + instrument=ns_parser.instrument, params=parameters + ) response = client.request(request) for i in range(400, 700, 1): @@ -163,79 +147,83 @@ def get_order_book(other_args: List [str]): print(f"Price: {price}") print(f"Short count percent: {short_count_percent}") print(f"Long count percent: {long_count_percent}") - print("-"*30) + print("-" * 30) -def get_position_book(other_args: List [str]): +def get_position_book(other_args: List[str]): parser = argparse.ArgumentParser( add_help=False, prog="get_position_book ", description="Get Position Book", ) parser.add_argument( - "-i", - "--instrument", - dest="instrument", - action="store", - required=True - ) + "-i", "--instrument", dest="instrument", action="store", required=True + ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return - parameters = { - "bucketWidth": 0.1 - } - request = instruments.InstrumentsPositionBook (instrument=ns_parser.instrument, params=parameters) + parameters = {"bucketWidth": 0.1} + request = instruments.InstrumentsPositionBook( + instrument=ns_parser.instrument, params=parameters + ) response = client.request(request) - for i in range(200,400,1): + for i in range(200, 400, 1): order_instrument = response["positionBook"]["instrument"] price = response["positionBook"]["buckets"][i]["price"] - short_count_percent = response["positionBook"]["buckets"][i]["shortCountPercent"] + short_count_percent = response["positionBook"]["buckets"][i][ + "shortCountPercent" + ] long_count_percent = response["positionBook"]["buckets"][i]["longCountPercent"] print(f"Instrument: {order_instrument}") print(f"Price: {price}") print(f"Short count percent: {short_count_percent}") print(f"Long count percent: {long_count_percent}") - print("-"*30) + print("-" * 30) -def create_limit_order(accountID, instrument, other_args: List[str]): +def create_limit_order(accountID, other_args: List[str]): parser = argparse.ArgumentParser( - add_help=False, - prog="create_limit_order", - description="Create limit order", + add_help=False, + prog="create_limit_order", + description="Create limit order", ) parser.add_argument( - "-u", - "--unit", - dest="units", - action="store", - type=int, - default=0, - required=True, + "-u", + "--unit", + dest="units", + action="store", + type=int, + default=0, + required=True, ) parser.add_argument( - "-p", - "--price", - dest="price", - action="store", - type=float, - required=True, + "-p", + "--price", + dest="price", + action="store", + type=float, + required=True, ) + parser.add_argument( + "-i", + "--instrument", + dest="instrument", + action="store", + required=True) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return data = { - "order":{ + "order": { "price": ns_parser.price, - "instrument": instrument, + "instrument": ns_parser.instrument, "units": ns_parser.units, "type": "LIMIT", - "timeInForce":"GTC", - "positionFill": "DEFAULT" + "timeInForce": "GTC", + "positionFill": "DEFAULT", } } request = orders.OrderCreate(accountID, data) @@ -250,12 +238,12 @@ def cancel_pending_order(accountID, other_args: List[str]): description="Cancel Pending Order", ) parser.add_argument( - "-i", - "--id", - dest="orderID", - action="store", - type=str, - required=True, + "-i", + "--id", + dest="orderID", + action="store", + type=str, + required=True, ) ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: @@ -270,7 +258,7 @@ def cancel_pending_order(accountID, other_args: List[str]): def get_pending_orders(accountID): request = orders.OrdersPending(accountID) response = client.request(request) - for i in range(0,25,1): + for i in range(len(response["orders"])): try: order_id = response["orders"][i]["id"] instrument = response["orders"][i]["instrument"] @@ -284,7 +272,7 @@ def get_pending_orders(accountID): print(f"Units: {units}") print(f"Time created: {create_time}") print(f"Time in force: {time_in_force}") - print("-"*30) + print("-" * 30) except IndexError: break @@ -292,7 +280,7 @@ def get_pending_orders(accountID): def get_open_positions(accountID): request = positions.OpenPositions(accountID) response = client.request(request) - for i in range(0,100,1): + for i in range(0, 100, 1): try: instrument = response["positions"][i]["instrument"] long_units = response["positions"][i]["long"]["units"] @@ -303,12 +291,12 @@ def get_open_positions(accountID): short_upl = response["positions"][i]["short"]["unrealizedPL"] print(f"Instrument: {instrument}\n") print(f"Long Units: {long_units}") - print(f"Long P/L: {long_pl}") + 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"Short P/L: {short_pl}") + print(f"Total Short P/L: {short_pl}") print(f"Short Unrealized P/L: {short_upl}") - print("-"*30+"\n") + print("-" * 30 + "\n") except IndexError: break @@ -316,7 +304,7 @@ def get_open_positions(accountID): def get_open_trades(accountID): request = trades.OpenTrades(accountID) response = client.request(request) - for i in range (0,100,1): + for i in range(len(response["trades"])): try: order_id = response["trades"][i]["id"] instrument = response["trades"][i]["instrument"] @@ -328,20 +316,16 @@ def get_open_trades(accountID): print(f"Instrument: {instrument}") print(f"Initial Units: {initial_units}") print(f"Current Units: {current_units}") - print(f"Price: {price}") + print(f"Entry Price: {price}") print(f"Unrealized P/L: {unrealized_pl}") - print("-"*30+"\n") + print("-" * 30 + "\n") except IndexError: break - - - - def close_trade(accountID, other_args: List[str]): parser = ArgumentParser( - add_help = False, + add_help=False, prog="close_trade", description="close a trade", ) @@ -364,11 +348,63 @@ def close_trade(accountID, other_args: List[str]): ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return - data={ + data = { "units": ns_parser.units, - } + } try: request = trades.TradeClose(accountID, ns_parser.orderID, data) response = client.request(request) except V20Error as e: print(e) + + +def show_candles(accountID): + parameters = { + "granularity": "D" + } + try: + request = instruments.InstrumentsCandles("EUR_USD", params=parameters) + response = client.request(request) + process_response(response) + oanda_fix_date(".temp_candles.csv") + df = pd.read_csv(".candles.csv") + df["Datetime"] = pd.to_datetime(df["Datetime"]) + df.set_index(pd.DatetimeIndex(df["Datetime"]), inplace=True) + print(df) +# dvalues = df[["Open", "High", "Low", "Close"]].values.tolist() +# pdates = mdates.date2num(data.index) +# ohlc = [ ppdates[i] + dvalues[i] for i in range(len(pdates))] +# plt.style.use("fivethirtyeight") +# fix, ax = plt.subplots(figsize = (12, 6)) +# mpf.candlestick_ohlc(ax, ohlc[-50:], width=0.4) +# ax.set_xlabel("Date") +# ax.set_ylabel("Price") +# ax.set_title("Chart for EUR_USD") +# ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d')) +# fig.autofmt_xdate() + mpf.plot(df, type="candlestick") +# plt.show() + + except Exception as e: + print(e) + + +def process_response(response): + with open(".temp_candles.csv", 'w') as out: + for i in range(len(response["candles"])): + time = response["candles"][i]["time"] + o = response["candles"][i]["mid"]["o"] + h = response["candles"][i]["mid"]["h"] + l = response["candles"][i]["mid"]["l"] + c = response["candles"][i]["mid"]["c"] + out.write(str(time) + "," + str(o) + "," + str(h) + "," + str(l) + "," + str(c) + "\n") + + +def oanda_fix_date(file): + with open(file, 'r') as candle_file: + lines = candle_file.readlines() + with open(".candles.csv", 'w') as out: + out.write("Datetime, Open, High, Low, Close\n") + for line in lines: + with open(".candles.csv", "a") as output: + output.write(line[:10] + " " + line[11:19] + line[30:])