def test_gen_signal(): """ Tests two stocks with freezed data set """ config = TraderBase.get_config() db_tool = Db(config['sql'], TEST_LOGGER) db_tool.connect() symbols = [["LHA", 0.6, 2], ["MRK", 0.4, 0]] for symbol in symbols: stock = db_tool.session.query(Stock).filter( symbol[0] == Stock.symbol).first() arguments = { 'stock': stock, 'name': 'StockIsHot2Month', 'bars': None, 'threshold_buy': 0.8, 'threshold_sell': 0.5, 'intervals': [7, 30], 'secure_value': 0.84, 'lookback': 2 } my_filter = Sih(arguments, TEST_LOGGER) bars = stock.get_bars(my_filter.look_back_date(), output_type=BARS_NUMPY) my_filter.set_bars(bars) status = my_filter.analyse() TEST_LOGGER.info("%s score is: %s and status %s", symbol[0], my_filter.get_calculation(), status) npt.assert_almost_equal(my_filter.get_calculation(), symbol[1], decimal=4) assert symbol[2] == status db_tool.session.close()
def test_gen_signal(): """ Tests two stocks with freezed data set """ config = TraderBase.get_config() db_tool = Db(config['sql'], TEST_LOGGER) db_tool.connect() symbols = [["LHA", 5, 0], ["MRK", -6, 0]] for symbol in symbols: stock = db_tool.session.query(Stock).filter( symbol[0] == Stock.symbol).first() arguments = { 'stock': stock, 'name': Pr.NAME, 'bars': stock.get_bars(output_type=BARS_NUMPY), 'threshold_buy': 10, 'threshold_sell': 5, 'intervals': None, 'lookback': 2 } my_filter = Pr(arguments, TEST_LOGGER) status = my_filter.analyse() TEST_LOGGER.info("%s score is: %s and status %s", symbol[0], my_filter.get_calculation(), status) assert symbol[1] == my_filter.get_calculation() assert symbol[2] == status db_tool.session.close()
def compare_excepted_with_results(): """ Tests two stocks with freezed data set """ config = TraderBase.get_config() db_tool = Db(config['sql'], TestBase.TEST_LOGGER) db_tool.connect() symbols = TestBase.test_stocks excepted_results = TestBase.test_excepted_results results = [] # collect results for symbol in symbols: stock = db_tool.session.query(Stock).filter( symbol == Stock.symbol).first() for param in TestBase.test_params: results.append(TestBase.calculate_profit(stock, None, param)) # compare calculated results with excepted results for idx, result in enumerate(results): TestBase.TEST_LOGGER.info("Profit is %s and status %s", result[0], result[1]) assert result[1] == excepted_results[idx][ 1], "Test%s: %s != %s" % (idx, result[1], excepted_results[idx][1]) db_tool.session.close()
def test_date_gen_for_back_test(self): """ Tests the date generator / splitter :return: """ from_date, to_date = get_from_to_dates(None, None) assert from_date is None and to_date is None config = TraderBase.get_config() logger = TraderBase.setup_logger("autotrader") db_tool = StockDataBase(config["sql"], logger) db_tool.connect() db_tool.session.query(Plot).delete() db_tool.session.query(Parameter).delete() db_tool.session.query(Signal).delete() stock = db_tool.session.query(Stock).first() with freeze_time("2017-10-02 09:54"): my_signal = Signal( profit_in_percent=1, name="TestSignal", status=2, date=datetime.datetime.now(), refresh_date=datetime.datetime.now(), ) stock.signal.append(my_signal) with freeze_time("2017-08-02 09:33"): my_signal = Signal( profit_in_percent=1, name="TestSignal", status=2, date=datetime.datetime.now(), refresh_date=datetime.datetime.now(), ) stock.signal.append(my_signal) with freeze_time("2017-10-02"): my_dates_tasks = [get_from_to_dates(db_tool, [idx, 8]) for idx in range(8)] assert len(my_dates_tasks) == 8 my_dates_tasks_back = [] for from_date, to_date in my_dates_tasks: for my_date in BackTestingStrategy.date_range(from_date, to_date): my_dates_tasks_back.append(my_date) my_first_date = db_tool.session.query(Signal.date).order_by(Signal.date).first() my_dates_orig = [my_date for my_date in BackTestingStrategy.date_range(my_first_date[0], datetime.datetime.now())] # assert len(my_dates_orig) == len(my_dates_tasks_back) # for idx, my_date_back in enumerate(my_dates_tasks_back): # assert my_date_back == my_dates_orig[idx] db_tool.session.rollback()
def test2_signal_quick(self): """ Tests the update precess """ self.test1_signal_full() my_signals = self.db_tool.session.query(Signal).all() len_signals_after = len(my_signals) len_stocks = len(self.db_tool.session.query(Stock).all()) assert len_signals_after == len_stocks arguments = { 'signals': AroonSignal.SHORT_NAME, 'stocks': ["ALL"], 'look_back': 300, 'offline': True, 'db_tool': self.db_tool } exit_code = BuildIndicatorsBackTest(self.config, arguments, self.test_logger).build() assert exit_code == 0 self.db_tool.session = None self.db_tool = Db(self.config['sql'], self.test_logger) self.db_tool.connect() my_signals = self.db_tool.session.query(Signal).all() len_signals_after = len(my_signals) assert len_signals_after == len_stocks len_plot_after = len(self.db_tool.session.query(Plot).all()) len_parameter_after = len(self.db_tool.session.query(Parameter).all()) assert len_parameter_after == len_plot_after == len_signals_after for my_signal in my_signals: now_date = datetime.datetime.now().date() refresh_date = my_signal.refresh_date.date() assert now_date == refresh_date
def test_3_test_update_sheet(): """ test update balance and income :return: """ db_tool = StockDataBase(CONFIG["sql"], TEST_LOGGER) db_tool.connect() arguments = { 'stocks_to_update': ['ALL'], 'update_stocks': False, 'update_sheets': True, 'db_tool': db_tool, 'datasource': DegiroClient(CONFIG['degiro'], {"db_tool": db_tool}, TEST_LOGGER) } db_update = UpdateDataBaseStocks(CONFIG, arguments, TEST_LOGGER) db_update.build()
def setUpClass(cls): cls.config = TraderBase.get_config() cls.db = StockDataBase(cls.config['sql'], TEST_LOGGER) cls.db.connect() arguments = {"db_tool": cls.db} cls.client = DegiroClient(cls.config['degiro'], arguments, TEST_LOGGER) cls.client.login()
def test_get_stocks(self): """ Test stocks splitter :return: """ stocks = get_stocks(None, None) assert 'ALL' in stocks and len(stocks) == 1 config = TraderBase.get_config() logger = TraderBase.setup_logger("autotrader") db_tool = StockDataBase(config["sql"], logger) db_tool.connect() my_stocks = db_tool.session.query(Stock.id).all() my_stocks_orig = [my_stock[0] for my_stock in my_stocks if my_stock] my_stocks_tasks = [] for idx in range(8): my_stocks_tasks += get_stocks(db_tool, [idx, 8]) assert len(my_stocks) == len(my_stocks_tasks) for idx, stock_orig in enumerate(my_stocks_orig): assert stock_orig == my_stocks_tasks[idx]
def check_consistency(): """ Checks if results are stable. The method must produce same values after n runs. """ config = TraderBase.get_config() db_tool = Db(config['sql'], TestBase.TEST_LOGGER) db_tool.connect() stock = db_tool.session.query(Stock).filter( Stock.symbol == TestBase.test_stocks[1]).first() status_list = [] profits_list = [] for _ in range(100): profit, status = TestBase.calculate_profit(stock, TestBase.test_strategy, TestBase.test_params) status_list.append(status) profits_list.append(profit) # check if profit elements are equal and status elements are equal assert status_list.count(status_list[0]) == len(status_list) assert profits_list.count(profits_list[0]) == len(profits_list) db_tool.session.close()
def test_levermann(): """ Tests two stocks with freezed data set """ config = TraderBase.get_config() db_tool = Db(config['sql'], TEST_LOGGER) db_tool.connect() symbols = [["LHA", 1, 0], ["MRK", -1, 0]] for symbol in symbols: stock = db_tool.session.query(Stock).filter( symbol[0] == Stock.symbol).first() arguments = { 'stock': stock, 'name': Ls.NAME, 'bars': stock.get_bars(start=datetime.datetime(2016, 6, 1, 0, 0), end=datetime.datetime(2017, 9, 1, 0, 0), output_type=BARS_NUMPY), 'threshold_buy': 7, 'threshold_sell': 2, 'intervals': None, 'lookback': 12 } my_filter = Ls(arguments, TEST_LOGGER) status = my_filter.analyse() TEST_LOGGER.info("%s score is: %s - %s", symbol[0], my_filter.get_calculation(), status) assert symbol[1] == my_filter.get_calculation(),\ " Calc: %s != %s" % (symbol[1], my_filter.get_calculation()) assert symbol[2] == status, " Status: %s != %s" % (symbol[2], status) db_tool.session.close()
def test_1_install_db(): """ test install db :return: """ arguments = {} db_tool = StockDataBase(CONFIG["sql"], TEST_LOGGER) arguments["db_tool"] = db_tool arguments["datasource"] = DegiroClient(CONFIG['degiro'], {}, TEST_LOGGER) db_builder = CreateAndFillDataBase(CONFIG, arguments, TEST_LOGGER) db_builder.build() DB.connect() adidas = DB.session.query(Stock).filter(Stock.name == "Adidas AG").first() # check if stock has data assert adidas.series bars = adidas.get_bars(resolution="PT1S") assert not bars bars = adidas.get_bars() assert bars bars = adidas.get_bars(output_type=BARS_NUMPY) assert bars.shape[1] > 0 bars = adidas.get_bars(output_type=BARS_PANDAS) assert bars.size > 0 DB.session.close()
def autotrader_app(): """ Main entry point for autotrader application :return: """ # print usage when no option is given parsed_args = get_arg_parse(sys.argv[1:]) exit_code = 0 if not parsed_args: return False if parsed_args.config: config = TraderBase.get_config(parsed_args.config) logger = TraderBase.setup_logger("autotrader") db_tool = StockDataBase(config["sql"], logger) db_tool.connect() print("Autotrader {}".format(VERSION)) if parsed_args.app: build_app_db(logger, db_tool) if parsed_args.dump: build_yaml_file(db_tool) if parsed_args.install is not None: datasource = DegiroClient(config['degiro'], {"db_tool": None}, logger) arguments = { 'stocks_to_update': ['ALL'], # For UpdateDataBaseStocks 'update_stocks': False, # For UpdateDataBaseStocks 'update_sheets': True, # For UpdateDataBaseStocks 'db_tool': db_tool, 'datasource': datasource } exit_code += CreateAndFillDataBase(config, arguments, logger).build() exit_code += UpdateDataBaseStocks(config, arguments, logger).build() if parsed_args.update is not None: arguments = { 'stocks_to_update': parsed_args.update, 'update_stocks': True, 'update_sheets': False, 'db_tool': db_tool, 'datasource': DegiroClient(config['degiro'], {"db_tool": db_tool}, logger) } exit_code += UpdateDataBaseStocks(config, arguments, logger).build() if parsed_args.updatesheets is not None: arguments = { 'stocks_to_update': parsed_args.updatesheets, 'update_stocks': False, 'update_sheets': True, 'db_tool': db_tool, 'datasource': DegiroClient(config['degiro'], {"db_tool": db_tool}, logger) } exit_code += UpdateDataBaseStocks(config, arguments, logger).build() if parsed_args.backup is not None: raise NotImplementedError if parsed_args.filter is not None: arguments = {'db_tool': db_tool} exit_code += BuildFilters(arguments, logger).build() if parsed_args.rebuild_filter is not None: from_date, to_date = get_from_to_dates(db_tool, parsed_args.task) arguments = { 'db_tool': db_tool, "from_date": from_date, "to_date": to_date, 'filters': parsed_args.rebuild_filter } exit_code += RecreateFilters(arguments, logger).build() if parsed_args.delete_filter is not None: arguments = { 'db_tool': db_tool, 'filters': parsed_args.delete_filter } my_recreate = RecreateFilters(arguments, logger) my_recreate.delete_old_filter() if parsed_args.delete_backtest_strategy is not None: arguments_broker = { "portfolio_name": "", "portfolio_user": "******", "database_data": True, "db_tool": db_tool, "cash": 2000 } arguments = { 'strategies': ["ALL"], 'broker': DemoBroker(config, arguments_broker, logger), 'strategy_name_prefix': 'B', 'db_tool': db_tool } StartStrategy(config, arguments, logger).recreate_all_strategies() arguments["broker"].commit_work() if parsed_args.delete_demo_strategy is not None: arguments_broker = { "portfolio_name": "", "portfolio_user": "******", "database_data": True, "db_tool": db_tool, "cash": 2000 } arguments = { 'strategies': ["ALL"], 'broker': DemoBroker(config, arguments_broker, logger), 'strategy_name_prefix': 'D', 'db_tool': db_tool } StartStrategy(config, arguments, logger).recreate_all_strategies() arguments["broker"].commit_work() if parsed_args.signals is not None: # split all stocks in almost equal pieces and get part of split by task id my_stocks = get_stocks(db_tool, parsed_args.task) arguments = { 'signals': ["ALL"], 'stocks': my_stocks, "look_back": 300, 'db_tool': db_tool } exit_code += BuildIndicators(config, arguments, logger).build() if parsed_args.quicksignals is not None: # split all stocks in almost equal pieces and get part of split by task id my_stocks = get_stocks(db_tool, parsed_args.task) arguments = { 'signals': ["ALL"], 'stocks': my_stocks, "look_back": 300, 'db_tool': db_tool } exit_code += BuildIndicatorsQuick(config, arguments, logger).build() if parsed_args.live: arguments_broker = { "portfolio_name": "degiro", "portfolio_user": "******", "database_data": False, "db_tool": db_tool } degiro = DegiroClient(config["degiro"], arguments_broker, logger) degiro.login() arguments = { 'strategies': ["SecureHotH6MonthT50V40"], 'broker': degiro, 'strategy_name_prefix': 'L', 'db_tool': db_tool } exit_code += StartStrategy(config, arguments, logger).build() if parsed_args.strategy is not None: arguments_broker = { "portfolio_name": "", "portfolio_user": "******", "database_data": False, "db_tool": db_tool, "cash": 2000 } arguments = { 'strategies': parsed_args.strategy, 'broker': DemoBroker(config, arguments_broker, logger), 'strategy_name_prefix': 'D', 'db_tool': db_tool } exit_code += StartStrategy(config, arguments, logger).build() arguments["broker"].commit_work() if parsed_args.back_test_strategy is not None: arguments_broker = { "portfolio_name": "", "portfolio_user": "******", "database_data": True, "db_tool": db_tool, "cash": 2000 } backtest_days = int(config['autotrader']['backtest_days']) from_date, to_date = datetime.datetime.now() + datetime.timedelta(days=-backtest_days), \ datetime.datetime.now() arguments = { "strategies": ["ALL"], 'stocks': ["ALL"], "signals": ["ALL"], 'db_tool': db_tool, "broker": DemoBroker(config, arguments_broker, logger), "from_date": from_date, "to_date": to_date } exit_code += BackTestingStrategy(config, arguments, logger).build() arguments["broker"].commit_work() if parsed_args.version: print(VERSION) return exit_code
class TestSignalTool(unittest.TestCase): """ Tests the signal generator tool """ @classmethod def setUpClass(cls): """ create test basics :return: """ cls.config = TraderBase.get_config() cls.test_logger = logging.getLogger() cls.test_logger.setLevel(logging.WARNING) cls.db_tool = Db(cls.config['sql'], cls.test_logger) cls.db_tool.connect() assert 'PYCHARM' in os.environ or cls.config['sql']['address'] == 'mysqltest' @classmethod def tearDownClass(cls): cls.db_tool.session = None def setUp(self): self.delete_all() def tearDown(self): self.delete_all() @freeze_time("2017-10-02") def test1_signal_full(self): """ Tests the signal creation :return: """ len_signals_before = len(self.db_tool.session.query(Signal).all()) arguments = { 'signals': AroonSignal.SHORT_NAME, 'stocks': ["ALL"], "look_back": 300, "db_tool": self.db_tool } exit_code = BuildIndicators(self.config, arguments, self.test_logger).build() assert exit_code == 0 len_signals_after = len(self.db_tool.session.query(Signal).all()) assert len_signals_after > len_signals_before len_stocks = len(self.db_tool.session.query(Stock).all()) assert len_signals_after == len_stocks len_plot_after = len(self.db_tool.session.query(Plot).all()) len_parameter_after = len(self.db_tool.session.query(Parameter).all()) assert len_parameter_after == len_plot_after == len_stocks @freeze_time("2017-10-06") def test2_signal_quick(self): """ Tests the update precess """ self.test1_signal_full() my_signals = self.db_tool.session.query(Signal).all() len_signals_after = len(my_signals) len_stocks = len(self.db_tool.session.query(Stock).all()) assert len_signals_after == len_stocks arguments = { 'signals': AroonSignal.SHORT_NAME, 'stocks': ["ALL"], 'look_back': 300, 'offline': True, 'db_tool': self.db_tool } exit_code = BuildIndicatorsBackTest(self.config, arguments, self.test_logger).build() assert exit_code == 0 self.db_tool.session = None self.db_tool = Db(self.config['sql'], self.test_logger) self.db_tool.connect() my_signals = self.db_tool.session.query(Signal).all() len_signals_after = len(my_signals) assert len_signals_after == len_stocks len_plot_after = len(self.db_tool.session.query(Plot).all()) len_parameter_after = len(self.db_tool.session.query(Parameter).all()) assert len_parameter_after == len_plot_after == len_signals_after for my_signal in my_signals: now_date = datetime.datetime.now().date() refresh_date = my_signal.refresh_date.date() assert now_date == refresh_date def delete_all(self): """ Deletes all plot, parameter and signal records :return: """ self.db_tool.session.query(Plot).delete() self.db_tool.session.query(Parameter).delete() self.db_tool.session.query(Signal).delete() self.db_tool.commit()
def test2_trade(self): """ Test order sell/buy :return: """ portfolio_name = "degiro" portfolio_user = "******" arguments = { "portfolio_name": portfolio_name, "portfolio_user": portfolio_user, "database_data": True, "db_tool": self.db_tool, "cash": 2000 } broker = DemoBroker(self.config, arguments, TEST_LOGGER) broker.delete_portfolio(portfolio_name, portfolio_user) self.db_tool.commit() broker.set_portfolio(portfolio_name, portfolio_user, 2000) order_data = { "orderType": OrderType.market, "timeType": 1, "price": -1, "size": 5 } ads = self.db_tool.session.query(Stock).filter( Stock.symbol == 'ADS').first() ifx = self.db_tool.session.query(Stock).filter( Stock.symbol == 'IFX').first() lha = self.db_tool.session.query(Stock).filter( Stock.symbol == 'LHA').first() assert ads and ifx and lha self.assertRaises(RuntimeError, broker.buy, -1, "XETR", order_data) self.assertRaises(RuntimeError, broker.buy, ads.id, "TR", order_data) order_id = broker.buy(ads.id, "XETR", order_data) broker.commit_work() orders_by_id = list( broker.db_tool.session.query(Orders).filter( Orders.order_uuid == order_id)) assert len(orders_by_id) == 1 order_data["size"] = 5000 self.assertRaises(RuntimeError, broker.buy, ads.id, "XETR", order_data) order_data["size"] = 6 self.assertRaises(RuntimeError, broker.sell, ads.id, "XETR", order_data) order_data["size"] = 5 order_id = broker.sell(ads.id, "XETR", order_data) orders_by_id = list( broker.db_tool.session.query(Orders).filter( Orders.order_uuid == order_id)) assert len(orders_by_id) == 1 broker.delete_portfolio(portfolio_name, portfolio_user) broker.commit_work() broker.set_portfolio(portfolio_name, portfolio_user, 4000) broker.buy(ads.id, "XETR", order_data) broker.buy(ifx.id, "XETR", order_data) broker.buy(lha.id, "XETR", order_data) broker.sell(ads.id, "XETR", order_data) broker.sell(ifx.id, "XETR", order_data) order_data["size"] = 1 broker.sell(lha.id, "XETR", order_data) broker.sell(lha.id, "XETR", order_data) broker.sell(lha.id, "XETR", order_data) broker.sell(lha.id, "XETR", order_data) broker.sell(lha.id, "XETR", order_data) self.assertRaises(RuntimeError, broker.sell, lha.id, "XETR", order_data) order_data = { "orderType": OrderType.limit, "timeType": 1, "price": 15.25, "size": 5 } order_id_limit = broker.buy(ifx.id, "XETR", order_data) assert order_id_limit orders_by_id = list( broker.db_tool.session.query(Orders).filter( Orders.order_uuid == order_id_limit)) assert not orders_by_id broker.commit_work() orders_by_id = list( broker.db_tool.session.query(Orders).filter( Orders.order_uuid == order_id_limit)) assert len(orders_by_id) == 1 portfolio = broker.get_portfolio_object() assert portfolio broker.delete_portfolio(portfolio_name, portfolio_user) portfolio = broker.get_portfolio_object() assert portfolio is None db_tool_new = Db(self.config['sql'], TEST_LOGGER) db_tool_new.connect() broker.db_tool = db_tool_new portfolio = broker.get_portfolio_object() assert portfolio db_tool_new.session.close()
""" import unittest import logging from autotrader.base.trader_base import TraderBase from autotrader.broker.degiro.degiro_client import DegiroClient from autotrader.datasource.database.stock_database import StockDataBase from autotrader.datasource.database.stock_schema import BARS_NUMPY, BARS_PANDAS, Stock from autotrader.tool.database.create_and_fill_database import CreateAndFillDataBase from autotrader.tool.database.update_database_stocks import UpdateDataBaseStocks TEST_LOGGER = logging.getLogger() TEST_LOGGER.setLevel(logging.WARNING) CONFIG = TraderBase.get_config() CONFIG['sql']['database'] = 'testdatabase' DB = StockDataBase(CONFIG['sql'], TEST_LOGGER) class TestDataBase(unittest.TestCase): """ Test suite for database installer """ @staticmethod def test_1_install_db(): """ test install db :return: """ arguments = {} db_tool = StockDataBase(CONFIG["sql"], TEST_LOGGER)