def test_logger(): """ tests the logger creation :return: nothing """ logger = TraderBase.setup_logger("auto_trader") assert logger is not None logger = TraderBase.setup_logger(None) assert logger is not None
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 __do_limit(self, stock, order_data: dict, portfolio): if "size" not in order_data or "price" not in order_data or order_data['price'] == -1\ or "buysell" not in order_data: raise RuntimeError("Order data is not correct") price, price_complete, commission = self.__calculate_price(order_data['price'], order_data, order_data["buysell"] == 1) if order_data["buysell"] == 0 and portfolio.cash + price_complete < 0: raise RuntimeError("Insufficient Funds: Price {} is higher than cash {}".format( price_complete, portfolio.cash)) time_zone = TraderBase.get_timezone() now = datetime.datetime.now(time_zone) my_order = Orders( status=Status.confirmed, order_type=OrderType.limit, order_uuid=str(uuid.uuid4()), size=order_data["size"]*-1 if order_data["buysell"] == 1 else order_data["size"], price=price, price_complete=price_complete, commission=commission, stock_id=stock.id, signal_id=order_data.get('signal_id'), expire_date=datetime.datetime.now(time_zone) + datetime.timedelta(hours=self.expire_in_hours), is_sell=True if order_data["buysell"] == 1 else False, date=now ) return my_order
def __do_market(self, stock, order_data: dict, portfolio): if "size" not in order_data or "buysell" not in order_data: raise RuntimeError("Order data is not correct") # get live data prices = self.get_last_price(stock) # get last stock price by database if not prices: raise RuntimeError("Couldnt collect price") last_price = prices price, price_complete, commission = self.__calculate_price(last_price, order_data, order_data["buysell"] == 1) if order_data["buysell"] != 1 and (portfolio.cash + price_complete) < 0: raise RuntimeError("Insufficient Funds: Price {} is higher" " than cash {}.".format(price, portfolio.cash)) time_zone = TraderBase.get_timezone() now = datetime.datetime.now(time_zone) my_order = Orders( status=Status.completed, order_type=OrderType.market, order_uuid=str(uuid.uuid4()), size=order_data["size"]*-1 if order_data["buysell"] == 1 else order_data["size"], price=price, price_complete=price_complete, commission=commission, stock_id=stock.id, signal_id=order_data.get('signal_id'), is_sell=True if order_data["buysell"] == 1 else False, date=now ) return my_order
def __handle_open_orders(self): """ Get all open orders and check if desired price matches with historical stock prices :return: """ portfolio = self.get_portfolio_object() # only take complete orders orders = [order for order in portfolio.orders if order.status == Status.confirmed] time_zone = TraderBase.get_timezone() now = datetime.datetime.now(time_zone) for order in orders: price = self.db_tool.session.query(Series)\ .filter(order.stock_id == Series.stock_id) \ .filter(Series.date.between(order.date, now)) \ .filter(order.price >= Series.pricehigh)\ .order_by(Series.date.asc()).first() if price: order.status = Status.completed order.date = price.date self.connect_related_order(order) else: diff = now - order.date.replace(tzinfo=time_zone) hours = diff.total_seconds() / 60 if hours >= self.expire_in_hours: self.logger.info("Order is expired because limit {} for {} " "was not reached during the day". format(order.price, order.stock_id)) order.status = Status.expired portfolio.cash -= order.price_complete
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 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_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 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 build_indicator(self, arguments): stock_id = arguments["stock_id"] stock_index = arguments["stock_index"] stock_symbol = arguments["stock_symbol"] stock_bars = arguments["stock_bars"] self.logger.info("Analyse %s:%s" % (stock_index, stock_symbol)) return_code = 0 indicators = [] for indicator in ind.INDICATORS: if indicator.SHORT_NAME in self.signal_to_builds or 'ALL' in self.signal_to_builds: indicators.append(indicator(indicator.ARGUMENTS, self.logger)) for indicator in indicators: self.logger.info("Execute filter %s" % indicator.name) if indicator.SHORT_NAME in ["SO", "SOM2", "SOM3"]: optimizer_values = itertools.product( range(3, int(self.look_back / 2)), range(3, int(self.look_back / 2)), range(3, int(self.look_back / 2))) else: optimizer_values = itertools.combinations( range(5, int(self.look_back / 2)), indicator.param_count) profit_max, param_max, status = Optimizer( self.logger).run_optimizer(optimizer_values, indicator, stock_bars) self.logger.info( "Signal %s(%s) earns %s for %s and has status code %s" % (indicator.name, param_max, profit_max, stock_symbol, status)) if not param_max: self.logger.warning("no results for %s", indicator) continue # save to bulk data storage db_signal = Signal( profit_in_percent=float(profit_max), name=indicator.name, status=status, info=self.look_back, date=datetime.datetime.now(TraderBase.get_timezone()), refresh_date=datetime.datetime.now(TraderBase.get_timezone())) self.__add_signal_to_bulk(stock_id, db_signal) self.__add_parameter_to_bulk(db_signal, param_max) self.__add_plot_to_bulk(indicator, param_max, db_signal) return return_code
def test_config(): """ tests the config creation by environment variable and root project dir :return: nothing """ # test with config.ini in project root main_config = TraderBase.get_config() assert main_config is not None # test with environment variable file_config = open('config_test_unittest.ini', 'wt', encoding='utf-8') test_value = "[test]\ntest_value = 123456" file_config.write(test_value) file_config.close() old_config_path = os.environ["CONFIG_FILE"] os.environ["CONFIG_FILE"] = "config_test_unittest.ini" main_config = TraderBase.get_config() assert main_config['test']['test_value'] == '123456' os.environ.pop("CONFIG_FILE") os.environ["CONFIG_FILE"] = old_config_path
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'
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 __is_exchange_open(exchange: str): """ :param exchange: :return: """ time_zone = TraderBase.get_timezone() date_now = datetime.datetime.now(time_zone) if exchange == 'XETR': if date_now.isoweekday() in range(1, 6) and date_now.hour in range(9, 17): return True elif exchange == 'XFRA': if date_now.isoweekday() in range(1, 6) and date_now.hour in range(8, 20): return True return False
def get_last_price(self, stock_object, time_zone=None): """ Get last price of stock symbol :param stock_object: symbol of stock like ADS :param time_zone tz :return: last price or None """ time_zone = TraderBase.get_timezone() if self.client: return self.client.get_last_price(stock_object) # get last stock price by database price = self.db_tool.session.query(Series)\ .join(Stock)\ .filter(Stock.id == stock_object.id)\ .filter(Series.date <= datetime.datetime.now(time_zone))\ .order_by(-Series.date).first() if not price: return None return price.priceclose
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 __build(self, my_filter, stock): bars = stock.get_bars(my_filter.look_back_date(), datetime.datetime.now(), output_type=BARS_NUMPY) if my_filter.look_back_date() is None or bars.size: my_filter.set_bars(bars) my_filter.set_stock(stock) strategy_status = my_filter.analyse() strategy_value = my_filter.get_calculation() tz = TraderBase.get_timezone() stock.filter.append( Filter(value=strategy_value, name=my_filter.name, status=strategy_status, date=datetime.datetime.now(tz))) if strategy_status == BaseFilter.BUY: self.logger.debug("Buy %s", stock.symbol) elif strategy_status == BaseFilter.HOLD: self.logger.debug("Hold %s", stock.symbol) else: self.logger.debug("Do not buy Stock %s ", stock.symbol)
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() cls.portfolio_name = "TestDemoSimpleMarket" arguments_broker = { "portfolio_name": cls.portfolio_name, "portfolio_user": "******", "database_data": True, "db_tool": cls.db_tool, "cash": 20000000 } cls.broker = DemoBroker(cls.config, arguments_broker, cls.test_logger) assert 'PYCHARM' in os.environ or cls.config['sql'][ 'address'] == 'mysqltest'
def __get_signals_to_update(db_tool, signal_max_age): time_zone = TraderBase.get_timezone() # at first we need all signals in a date range of 6 days all_signals_in_date_range = db_tool.session.query(Signal).\ filter(Signal.date.between(datetime.now(time_zone) - timedelta(days=signal_max_age), datetime.now(time_zone))) # older signals connected with a order must also be refreshed sub_orders = db_tool.session.query( Orders.signal_id )\ .filter(Orders.is_sell == 0)\ .filter(Orders.orders_id.is_(None))\ .group_by(Orders.signal_id).\ subquery('t3') signals_with_order = db_tool.session.query(Signal).join( sub_orders, Signal.id == sub_orders.c.signal_id) update_new_signals = all_signals_in_date_range.union_all( signals_with_order) my_result = update_new_signals.all() return my_result
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 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
See the License for the specific language governing permissions and limitations under the License. """ 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: """
from fnmatch import filter from freezegun import freeze_time from int_date import to_date from sqlalchemy.orm import query from autotrader.base.trader_base import TraderBase from autotrader.broker.degiro.degiro_client import DegiroClient from autotrader.broker.degiro.degiro_config_helper import DegiroConfigHelper from autotrader.datasource.database.stock_database import StockDataBase from autotrader.datasource.database.stock_schema import OrderType, Orders, \ Status, Stock, Signal TEST_LOGGER = logging.getLogger() TEST_LOGGER.setLevel(logging.WARNING) tz = TraderBase.get_timezone() class TestDegiro(unittest.TestCase): """ Degiro test suite """ @classmethod 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 get_plot(self): """ Generate plot data for highcharts :return: json series string """ tz = TraderBase.get_timezone() series_list = [{ "name": "Price", "data": [[int(self.times[idx].replace(tzinfo=tz).timestamp()) * 1000, x] for idx, x in enumerate(self.open)], "id": 'dataseries' }, { "type": 'flags', "data": [], "onSeries": 'dataseries', "shape": 'circlepin', "width": 20 }] # we have to generate the siganl again signal = self.generate_signals() for idx, val in enumerate(signal): timestamp = int(self.times[idx + self.signal_shift].replace( tzinfo=tz).timestamp()) * 1000 if val == 1: series_list[1]["data"].append({ "x": timestamp, "title": 'B', "text": 'Buy', "color": "#155724", "fillColor": "#c3e6cb", "style": { "fontFamily": 'monospace', "color": "#155724" } }) elif val == -1: series_list[1]["data"].append({ "x": timestamp, "title": 'S', "text": 'Sell', "color": "#721c24", "fillColor": "#f8d7da", "style": { "fontFamily": 'monospace', "color": "#721c24" } }) indicators = self.get_indicators() for idx, val in enumerate(indicators): data_shift = len(series_list[0]["data"]) - val.size indicator_values = [None for _ in range(data_shift)] for idx2, val2 in enumerate(val): timestamp = int(self.times[idx2 + data_shift].replace( tzinfo=tz).timestamp()) * 1000 indicator_values.append([timestamp, val2]) series_list.append({ "yAxis": 1, "name": "Graph" + str(idx), "data": indicator_values }) my_json_str = json.dumps(series_list) my_pack_str = base64.b64encode( zlib.compress(my_json_str.encode("utf-8"), 9)) size_str = sys.getsizeof(my_json_str) size_pack = sys.getsizeof(my_pack_str) debug_msg = "Size before {} and size after {}. {}".format( size_str, size_pack, 1 - size_pack / size_str) self.logger.debug(debug_msg) return my_pack_str
def setUpClass(cls): cls.config = TraderBase.get_config() cls.db_tool = Db(cls.config['sql'], TEST_LOGGER) cls.db_tool.connect()
def test_8_back_testing(self): """ test the back testing tool for strategies :return: """ tz = TraderBase.get_timezone() logging.basicConfig(level=logging.DEBUG) date_now = datetime.datetime.now(tz=tz) date_fake_starts = date_now - datetime.timedelta(days=150) config = TraderBase.get_config() my_parameter = [Parameter(value=5), Parameter(value=6)] signal_list = self.create_fake_signals( -2, date_fake_starts, [1], 'UltimateOscillatorCrossEmaSignal', my_parameter) assert signal_list assert len(signal_list) == 1 my_plot = Plot() my_plot.add_plot_to_data({}) signal_list[0].plot.append(my_plot) self.db_tool.commit() arguments_broker = { "portfolio_name": "", "portfolio_user": "******", "database_data": True, "db_tool": self.db_tool, "cash": 2000 } arguments = { "strategies": ["SimpleMarket40"], "signals": ["Uoe"], "stocks": [1], "look_back": 400, "db_tool": self.db_tool, "broker": DemoBroker(config, arguments_broker, self.test_logger), "from_date": date_fake_starts, "to_date": date_now } BackTestingStrategy(config, arguments, self.test_logger).build() arguments["broker"].commit_work() json_data = self.db_tool.session.query(Plot).\ filter(Plot.signal_id == signal_list[0].id).first() assert json_data.data json_data = json_data.get_plot() assert json_data != '{}' # todo analyse more functions with default datetime.now() arguments # todo solve monday not tlrade issue tz = TraderBase.get_timezone() sell_date = [ datetime.datetime.fromtimestamp(int(data["x"]) / 1000, tz=tz) for data in json_data[1]["data"] if data["text"] == "Sell" ] buy_date = [ datetime.datetime.fromtimestamp(int(date["x"]) / 1000, tz=tz) for date in json_data[1]["data"] if date["text"] == "Buy" ] assert sell_date and buy_date # now we check if strategy really bought stocky by signal sell_date = [ item for item in sell_date if date_now >= item >= date_fake_starts ] buy_date = [ item for item in buy_date if date_now >= item >= date_fake_starts ] assert sell_date and buy_date # remove first sell signal if younger than first buy signal if sell_date[0] < buy_date[0]: sell_date.pop(0) my_orders_buy = [ x[0] for x in self.db_tool.session.query(Orders.date).filter( Orders.is_sell == 0).order_by(Orders.date).all() ] my_orders_sell = [ x[0] for x in self.db_tool.session.query(Orders.date).filter( Orders.is_sell == 1).order_by(Orders.date).all() ] assert len(my_orders_buy) == len(buy_date) assert len(my_orders_sell) == len(sell_date) def check_date(date_list1, date_list2): """ returns false if date in list is unequal :param date_list1: :param date_list2: :return: """ for idx, my_date1 in enumerate(date_list1): if my_date1.replace( tzinfo=tz).date() != date_list2[idx].date(): return False return True assert check_date(my_orders_buy, buy_date), \ " The given date lists are not equal %s %s" % (my_orders_buy, buy_date) assert check_date(my_orders_sell, sell_date), \ " The given date lists are not equal %s %s" % (my_orders_sell, sell_date)