mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
* Add README link to each menu * Retrieve good error when #517 happens * Fix column names with numbers in dataframes * Update README.md * ignore false positive
128 lines
3.9 KiB
Python
128 lines
3.9 KiB
Python
"""Backtesting Controller Module"""
|
|
__docformat__ = "numpy"
|
|
|
|
import argparse
|
|
from typing import List, Union
|
|
from datetime import datetime
|
|
import matplotlib as mpl
|
|
import matplotlib.pyplot as plt
|
|
from prompt_toolkit.completion import NestedCompleter
|
|
from gamestonk_terminal import feature_flags as gtff
|
|
from gamestonk_terminal.helper_funcs import get_flair
|
|
from gamestonk_terminal.menu import session
|
|
|
|
# This code below aims to fix an issue with the fnn module, used by bt module
|
|
# which forces matplotlib backend to be 'agg' which doesn't allow to plot
|
|
# Save current matplotlib backend
|
|
default_backend = mpl.get_backend()
|
|
# pylint: disable=wrong-import-position
|
|
from gamestonk_terminal.backtesting import bt_view # noqa: E402
|
|
|
|
# Restore backend matplotlib used
|
|
mpl.use(default_backend)
|
|
|
|
|
|
class BacktestingController:
|
|
"""Backtesting Class"""
|
|
|
|
CHOICES = ["help", "q", "quit", "ema", "ema_cross", "rsi"]
|
|
|
|
def __init__(
|
|
self,
|
|
ticker: str,
|
|
start: Union[datetime, str],
|
|
):
|
|
self.ticker = ticker
|
|
self.start = start
|
|
self.bt_parser = argparse.ArgumentParser(add_help=False, prog="bt")
|
|
self.bt_parser.add_argument(
|
|
"cmd",
|
|
choices=self.CHOICES,
|
|
)
|
|
|
|
def print_help(self):
|
|
"""Print help"""
|
|
print(
|
|
"https://github.com/GamestonkTerminal/GamestonkTerminal/tree/main/gamestonk_terminal/backtesting"
|
|
)
|
|
print("\nBacktesting:")
|
|
print(" help show this backtesting menu again")
|
|
print(" q quit this menu, and shows back to main menu")
|
|
print(" quit quit to abandon program")
|
|
print("")
|
|
print(" ema buy when price exceeds EMA(l)")
|
|
print(" ema_cross buy when EMA(short) > EMA(long) ")
|
|
print(" rsi buy when RSI < low and sell when RSI > high")
|
|
print("")
|
|
|
|
def switch(self, an_input: str):
|
|
"""Process and dispatch input
|
|
|
|
Returns
|
|
-------
|
|
True, False or None
|
|
False - quit the menu
|
|
True - quit the program
|
|
None - continue in the menu
|
|
"""
|
|
|
|
(known_args, other_args) = self.bt_parser.parse_known_args(an_input.split())
|
|
|
|
return getattr(
|
|
self, "call_" + known_args.cmd, lambda: "Command not recognized!"
|
|
)(other_args)
|
|
|
|
def call_help(self, _):
|
|
"""Process Help command"""
|
|
self.print_help()
|
|
|
|
def call_q(self, _):
|
|
"""Process Q command - quit the menu"""
|
|
return False
|
|
|
|
def call_quit(self, _):
|
|
"""Process Quit command - quit the program"""
|
|
return True
|
|
|
|
def call_ema(self, other_args: List[str]):
|
|
"""Call EMA strategy"""
|
|
bt_view.simple_ema(self.ticker, self.start, other_args)
|
|
|
|
def call_ema_cross(self, other_args: List[str]):
|
|
"""Call EMA Cross strategy"""
|
|
bt_view.ema_cross(self.ticker, self.start, other_args)
|
|
|
|
def call_rsi(self, other_args: List[str]):
|
|
"""Call RSI Strategy"""
|
|
bt_view.rsi_strat(self.ticker, self.start, other_args)
|
|
|
|
|
|
def menu(ticker: str, start: Union[str, datetime]):
|
|
"""Backtesting Menu"""
|
|
plt.close("all")
|
|
bt_controller = BacktestingController(ticker, start)
|
|
bt_controller.call_help(None)
|
|
|
|
while True:
|
|
# Get input command from user
|
|
if session and gtff.USE_PROMPT_TOOLKIT:
|
|
completer = NestedCompleter.from_nested_dict(
|
|
{c: None for c in bt_controller.CHOICES}
|
|
)
|
|
an_input = session.prompt(
|
|
f"{get_flair()} (bt)> ",
|
|
completer=completer,
|
|
)
|
|
else:
|
|
an_input = input(f"{get_flair()} (bt)> ")
|
|
|
|
try:
|
|
plt.close("all")
|
|
process_input = bt_controller.switch(an_input)
|
|
if process_input is not None:
|
|
return process_input
|
|
|
|
except SystemExit:
|
|
print("The command selected doesn't exist\n")
|
|
continue
|