From c3222186e08da81f4948603d7457e2f4337dbc74 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Thu, 25 Apr 2024 22:43:53 +0200 Subject: [PATCH 01/31] Add backtest date range --- .../backtest_experiment/configuration.json | 128 -- .../configuration_copy.json | 146 ++ examples/backtest_experiment/run_backtest.py | 32 +- investing_algorithm_framework/__init__.py | 5 +- .../app/algorithm.py | 54 +- investing_algorithm_framework/app/app.py | 24 +- .../dependency_container.py | 4 +- .../domain/__init__.py | 9 +- .../domain/models/__init__.py | 8 +- .../domain/models/backtesting/__init__.py | 2 + .../models/backtesting/backtest_date_range.py | 26 + .../models/backtesting/backtest_position.py | 14 + .../models/backtesting/backtest_report.py | 52 +- .../domain/models/order/__init__.py | 3 +- .../domain/models/order/order.py | 95 +- .../domain/models/order/order_fee.py | 49 - .../domain/models/trade/trade.py | 15 + .../domain/utils/__init__.py | 2 +- .../domain/utils/backtesting.py | 26 +- .../domain/utils/csv.py | 1 + .../infrastructure/__init__.py | 6 +- .../infrastructure/models/__init__.py | 3 +- .../market_data_sources/us_treasury_yield.py | 41 + .../infrastructure/models/order/__init__.py | 3 +- .../infrastructure/models/order/order.py | 29 +- .../infrastructure/models/order/order_fee.py | 21 - .../infrastructure/repositories/__init__.py | 2 - .../repositories/order_fee_repository.py | 15 - .../backtest_report_writer_service.py | 47 +- .../services/backtesting/backtest_service.py | 5 +- .../order_service/order_backtest_service.py | 2 - .../services/order_service/order_service.py | 28 - tests/app/backtesting/test_backtest_report.py | 61 +- tests/app/backtesting/test_run_backtest.py | 56 +- tests/app/backtesting/test_run_backtests.py | 16 +- tests/domain/models/test_backtest_report.py | 50 + .../test_backtest_reports_evaluation.py | 11 +- tests/domain/test_load_backtest_reports.py | 26 + .../report_10-50-1002024-03-21 23:32:51.csv | 2 - .../report_10-50-1002024-03-22 00:16:29.csv | 2 - ...-20:00:00_created_at_2024-04-25:13:52.json | 1226 ++++++++++++++ ...-10:00:00_created_at_2024-04-25:13:54.json | 1294 +++++++++++++++ ...-01:00:00_created_at_2024-04-25:13:53.json | 1281 +++++++++++++++ .../report_10-75-1502024-03-21 23:33:42.csv | 2 - .../report_10-75-1502024-03-22 00:17:23.csv | 2 - .../report_11-50-1002024-03-21 23:33:09.csv | 2 - .../report_11-50-1002024-03-22 00:16:48.csv | 2 - .../report_11-75-1502024-03-21 23:33:58.csv | 2 - .../report_11-75-1502024-03-22 00:17:44.csv | 2 - .../report_20-75-1502024-03-21 23:34:15.csv | 2 - .../report_20-75-1502024-03-22 00:18:06.csv | 2 - .../report_20-75-2002024-03-22 00:20:26.csv | 2 - .../report_21-75-1502024-03-22 00:18:27.csv | 2 - .../report_21-75-2002024-03-22 00:20:54.csv | 2 - .../report_22-75-1502024-03-22 00:18:47.csv | 2 - .../report_22-75-2002024-03-22 00:21:15.csv | 2 - .../report_23-75-1502024-03-22 00:19:10.csv | 2 - .../report_23-75-2002024-03-22 00:21:38.csv | 2 - .../report_24-75-1502024-03-21 23:34:30.csv | 2 - .../report_24-75-1502024-03-22 00:19:34.csv | 2 - .../report_24-75-2002024-03-22 00:22:00.csv | 2 - .../report_25-75-1502024-03-21 23:34:46.csv | 2 - .../report_25-75-1502024-03-22 00:19:55.csv | 2 - .../report_25-75-1502024-03-22 00:22:22.csv | 2 - .../report_9-50-1002024-03-21 23:32:32.csv | 2 - .../report_9-50-1002024-03-22 00:16:10.csv | 2 - ...-20:00:00_created_at_2024-04-25:13:52.json | 1226 ++++++++++++++ ...-10:00:00_created_at_2024-04-25:13:53.json | 1459 +++++++++++++++++ ...-01:00:00_created_at_2024-04-25:13:52.json | 1336 +++++++++++++++ .../report_9-75-1502024-03-21 23:33:25.csv | 2 - .../report_9-75-1502024-03-22 00:17:06.csv | 2 - tests/services/test_order_backtest_service.py | 1 - 72 files changed, 8488 insertions(+), 506 deletions(-) create mode 100644 examples/backtest_experiment/configuration_copy.json create mode 100644 investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py delete mode 100644 investing_algorithm_framework/domain/models/order/order_fee.py create mode 100644 investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py delete mode 100644 investing_algorithm_framework/infrastructure/models/order/order_fee.py delete mode 100644 investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py create mode 100644 tests/domain/models/test_backtest_report.py create mode 100644 tests/domain/test_load_backtest_reports.py delete mode 100644 tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-21 23:32:51.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-22 00:16:29.csv create mode 100644 tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json create mode 100644 tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:54.json create mode 100644 tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:53.json delete mode 100644 tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-21 23:33:42.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-22 00:17:23.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-21 23:33:09.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-22 00:16:48.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-21 23:33:58.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-22 00:17:44.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-21 23:34:15.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-22 00:18:06.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_20-75-2002024-03-22 00:20:26.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_21-75-1502024-03-22 00:18:27.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_21-75-2002024-03-22 00:20:54.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_22-75-1502024-03-22 00:18:47.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_22-75-2002024-03-22 00:21:15.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_23-75-1502024-03-22 00:19:10.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_23-75-2002024-03-22 00:21:38.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-21 23:34:30.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-22 00:19:34.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_24-75-2002024-03-22 00:22:00.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-21 23:34:46.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:19:55.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:22:22.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-21 23:32:32.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-22 00:16:10.csv create mode 100644 tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json create mode 100644 tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:53.json create mode 100644 tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:52.json delete mode 100644 tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-21 23:33:25.csv delete mode 100644 tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-22 00:17:06.csv diff --git a/examples/backtest_experiment/configuration.json b/examples/backtest_experiment/configuration.json index 9694ba6a..5223a2c5 100644 --- a/examples/backtest_experiment/configuration.json +++ b/examples/backtest_experiment/configuration.json @@ -14,133 +14,5 @@ "slow":50, "trend":100, "stop_loss_percentage":7 - }, - { - "name":"11-50-100", - "description":"11-50-100", - "fast":11, - "slow":50, - "trend":100, - "stop_loss_percentage":7 - }, - { - "name":"9-75-150", - "description":"9-75-150", - "fast":9, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"10-75-150", - "description":"10-75-150", - "fast":10, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"11-75-150", - "description":"11-75-150", - "fast":11, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"20-75-150", - "description":"20-75-150", - "fast":20, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"21-75-150", - "description":"21-75-150", - "fast":21, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"22-75-150", - "description":"22-75-150", - "fast":22, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"23-75-150", - "description":"23-75-150", - "fast":23, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"24-75-150", - "description":"24-75-150", - "fast":24, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"25-75-150", - "description":"25-75-150", - "fast":25, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"20-75-200", - "description":"20-75-200", - "fast":20, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"21-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"22-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"23-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"24-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"25-75-150", - "description":"25-75-200", - "fast":25, - "slow":75, - "trend":200, - "stop_loss_percentage":7 } ] \ No newline at end of file diff --git a/examples/backtest_experiment/configuration_copy.json b/examples/backtest_experiment/configuration_copy.json new file mode 100644 index 00000000..9694ba6a --- /dev/null +++ b/examples/backtest_experiment/configuration_copy.json @@ -0,0 +1,146 @@ +[ + { + "name":"9-50-100", + "description":"9-50-100", + "fast":9, + "slow":50, + "trend":100, + "stop_loss_percentage":7 + }, + { + "name":"10-50-100", + "description":"10-50-100", + "fast":10, + "slow":50, + "trend":100, + "stop_loss_percentage":7 + }, + { + "name":"11-50-100", + "description":"11-50-100", + "fast":11, + "slow":50, + "trend":100, + "stop_loss_percentage":7 + }, + { + "name":"9-75-150", + "description":"9-75-150", + "fast":9, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"10-75-150", + "description":"10-75-150", + "fast":10, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"11-75-150", + "description":"11-75-150", + "fast":11, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"20-75-150", + "description":"20-75-150", + "fast":20, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"21-75-150", + "description":"21-75-150", + "fast":21, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"22-75-150", + "description":"22-75-150", + "fast":22, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"23-75-150", + "description":"23-75-150", + "fast":23, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"24-75-150", + "description":"24-75-150", + "fast":24, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"25-75-150", + "description":"25-75-150", + "fast":25, + "slow":75, + "trend":150, + "stop_loss_percentage":7 + }, + { + "name":"20-75-200", + "description":"20-75-200", + "fast":20, + "slow":75, + "trend":200, + "stop_loss_percentage":7 + }, + { + "name":"21-75-200", + "description":"24-75-200", + "fast":24, + "slow":75, + "trend":200, + "stop_loss_percentage":7 + }, + { + "name":"22-75-200", + "description":"24-75-200", + "fast":24, + "slow":75, + "trend":200, + "stop_loss_percentage":7 + }, + { + "name":"23-75-200", + "description":"24-75-200", + "fast":24, + "slow":75, + "trend":200, + "stop_loss_percentage":7 + }, + { + "name":"24-75-200", + "description":"24-75-200", + "fast":24, + "slow":75, + "trend":200, + "stop_loss_percentage":7 + }, + { + "name":"25-75-150", + "description":"25-75-200", + "fast":25, + "slow":75, + "trend":200, + "stop_loss_percentage":7 + } +] \ No newline at end of file diff --git a/examples/backtest_experiment/run_backtest.py b/examples/backtest_experiment/run_backtest.py index 57e2b3b1..d613965a 100644 --- a/examples/backtest_experiment/run_backtest.py +++ b/examples/backtest_experiment/run_backtest.py @@ -1,14 +1,29 @@ import json -from datetime import datetime, timedelta +from datetime import datetime from algorithms import create_algorithm from app import app from investing_algorithm_framework import PortfolioConfiguration, \ - pretty_print_backtest_reports_evaluation, BacktestReportsEvaluation + pretty_print_backtest_reports_evaluation, BacktestReportsEvaluation, \ + BacktestDateRange if __name__ == "__main__": - end_date = datetime(2023, 12, 2) - start_date = end_date - timedelta(days=100) + down_turn_date_range = BacktestDateRange( + start_date=datetime(2021, 12, 21), + end_date=datetime(2022, 6, 20), + name="down_turn" + ) + up_turn_date_range = BacktestDateRange( + start_date=datetime(2022, 12, 20), + end_date=datetime(2023, 6, 1), + name="up_turn" + ) + sideways_date_range = BacktestDateRange( + start_date=datetime(2022, 6, 10), + end_date=datetime(2023, 1, 10), + name="sideways" + ) + json = json.load(open("configuration.json")) algorithms = [] @@ -27,12 +42,9 @@ reports = app.run_backtests( algorithms=algorithms, date_ranges=[ - (datetime(2023, 7, 2), - datetime(2023, 7, 2) + timedelta(days=200)), - (datetime(2022, 7, 2), - datetime(2022, 7, 2) + timedelta(days=200)), - (datetime(2024, 1, 1), - datetime(2024, 1, 1) + timedelta(days=100)), + down_turn_date_range, + up_turn_date_range, + sideways_date_range ], pending_order_check_interval="2h", ) diff --git a/investing_algorithm_framework/__init__.py b/investing_algorithm_framework/__init__.py index c981ec20..1a31511b 100644 --- a/investing_algorithm_framework/__init__.py +++ b/investing_algorithm_framework/__init__.py @@ -9,7 +9,8 @@ Trade, OHLCVMarketDataSource, OrderBookMarketDataSource, SYMBOLS, \ TickerMarketDataSource, MarketService, BacktestReportsEvaluation, \ pretty_print_backtest_reports_evaluation, load_backtest_reports, \ - RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT + RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT,\ + load_backtest_report, BacktestDateRange from investing_algorithm_framework.infrastructure import \ CCXTOrderBookMarketDataSource, CCXTOHLCVMarketDataSource, \ CCXTTickerMarketDataSource, CSVOHLCVMarketDataSource, \ @@ -61,4 +62,6 @@ "APP_MODE", "AppMode", "DATETIME_FORMAT", + "load_backtest_report", + "BacktestDateRange", ] diff --git a/investing_algorithm_framework/app/algorithm.py b/investing_algorithm_framework/app/algorithm.py index 7bfc20ff..76c01d85 100644 --- a/investing_algorithm_framework/app/algorithm.py +++ b/investing_algorithm_framework/app/algorithm.py @@ -1,8 +1,8 @@ import inspect import logging -from typing import List +from typing import List, Dict -from investing_algorithm_framework.domain import OrderStatus, OrderFee, \ +from investing_algorithm_framework.domain import OrderStatus, \ Position, Order, Portfolio, OrderType, OrderSide, \ BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME, MarketService, TimeUnit, \ OperationalException, random_string, RoundingService @@ -16,8 +16,22 @@ class Algorithm: - - def __init__(self, name=None, description=None): + """ + Class to represent an algorithm. An algorithm is a collection of + strategies that are executed in a specific order. The algorithm + class is responsible for managing the strategies and executing + them in the correct order. + + :param name: The name of the algorithm + :param description: The description of the algorithm + :param context: The context of the algorithm, for backtest references + """ + def __init__( + self, + name: str = None, + description: str = None, + context: Dict[str, str] = None + ): self._name = name if name is None: @@ -28,6 +42,21 @@ def __init__(self, name=None, description=None): if description is not None: self._description = description + self._context = context + + if self.context is None: + self._context = {} + + # Check if the context is a dictionary with only string, + # float or int values + for key, value in self.context.items(): + if not isinstance(key, str) or \ + not isinstance(value, (str, float, int)): + raise OperationalException( + "The context of the algorithm must be a dictionary with " + "only string, float or int values." + ) + self._strategies = [] self._tasks = [] self.portfolio_service: PortfolioService @@ -108,6 +137,20 @@ def config(self): """ return self.configuration_service.config + @property + def description(self): + """ + Function to get the description of the algorithm + """ + return self._description + + @property + def context(self): + """ + Function to get the context of the algorithm + """ + return self._context + @property def running(self) -> bool: """ @@ -362,9 +405,6 @@ def get_orders( } ) - def get_order_fee(self, order_id) -> OrderFee: - return self.order_service.get_order_fee(order_id) - def get_positions( self, market=None, diff --git a/investing_algorithm_framework/app/app.py b/investing_algorithm_framework/app/app.py index 2b2bf66d..42a2262a 100644 --- a/investing_algorithm_framework/app/app.py +++ b/investing_algorithm_framework/app/app.py @@ -20,7 +20,7 @@ SQLALCHEMY_DATABASE_URI, OperationalException, BACKTESTING_FLAG, \ BACKTESTING_START_DATE, BACKTESTING_END_DATE, BacktestReport, \ BACKTESTING_PENDING_ORDER_CHECK_INTERVAL, APP_MODE, MarketCredential, \ - AppMode + AppMode, BacktestDateRange from investing_algorithm_framework.infrastructure import setup_sqlalchemy, \ create_all_tables from investing_algorithm_framework.services import OrderBacktestService, \ @@ -319,7 +319,6 @@ def _initialize_app_for_backtest( self.container.order_service.override( OrderBacktestService( order_repository=self.container.order_repository(), - order_fee_repository=self.container.order_fee_repository(), position_repository=self.container.position_repository(), portfolio_repository=self.container.portfolio_repository(), portfolio_configuration_service=self.container @@ -729,7 +728,7 @@ def run_backtest( "backtest_reports" ) - backtest_report_writer_service.write_report_to_csv( + backtest_report_writer_service.write_report_to_json( report=report, output_directory=output_directory ) @@ -740,7 +739,7 @@ def run_backtests( algorithms, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None, - date_ranges: Optional[Tuple[datetime, datetime]] = None, + date_ranges: Optional[List[BacktestDateRange]] = None, pending_order_check_interval=None, output_directory=None ) -> List[BacktestReport]: @@ -754,7 +753,7 @@ def run_backtests( :param end_date: The end date of the backtest :param pending_order_check_interval: The interval at which to check :param date_ranges: The date ranges to run the backtests for (list of - tuples of start and end dates) + BacktestDateRange instances representing a start and end date) pending orders :param output_directory: The directory to write the backtest report to :return: List of BacktestReport intances @@ -767,7 +766,9 @@ def run_backtests( if end_date is None: end_date = datetime.utcnow() - date_ranges = [(start_date, end_date)] + date_ranges = [ + BacktestDateRange(start_date=start_date, end_date=end_date) + ] else: if date_ranges is None: raise OperationalException("No date ranges specified") @@ -776,7 +777,9 @@ def run_backtests( .get_market_data_sources() for date_range in date_ranges: - start_date, end_date = date_range + date_range: BacktestDateRange = date_range + start_date = date_range.start_date + end_date = date_range.end_date self._initialize_app_for_backtest( backtest_start_date=start_date, backtest_end_date=end_date, @@ -804,6 +807,11 @@ def run_backtests( start_date=start_date, end_date=end_date ) + + # Add date range name to report if present + if date_range.name is not None: + report.date_range_name = date_range.name + backtest_report_writer_service = self.container \ .backtest_report_writer_service() @@ -813,7 +821,7 @@ def run_backtests( "backtest_reports" ) - backtest_report_writer_service.write_report_to_csv( + backtest_report_writer_service.write_report_to_json( report=report, output_directory=output_directory ) reports.append(report) diff --git a/investing_algorithm_framework/dependency_container.py b/investing_algorithm_framework/dependency_container.py index 2f06d908..a46cbc72 100644 --- a/investing_algorithm_framework/dependency_container.py +++ b/investing_algorithm_framework/dependency_container.py @@ -3,7 +3,7 @@ from investing_algorithm_framework.app.algorithm import Algorithm from investing_algorithm_framework.infrastructure import SQLOrderRepository, \ SQLPositionRepository, SQLPortfolioRepository, \ - SQLOrderFeeRepository, SQLPortfolioSnapshotRepository, \ + SQLPortfolioSnapshotRepository, \ SQLPositionSnapshotRepository, PerformanceService, CCXTMarketService from investing_algorithm_framework.services import OrderService, \ PositionService, PortfolioService, StrategyOrchestratorService, \ @@ -33,7 +33,6 @@ class DependencyContainer(containers.DeclarativeContainer): MarketCredentialService ) order_repository = providers.Factory(SQLOrderRepository) - order_fee_repository = providers.Factory(SQLOrderFeeRepository) position_repository = providers.Factory(SQLPositionRepository) portfolio_repository = providers.Factory(SQLPortfolioRepository) position_snapshot_repository = providers.Factory( @@ -70,7 +69,6 @@ class DependencyContainer(containers.DeclarativeContainer): OrderService, configuration_service=configuration_service, order_repository=order_repository, - order_fee_repository=order_fee_repository, portfolio_repository=portfolio_repository, position_repository=position_repository, market_service=market_service, diff --git a/investing_algorithm_framework/domain/__init__.py b/investing_algorithm_framework/domain/__init__.py index e3761e14..14995d53 100644 --- a/investing_algorithm_framework/domain/__init__.py +++ b/investing_algorithm_framework/domain/__init__.py @@ -15,9 +15,9 @@ from .models import OrderStatus, OrderSide, OrderType, TimeInterval, \ TimeUnit, TimeFrame, TradingTimeFrame, TradingDataType, \ PortfolioConfiguration, Portfolio, Position, Order, TradeStatus, \ - OrderFee, BacktestReport, PortfolioSnapshot, StrategyProfile, \ + BacktestReport, PortfolioSnapshot, StrategyProfile, \ BacktestPosition, Trade, MarketCredential, PositionSnapshot, \ - BacktestReportsEvaluation, AppMode + BacktestReportsEvaluation, AppMode, BacktestDateRange from .services import TickerMarketDataSource, OrderBookMarketDataSource, \ OHLCVMarketDataSource, BacktestMarketDataSource, MarketDataSource, \ MarketService, MarketCredentialService, AbstractPortfolioSyncService, \ @@ -26,7 +26,7 @@ from .stateless_actions import StatelessActions from .strategy import Strategy from .utils import random_string, append_dict_as_row_to_csv, \ - add_column_headers_to_csv, get_total_amount_of_rows, \ + add_column_headers_to_csv, get_total_amount_of_rows, load_backtest_report,\ csv_to_list, StoppableThread, pretty_print_backtest_reports_evaluation, \ pretty_print_backtest, load_csv_into_dict, load_backtest_reports @@ -70,7 +70,6 @@ "Strategy", "DATETIME_FORMAT", "StatelessActions", - "OrderFee", "parse_decimal_to_string", "parse_string_to_decimal", "BacktestReport", @@ -112,4 +111,6 @@ "APP_MODE", "AppMode", "RoundingService", + "BacktestDateRange", + "load_backtest_report", ] diff --git a/investing_algorithm_framework/domain/models/__init__.py b/investing_algorithm_framework/domain/models/__init__.py index da2e30ae..219dcb96 100644 --- a/investing_algorithm_framework/domain/models/__init__.py +++ b/investing_algorithm_framework/domain/models/__init__.py @@ -1,8 +1,8 @@ from .app_mode import AppMode from .backtesting import BacktestReport, BacktestPosition, \ - BacktestReportsEvaluation + BacktestReportsEvaluation, BacktestDateRange from .market import MarketCredential -from .order import OrderStatus, OrderSide, OrderType, Order, OrderFee +from .order import OrderStatus, OrderSide, OrderType, Order from .portfolio import PortfolioConfiguration, Portfolio, PortfolioSnapshot from .position import Position, PositionSnapshot from .strategy_profile import StrategyProfile @@ -26,7 +26,6 @@ "PortfolioConfiguration", "Position", "Portfolio", - "OrderFee", "BacktestReport", "PositionSnapshot", "PortfolioSnapshot", @@ -36,5 +35,6 @@ "MarketCredential", "TradeStatus", "BacktestReportsEvaluation", - "AppMode" + "AppMode", + "BacktestDateRange" ] diff --git a/investing_algorithm_framework/domain/models/backtesting/__init__.py b/investing_algorithm_framework/domain/models/backtesting/__init__.py index af505842..eeb6f266 100644 --- a/investing_algorithm_framework/domain/models/backtesting/__init__.py +++ b/investing_algorithm_framework/domain/models/backtesting/__init__.py @@ -1,9 +1,11 @@ from .backtest_position import BacktestPosition from .backtest_report import BacktestReport from .backtest_reports_evaluation import BacktestReportsEvaluation +from .backtest_date_range import BacktestDateRange __all__ = [ "BacktestReport", "BacktestPosition", "BacktestReportsEvaluation", + "BacktestDateRange" ] diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py b/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py new file mode 100644 index 00000000..35eee8a9 --- /dev/null +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py @@ -0,0 +1,26 @@ +from datetime import datetime + + +class BacktestDateRange: + """ + Represents a date range for a backtest + """ + def __init__(self, start_date, end_date = None, name = None): + self._start_date = start_date + self._end_date = end_date + self._name = name + + if end_date is None: + self._end_date = datetime.now() + + @property + def start_date(self): + return self._start_date + + @property + def end_date(self): + return self._end_date + + @property + def name(self): + return self._name diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_position.py b/investing_algorithm_framework/domain/models/backtesting/backtest_position.py index a66015fd..976866a5 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_position.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_position.py @@ -104,3 +104,17 @@ def get_percentage_of_portfolio(self): return 0.0 return self.value / self._total_value_portfolio * 100 + + def to_dict(self): + return { + "symbol": self.symbol, + "amount": self.amount, + "cost": self.cost, + "price": self.price, + "value": self.value, + "growth": self.growth, + "growth_rate": self.growth_rate, + "amount_pending_buy": self.amount_pending_buy, + "amount_pending_sell": self.amount_pending_sell, + "percentage_of_portfolio": self.percentage_of_portfolio + } \ No newline at end of file diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py index 0907c2dd..d62876a0 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py @@ -2,6 +2,7 @@ from investing_algorithm_framework.domain.models.base_model import BaseModel from investing_algorithm_framework.domain.models.time_unit import TimeUnit +from investing_algorithm_framework.domain.constants import DATETIME_FORMAT class BacktestReport(BaseModel): @@ -18,7 +19,6 @@ def __init__( backtest_data_index_date=None, backtest_start_date=None, backtest_end_date=None, - backtest_index_date=None, trading_time_frame=None, trading_time_frame_start_date=None, symbols=None, @@ -42,14 +42,15 @@ def __init__( average_trade_duration=0, average_trade_size=0.0, trades=None, - created_at: datetime = None + orders=None, + created_at: datetime = None, + context=None, ): self._name = name self._strategy_identifiers = strategy_identifiers self._backtest_start_date_data = backtest_start_date_data self._backtest_start_date = backtest_start_date self._backtest_end_date = backtest_end_date - self._backtest_index_date = backtest_index_date self._number_of_runs = number_of_runs self._trading_time_frame = trading_time_frame self._trading_time_frame_start_date = trading_time_frame_start_date @@ -72,13 +73,15 @@ def __init__( self._total_net_gain = total_net_gain self._backtest_data_index_date = backtest_data_index_date self._total_value = total_value - self.positions = positions + self._positions = positions + self._orders = orders self._average_trade_duration = average_trade_duration self._average_trade_size = average_trade_size self._trades = trades self._created_at: datetime = created_at self._interval = interval self._time_unit = time_unit + self._context = context @property def name(self): @@ -116,10 +119,6 @@ def backtest_start_date(self): def backtest_end_date(self): return self._backtest_end_date - @property - def backtest_index_date(self): - return self._backtest_index_date - @property def trading_time_frame(self): return self._trading_time_frame @@ -160,10 +159,6 @@ def backtest_start_date_data(self, value): def backtest_end_date(self, value): self._backtest_end_date = value - @backtest_index_date.setter - def backtest_index_date(self, value): - self._backtest_index_date = value - @number_of_runs.setter def number_of_runs(self, value): self._number_of_runs = value @@ -316,6 +311,14 @@ def positions(self): def positions(self, value): self._positions = value + @property + def orders(self): + return self._orders + + @orders.setter + def orders(self, value): + self._orders = value + @property def average_trade_duration(self): return self._average_trade_duration @@ -348,6 +351,14 @@ def interval(self): def interval(self, value): self._interval = value + @property + def context(self): + return self._context + + @context.setter + def context(self, value): + self._context = value + @property def time_unit(self): return self._time_unit @@ -372,7 +383,6 @@ def __repr__(self): name=self.name, start_date=self.backtest_start_date, end_date=self.backtest_end_date, - backtest_index_date=self.backtest_index_date, start_date_data=self.backtest_start_date_data, ) @@ -383,9 +393,12 @@ def to_dict(self): """ return { "name": self.name, + "context": self.context if self.context is not None else {}, "strategy_identifiers": self.strategy_identifiers, - "backtest_start_date": self.backtest_start_date, - "backtest_end_date": self.backtest_end_date, + "backtest_start_date": self.backtest_start_date + .strftime(DATETIME_FORMAT), + "backtest_end_date": self.backtest_end_date + .strftime(DATETIME_FORMAT), "number_of_runs": self.number_of_runs, "symbols": self.symbols, "market": self.market, @@ -404,10 +417,16 @@ def to_dict(self): "trading_symbol": self.trading_symbol, "total_net_gain_percentage": self.total_net_gain_percentage, "total_net_gain": self.total_net_gain, - "backtest_data_index_date": self.backtest_data_index_date, "total_value": self.total_value, "average_trade_duration": self.average_trade_duration, "average_trade_size": self.average_trade_size, + "positions": [position.to_dict() for position in self.positions], + "trades": [trade.to_dict() for trade in self.trades], + "orders": [ + order.to_dict(datetime_format=DATETIME_FORMAT) + for order in self.orders + ], + "created_at": self.created_at.strftime(DATETIME_FORMAT), } @staticmethod @@ -438,7 +457,6 @@ def from_dict(data): trading_symbol=data["trading_symbol"], total_net_gain_percentage=float(data["total_net_gain_percentage"]), total_net_gain=float(data["total_net_gain"]), - backtest_data_index_date=data["backtest_data_index_date"], total_value=float(data["total_value"]), average_trade_duration=data["average_trade_duration"], average_trade_size=float(data["average_trade_size"]), diff --git a/investing_algorithm_framework/domain/models/order/__init__.py b/investing_algorithm_framework/domain/models/order/__init__.py index 83d24b4d..a6ba94b7 100644 --- a/investing_algorithm_framework/domain/models/order/__init__.py +++ b/investing_algorithm_framework/domain/models/order/__init__.py @@ -1,7 +1,6 @@ from .order import Order -from .order_fee import OrderFee from .order_side import OrderSide from .order_status import OrderStatus from .order_type import OrderType -__all__ = ["OrderType", "OrderStatus", "OrderSide", "Order", "OrderFee"] +__all__ = ["OrderType", "OrderStatus", "OrderSide", "Order"] diff --git a/investing_algorithm_framework/domain/models/order/order.py b/investing_algorithm_framework/domain/models/order/order.py index d44d4df9..e51d99eb 100644 --- a/investing_algorithm_framework/domain/models/order/order.py +++ b/investing_algorithm_framework/domain/models/order/order.py @@ -5,20 +5,20 @@ from investing_algorithm_framework.domain.exceptions import \ OperationalException from investing_algorithm_framework.domain.models.base_model import BaseModel +from investing_algorithm_framework.domain.models.order.order_side import \ + OrderSide from investing_algorithm_framework.domain.models.order.order_status import \ OrderStatus from investing_algorithm_framework.domain.models.order.order_type import \ OrderType -from investing_algorithm_framework.domain.models.order.order_side import \ - OrderSide -from investing_algorithm_framework.domain.models.order.order_fee import \ - OrderFee logger = logging.getLogger("investing_algorithm_framework") class Order(BaseModel): - + """ + Order model class to represent an order of the trading bot + """ def __init__( self, order_type, @@ -40,10 +40,9 @@ def __init__( cost=None, fee=None, position_id=None, - stop_loss=None, - stop_loss_percentage=None, - trailing_stop_loss=None, - trailing_stop_loss_percentage=None, + order_fee=None, + order_fee_currency=None, + order_fee_rate=None ): if target_symbol is None: raise OperationalException("Target symbol is not specified") @@ -80,11 +79,10 @@ def __init__( self.remaining = remaining self.cost = cost self.fee = fee - self.stop_loss = stop_loss - self.stop_loss_percentage = stop_loss_percentage - self.trailing_stop_loss = trailing_stop_loss - self.trailing_stop_loss_percentage = trailing_stop_loss_percentage self._available_amount = self.filled + self.order_fee = order_fee + self.order_fee_currency = order_fee_currency + self.order_fee_rate = order_fee_rate def get_id(self): return self.id @@ -107,6 +105,24 @@ def get_price(self): def set_price(self, price): self.price = price + def get_order_fee_currency(self): + return self.order_fee_currency + + def set_order_fee_currency(self, order_fee_currency): + self.order_fee_currency = order_fee_currency + + def get_order_fee_rate(self): + return self.order_fee_rate + + def set_order_fee_rate(self, order_fee_rate): + self.order_fee_rate = order_fee_rate + + def get_order_fee(self): + return self.order_fee + + def set_order_fee(self, order_fee): + self.order_fee = order_fee + def get_order_size(self): return self.order_side @@ -232,7 +248,20 @@ def set_available_amount(self, available_amount): def available_amount(self, available_amount): self.set_available_amount(available_amount) - def to_dict(self): + def to_dict(self, datetime_format=None): + + if datetime_format is not None: + created_at = self.created_at.strftime(datetime_format) \ + if self.created_at else None + updated_at = self.updated_at.strftime(datetime_format) \ + if self.updated_at else None + trade_closed_at = self.trade_closed_at.strftime(datetime_format) \ + if self.trade_closed_at else None + else: + created_at = self.created_at + updated_at = self.updated_at + trade_closed_at = self.trade_closed_at + return { "external_id": self.external_id, "target_symbol": self.target_symbol, @@ -243,18 +272,16 @@ def to_dict(self): "price": self.price, "amount": self.amount, "net_gain": self.net_gain, - "trade_closed_at": self.trade_closed_at, + "trade_closed_at": trade_closed_at, "trade_closed_price": self.trade_closed_price, - "created_at": self.created_at, - "updated_at": self.updated_at, + "created_at": created_at, + "updated_at": updated_at, "filled": self.filled, "remaining": self.remaining, "cost": self.cost, - "fee": self.fee.to_dict() if self.fee is not None else None, - "stop_loss": self.stop_loss, - "stop_loss_percentage": self.stop_loss_percentage, - "trailing_stop_loss": self.trailing_stop_loss, - "trailing_stop_loss_percentage": self.trailing_stop_loss_percentage + "order_fee_currency": self.order_fee_currency, + "order_fee_rate": self.order_fee_rate, + "order_fee": self.order_fee, } @staticmethod @@ -290,14 +317,32 @@ def from_dict(data: dict): cost=data.get("cost", None), fee=data.get("fee", None), created_at=created_at, - updated_at=updated_at + updated_at=updated_at, + order_fee=data.get("order_fee", None), + order_fee_currency=data.get("order_fee_currency", None), + order_fee_rate=data.get("order_fee_rate", None), ) @staticmethod def from_ccxt_order(ccxt_order): + """ + Create an Order object from a ccxt order object + :param ccxt_order: ccxt order object + :return: Order object + """ status = OrderStatus.from_value(ccxt_order["status"]) target_symbol = ccxt_order.get("symbol").split("/")[0] trading_symbol = ccxt_order.get("symbol").split("/")[1] + ccxt_fee = ccxt_order.get("fee", None) + order_fee = None + order_fee_currency = None + order_fee_rate = None + + if ccxt_fee is not None: + order_fee = ccxt_fee.get("cost", None) + order_fee_currency = ccxt_fee.get("currency", None) + order_fee_rate = ccxt_fee.get("rate", None) + return Order( external_id=ccxt_order.get("id", None), target_symbol=target_symbol, @@ -310,7 +355,9 @@ def from_ccxt_order(ccxt_order): filled=ccxt_order.get("filled", None), remaining=ccxt_order.get("remaining", None), cost=ccxt_order.get("cost", None), - fee=OrderFee.from_ccxt_fee(ccxt_order.get("fee", None)), + order_fee=order_fee, + order_fee_currency=order_fee_currency, + order_fee_rate=order_fee_rate, created_at=parse(ccxt_order.get("datetime", None)) ) diff --git a/investing_algorithm_framework/domain/models/order/order_fee.py b/investing_algorithm_framework/domain/models/order/order_fee.py deleted file mode 100644 index f053dac9..00000000 --- a/investing_algorithm_framework/domain/models/order/order_fee.py +++ /dev/null @@ -1,49 +0,0 @@ -from investing_algorithm_framework.domain.models.base_model import BaseModel - - -class OrderFee(BaseModel): - def __init__(self, currency, cost, rate): - self.currency = currency - self.cost = cost - self.rate = rate - - def get_currency(self): - return self.currency - - def set_currency(self, currency): - self.currency = currency - - def get_cost(self): - return self.cost - - def set_cost(self, cost): - self.cost = cost - - def get_rate(self): - return self.rate - - @staticmethod - def from_ccxt_fee(ccxt_fee): - - if ccxt_fee is None: - return None - - return OrderFee( - currency=ccxt_fee.get('currency'), - cost=ccxt_fee.get('cost'), - rate=ccxt_fee.get('rate'), - ) - - def to_dict(self): - return { - "currency": self.currency, - "cost": self.cost, - "rate": self.rate - } - - def __repr__(self): - return self.repr( - currency=self.get_currency(), - cost=self.get_cost(), - rate=self.get_rate(), - ) diff --git a/investing_algorithm_framework/domain/models/trade/trade.py b/investing_algorithm_framework/domain/models/trade/trade.py index 1dbc6f5d..b0a9b97a 100644 --- a/investing_algorithm_framework/domain/models/trade/trade.py +++ b/investing_algorithm_framework/domain/models/trade/trade.py @@ -230,6 +230,21 @@ def is_manual_stop_loss_trigger( stop_loss_price = highest_price * (1 - stop_loss_percentage / 100) return current_price <= stop_loss_price + def to_dict(self): + return { + "target_symbol": self.target_symbol, + "trading_symbol": self.trading_symbol, + "status": self.status, + "amount": self.amount, + "open_price": self.open_price, + "current_price": self.current_price, + "closed_price": self.closed_price, + "opened_at": self.opened_at.strftime(DATETIME_FORMAT) if self.opened_at else None, + "closed_at": self.closed_at.strftime(DATETIME_FORMAT) if self.closed_at else None, + "change": self.percentage_change, + "absolute_change": self.absolute_change, + } + def __repr__(self): return self.repr( target_symbol=self.target_symbol, diff --git a/investing_algorithm_framework/domain/utils/__init__.py b/investing_algorithm_framework/domain/utils/__init__.py index 80634a37..00fb400b 100644 --- a/investing_algorithm_framework/domain/utils/__init__.py +++ b/investing_algorithm_framework/domain/utils/__init__.py @@ -1,4 +1,4 @@ -from .backtesting import pretty_print_backtest, \ +from .backtesting import pretty_print_backtest, load_backtest_report, \ pretty_print_backtest_reports_evaluation, load_backtest_reports from .csv import get_total_amount_of_rows, append_dict_as_row_to_csv, \ add_column_headers_to_csv, csv_to_list, load_csv_into_dict diff --git a/investing_algorithm_framework/domain/utils/backtesting.py b/investing_algorithm_framework/domain/utils/backtesting.py index 890c1b86..aaae32f7 100644 --- a/investing_algorithm_framework/domain/utils/backtesting.py +++ b/investing_algorithm_framework/domain/utils/backtesting.py @@ -1,4 +1,5 @@ import os +import json from datetime import datetime from typing import List, Tuple @@ -462,6 +463,26 @@ def pretty_print_backtest( print(tabulate(trades_table, headers="keys", tablefmt="rounded_grid")) +def load_backtest_report(file_path: str) -> BacktestReport: + """ + Load a backtest report from a file. + + param file_path: The file path + :return: The backtest report + """ + + if not os.path.isfile(file_path): + raise OperationalException("File does not exist") + + if not file_path.endswith(".json"): + raise OperationalException("File is not a json file") + + with open(file_path, 'r') as json_file: + data = json.load(json_file) + + return BacktestReport.from_dict(data) + + def load_backtest_reports(folder_path: str) -> List[BacktestReport]: """ Load backtest reports from a folder. @@ -480,11 +501,10 @@ def load_backtest_reports(folder_path: str) -> List[BacktestReport]: raise OperationalException(f"Folder {folder_path} is empty") for file in list_of_files: - if not file.endswith(".csv"): + if not file.endswith(".json"): continue file_path = os.path.join(folder_path, file) - data = load_csv_into_dict(file_path) - report = BacktestReport.from_dict(data) + report = load_backtest_report(file_path) backtest_reports.append(report) return backtest_reports diff --git a/investing_algorithm_framework/domain/utils/csv.py b/investing_algorithm_framework/domain/utils/csv.py index a31c49bf..0f3a8c8b 100644 --- a/investing_algorithm_framework/domain/utils/csv.py +++ b/investing_algorithm_framework/domain/utils/csv.py @@ -1,4 +1,5 @@ import csv +import json import shutil import tempfile from typing import Dict, List diff --git a/investing_algorithm_framework/infrastructure/__init__.py b/investing_algorithm_framework/infrastructure/__init__.py index 6c0ffd1f..ed22bae3 100644 --- a/investing_algorithm_framework/infrastructure/__init__.py +++ b/investing_algorithm_framework/infrastructure/__init__.py @@ -1,12 +1,12 @@ from .database import setup_sqlalchemy, Session, \ create_all_tables -from .models import SQLPortfolio, SQLOrder, SQLPosition, SQLOrderFee, \ +from .models import SQLPortfolio, SQLOrder, SQLPosition, \ SQLPortfolioSnapshot, SQLPositionSnapshot, \ CCXTOHLCVBacktestMarketDataSource, CCXTOrderBookMarketDataSource, \ CCXTTickerMarketDataSource, CCXTOHLCVMarketDataSource, \ CSVOHLCVMarketDataSource, CSVTickerMarketDataSource from .repositories import SQLOrderRepository, SQLPositionRepository, \ - SQLPortfolioRepository, SQLOrderFeeRepository, \ + SQLPortfolioRepository, \ SQLPortfolioSnapshotRepository, SQLPositionSnapshotRepository from .services import PerformanceService, CCXTMarketService @@ -15,14 +15,12 @@ "SQLPositionRepository", "SQLPortfolioRepository", "SQLOrderRepository", - "SQLOrderFeeRepository", "SQLPortfolioSnapshotRepository", "SQLPositionSnapshotRepository", "setup_sqlalchemy", "Session", "SQLPortfolio", "SQLOrder", - "SQLOrderFee", "SQLPosition", "PerformanceService", "SQLPortfolioSnapshot", diff --git a/investing_algorithm_framework/infrastructure/models/__init__.py b/investing_algorithm_framework/infrastructure/models/__init__.py index 90847121..a11c53f8 100644 --- a/investing_algorithm_framework/infrastructure/models/__init__.py +++ b/investing_algorithm_framework/infrastructure/models/__init__.py @@ -2,7 +2,7 @@ CCXTTickerMarketDataSource, CCXTOHLCVMarketDataSource, \ CCXTOHLCVBacktestMarketDataSource, CSVOHLCVMarketDataSource, \ CSVTickerMarketDataSource -from .order import SQLOrder, SQLOrderFee +from .order import SQLOrder from .portfolio import SQLPortfolio, SQLPortfolioSnapshot from .position import SQLPosition, SQLPositionSnapshot @@ -10,7 +10,6 @@ "SQLOrder", "SQLPosition", "SQLPortfolio", - "SQLOrderFee", "SQLPositionSnapshot", "SQLPortfolioSnapshot", "CCXTOHLCVBacktestMarketDataSource", diff --git a/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py b/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py new file mode 100644 index 00000000..fe99e83d --- /dev/null +++ b/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py @@ -0,0 +1,41 @@ +import requests +from investing_algorithm_framework.domain import MarketDataSource, \ + BacktestMarketDataSource + + +class UsTreasuryYieldDataSource(MarketDataSource): + """ + UsTreasuryYield is a subclass of MarketDataSource. + It is used to get the US Treasury Yield data. + """ + URL = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/" \ + "v2/accounting/od/avg_interest_rates?" \ + "filter=record_date:gte:2024-01-01" + + def get_data( + self, + time_stamp=None, + from_time_stamp=None, + to_time_stamp=None, + **kwargs + ): + response = requests.get(self.URL) + + if response.status_code == 200: + # Extract risk-free rate from API response (e.g., 10-year Treasury yield) + treasury_yield_data = response.json() + entries = treasury_yield_data["data"] + for entry in entries: + print(entry) + print(entries[-1]) + print(entries[-1]["avg_interest_rate_amt"]) + # print(treasury_yield_data) + # ten_year_yield = treasury_yield_data["data"][0]["value"] + # risk_free_rate = ten_year_yield / 100 # Convert percentage to decimal + # print("10-Year Treasury Yield (Risk-Free Rate):", risk_free_rate) + else: + print("Failed to retrieve Treasury yield data. Status code:", + response.status_code) + + def to_backtest_market_data_source(self) -> BacktestMarketDataSource: + pass \ No newline at end of file diff --git a/investing_algorithm_framework/infrastructure/models/order/__init__.py b/investing_algorithm_framework/infrastructure/models/order/__init__.py index 9d9afda6..b328b27b 100644 --- a/investing_algorithm_framework/infrastructure/models/order/__init__.py +++ b/investing_algorithm_framework/infrastructure/models/order/__init__.py @@ -1,4 +1,3 @@ from .order import SQLOrder -from .order_fee import SQLOrderFee -__all__ = ["SQLOrder", "SQLOrderFee"] +__all__ = ["SQLOrder"] diff --git a/investing_algorithm_framework/infrastructure/models/order/order.py b/investing_algorithm_framework/infrastructure/models/order/order.py index a117ef5d..7ee3fc13 100644 --- a/investing_algorithm_framework/infrastructure/models/order/order.py +++ b/investing_algorithm_framework/infrastructure/models/order/order.py @@ -5,7 +5,7 @@ from sqlalchemy.orm import relationship from investing_algorithm_framework.domain import OrderType, \ - OrderSide, Order, OrderStatus, OrderFee + OrderSide, Order, OrderStatus from investing_algorithm_framework.infrastructure.database import SQLBaseModel from investing_algorithm_framework.infrastructure.models.model_extension \ import SQLAlchemyModelExtension @@ -35,12 +35,9 @@ class SQLOrder(Order, SQLBaseModel, SQLAlchemyModelExtension): trade_closed_price = Column(Float, default=None) trade_closed_amount = Column(Float, default=None) net_gain = Column(Float, default=0) - fee = relationship( - "SQLOrderFee", - uselist=False, - back_populates="order", - cascade="all, delete" - ) + order_fee = Column(Float, default=None) + order_fee_currency = Column(String) + order_fee_rate = Column(Float, default=None) _available_amount = None def update(self, data): @@ -101,9 +98,23 @@ def from_order(order): @staticmethod def from_ccxt_order(ccxt_order): + """ + Create an Order object from a CCXT order object + :param ccxt_order: CCXT order object + """ status = OrderStatus.from_value(ccxt_order["status"]) target_symbol = ccxt_order.get("symbol").split("/")[0] trading_symbol = ccxt_order.get("symbol").split("/")[1] + ccxt_fee = ccxt_order.get("fee", None) + order_fee = None + order_fee_rate = None + order_fee_currency = None + + if ccxt_fee is not None: + order_fee = ccxt_fee.get("cost", None) + order_fee_rate = ccxt_fee.get("rate", None) + order_fee_currency = ccxt_fee.get("currency", None) + return Order( external_id=ccxt_order.get("id", None), target_symbol=target_symbol, @@ -116,7 +127,9 @@ def from_ccxt_order(ccxt_order): filled=ccxt_order.get("filled", None), remaining=ccxt_order.get("remaining", None), cost=ccxt_order.get("cost", None), - fee=OrderFee.from_ccxt_fee(ccxt_order.get("fee", None)), + order_fee=order_fee, + order_fee_rate=order_fee_rate, + order_fee_currency=order_fee_currency, created_at=ccxt_order.get("datetime", None), ) diff --git a/investing_algorithm_framework/infrastructure/models/order/order_fee.py b/investing_algorithm_framework/infrastructure/models/order/order_fee.py deleted file mode 100644 index 0bca5cf1..00000000 --- a/investing_algorithm_framework/infrastructure/models/order/order_fee.py +++ /dev/null @@ -1,21 +0,0 @@ -from sqlalchemy import Column, Integer, String, ForeignKey, Float -from sqlalchemy.orm import relationship - -from investing_algorithm_framework.domain import OrderFee -from investing_algorithm_framework.infrastructure.database import SQLBaseModel -from investing_algorithm_framework.infrastructure.models.model_extension \ - import SQLAlchemyModelExtension - - -class SQLOrderFee(OrderFee, SQLBaseModel, SQLAlchemyModelExtension): - __tablename__ = "order_fees" - id = Column(Integer, primary_key=True, unique=True) - currency = Column(String) - cost = Column(Float) - rate = Column(Float) - order_id = Column(Integer, ForeignKey('orders.id')) - order = relationship("SQLOrder", back_populates="fee") - - def __init__(self, currency, cost, rate, order_id): - super().__init__(currency, cost, rate) - self.order_id = order_id diff --git a/investing_algorithm_framework/infrastructure/repositories/__init__.py b/investing_algorithm_framework/infrastructure/repositories/__init__.py index ed50b29b..eee27cc1 100644 --- a/investing_algorithm_framework/infrastructure/repositories/__init__.py +++ b/investing_algorithm_framework/infrastructure/repositories/__init__.py @@ -1,4 +1,3 @@ -from .order_fee_repository import SQLOrderFeeRepository from .order_repository import SQLOrderRepository from .portfolio_repository import SQLPortfolioRepository from .portfolio_snapshot_repository import SQLPortfolioSnapshotRepository @@ -6,7 +5,6 @@ from .position_snapshot_repository import SQLPositionSnapshotRepository __all__ = [ - "SQLOrderFeeRepository", "SQLOrderRepository", "SQLPositionRepository", "SQLPositionSnapshotRepository", diff --git a/investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py b/investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py deleted file mode 100644 index 0bb2becc..00000000 --- a/investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +++ /dev/null @@ -1,15 +0,0 @@ -from investing_algorithm_framework.infrastructure.models import SQLOrderFee -from .repository import Repository - - -class SQLOrderFeeRepository(Repository): - base_class = SQLOrderFee - DEFAULT_NOT_FOUND_MESSAGE = "Order fee not found" - - def _apply_query_params(self, db, query, query_params): - order_query_param = self.get_query_param("order", query_params) - - if order_query_param: - query = query.filter_by(order_id=order_query_param) - - return query diff --git a/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py b/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py index 376438b2..5bdeeae2 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py @@ -1,5 +1,6 @@ import csv import os +import json from investing_algorithm_framework.domain import BacktestReport, \ DATETIME_FORMAT_BACKTESTING @@ -19,6 +20,24 @@ def write_report_to_csv( Write a backtest report to a CSV file. """ + if not os.path.exists(output_directory): + os.makedirs(output_directory) + + csv_file_path = self.create_report_name( + report, output_directory, extension=".csv" + ) + report_dict = report.to_dict() + + with open(csv_file_path, 'w', newline='') as csv_file: + writer = csv.DictWriter(csv_file, fieldnames=report_dict.keys()) + writer.writeheader() + writer.writerow(report_dict) + + return csv_file_path + + def write_report_to_json( + self, report: BacktestReport, output_directory: str + ): if not os.path.exists(output_directory): os.makedirs(output_directory) backtest_start_date = report.backtest_start_date\ @@ -26,17 +45,31 @@ def write_report_to_csv( backtest_end_date = report.backtest_end_date\ .strftime(DATETIME_FORMAT_BACKTESTING) created_at = report.created_at.strftime(DATETIME_FORMAT_BACKTESTING) - csv_file_path = os.path.join( + json_file_path = os.path.join( output_directory, f"report_{report.name}_backtest_start_date_" f"{backtest_start_date}_backtest_end_date_" - f"{backtest_end_date}_created_at_{created_at}.csv" + f"{backtest_end_date}_created_at_{created_at}.json" ) report_dict = report.to_dict() + # Convert dictionary to JSON + json_data = json.dumps(report_dict, indent=4) - with open(csv_file_path, 'w', newline='') as csv_file: - writer = csv.DictWriter(csv_file, fieldnames=report_dict.keys()) - writer.writeheader() - writer.writerow(report_dict) + # Write JSON data to a .json file + with open(json_file_path, "w") as json_file: + json_file.write(json_data) - return csv_file_path + @staticmethod + def create_report_name(report, output_directory, extension=".json"): + backtest_start_date = report.backtest_start_date \ + .strftime(DATETIME_FORMAT_BACKTESTING) + backtest_end_date = report.backtest_end_date \ + .strftime(DATETIME_FORMAT_BACKTESTING) + created_at = report.created_at.strftime(DATETIME_FORMAT_BACKTESTING) + file_path = os.path.join( + output_directory, + f"report_{report.name}_backtest_start_date_" + f"{backtest_start_date}_backtest_end_date_" + f"{backtest_end_date}_created_at_{created_at}{extension}" + ) + return file_path diff --git a/investing_algorithm_framework/services/backtesting/backtest_service.py b/investing_algorithm_framework/services/backtesting/backtest_service.py index 648974ce..5bf8142b 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_service.py @@ -238,7 +238,6 @@ def create_backtest_report( backtest_profile = BacktestReport( name=algorithm.name, strategy_identifiers=ids, - backtest_index_date=start_date, backtest_start_date=start_date, backtest_end_date=end_date, initial_unallocated=initial_unallocated, @@ -277,6 +276,9 @@ def create_backtest_report( positions = self._position_repository.get_all({ "portfolio": portfolio.id }) + orders = self._order_service.get_all({ + "portfolio": portfolio.id + }) tickers = {} for position in positions: @@ -360,6 +362,7 @@ def create_backtest_report( backtest_positions.append(backtest_position) backtest_profile.positions = backtest_positions backtest_profile.trades = algorithm.get_trades() + backtest_profile.orders = orders return backtest_profile def set_backtest_market_data_sources(self, market_data_sources): diff --git a/investing_algorithm_framework/services/order_service/order_backtest_service.py b/investing_algorithm_framework/services/order_service/order_backtest_service.py index 02f08517..854bc662 100644 --- a/investing_algorithm_framework/services/order_service/order_backtest_service.py +++ b/investing_algorithm_framework/services/order_service/order_backtest_service.py @@ -17,7 +17,6 @@ class OrderBacktestService(OrderService): def __init__( self, order_repository, - order_fee_repository, position_repository, portfolio_repository, portfolio_configuration_service, @@ -27,7 +26,6 @@ def __init__( ): super(OrderService, self).__init__(order_repository) self.order_repository = order_repository - self.order_fee_repository = order_fee_repository self.position_repository = position_repository self.portfolio_repository = portfolio_repository self.portfolio_configuration_service = portfolio_configuration_service diff --git a/investing_algorithm_framework/services/order_service/order_service.py b/investing_algorithm_framework/services/order_service/order_service.py index 4819fb6c..c2ab390f 100644 --- a/investing_algorithm_framework/services/order_service/order_service.py +++ b/investing_algorithm_framework/services/order_service/order_service.py @@ -18,7 +18,6 @@ def __init__( self, configuration_service, order_repository, - order_fee_repository, market_service: MarketService, position_repository, portfolio_repository, @@ -29,7 +28,6 @@ def __init__( super(OrderService, self).__init__(order_repository) self.configuration_service = configuration_service self.order_repository = order_repository - self.order_fee_repository = order_fee_repository self.market_service: MarketService = market_service self.position_repository = position_repository self.portfolio_repository = portfolio_repository @@ -44,11 +42,6 @@ def create(self, data, execute=True, validate=True, sync=True) -> Order: if validate: self.validate_order(data, portfolio) - order_fee = None - - if "fee" in data: - order_fee = data.pop("fee") - del data["portfolio_id"] symbol = data["target_symbol"] @@ -62,10 +55,6 @@ def create(self, data, execute=True, validate=True, sync=True) -> Order: order = self.order_repository.create(data) order_id = order.id - if order_fee: - order_fee["order_id"] = order_id - self.order_fee_repository.create(order_fee) - if sync: if OrderSide.BUY.equals(order.get_order_side()): self._sync_portfolio_with_created_buy_order(order) @@ -92,20 +81,6 @@ def update(self, object_id, data): portfolio = self.portfolio_repository.get( trading_symbol_position.portfolio_id ) - - if "fee" in data: - order_fee_data = data.pop("fee") - - if order_fee_data is not None: - if self.order_fee_repository.exists({"order_id": object_id}): - order_fee = self.order_fee_repository\ - .find({"order_id": object_id}) - self.order_fee_repository\ - .update(order_fee.id, order_fee_data) - else: - order_fee_data["order_id"] = object_id - self.order_fee_repository.create(order_fee_data) - new_order = self.order_repository.update(object_id, data) filled_difference = new_order.get_filled() \ - previous_order.get_filled() @@ -148,9 +123,6 @@ def update(self, object_id, data): self.create_snapshot(portfolio.id, created_at=created_at) return new_order - def get_order_fee(self, order_id): - return self.order_fee_repository.find({"order": order_id}) - def execute_order(self, order_id, portfolio): order = self.get(order_id) diff --git a/tests/app/backtesting/test_backtest_report.py b/tests/app/backtesting/test_backtest_report.py index 430e386d..c5422183 100644 --- a/tests/app/backtesting/test_backtest_report.py +++ b/tests/app/backtesting/test_backtest_report.py @@ -5,6 +5,7 @@ from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \ TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm from investing_algorithm_framework.domain import DATETIME_FORMAT_BACKTESTING +from investing_algorithm_framework.services import BacktestReportWriterService class TestStrategy(TradingStrategy): @@ -59,17 +60,13 @@ def test_report_csv_creation(self): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue( + os.path.isfile(os.path.join(self.resource_dir, file_path)) + ) def test_report_csv_creation_without_strategy_identifier(self): """ @@ -95,18 +92,13 @@ def test_report_csv_creation_without_strategy_identifier(self): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) - # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue( + os.path.isfile(os.path.join(self.resource_dir, file_path)) + ) def test_report_csv_creation_with_multiple_strategies(self): """ @@ -139,19 +131,15 @@ def run_strategy(algorithm, market_data): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue( + os.path.isfile(os.path.join(self.resource_dir, file_path)) + ) - def test_report_csv_creation_with_multiple_strategies_with_id(self): + def test_report_json_creation_with_multiple_strategies_with_id(self): """ Test if the backtest report is created as a CSV file when there are multiple strategies with identifiers @@ -180,15 +168,10 @@ def run_strategy(algorithm, market_data): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) - # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue( + os.path.isfile(os.path.join(self.resource_dir, file_path)) + ) diff --git a/tests/app/backtesting/test_run_backtest.py b/tests/app/backtesting/test_run_backtest.py index 7040d806..230fb826 100644 --- a/tests/app/backtesting/test_run_backtest.py +++ b/tests/app/backtesting/test_run_backtest.py @@ -4,7 +4,7 @@ from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \ TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm -from investing_algorithm_framework.domain import DATETIME_FORMAT_BACKTESTING +from investing_algorithm_framework.services import BacktestReportWriterService class TestStrategy(TradingStrategy): @@ -59,17 +59,13 @@ def test_report_csv_creation(self): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue( + os.path.isfile(os.path.join(self.resource_dir, file_path)) + ) def test_report_csv_creation_without_strategy_identifier(self): """ @@ -95,18 +91,11 @@ def test_report_csv_creation_without_strategy_identifier(self): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue(os.path.isfile(file_path)) def test_report_csv_creation_with_multiple_strategies(self): """ @@ -139,18 +128,11 @@ def run_strategy(algorithm, market_data): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) - + self.assertTrue(os.path.isfile(file_path)) def test_report_csv_creation_with_multiple_strategies_with_id(self): """ Test if the backtest report is created as a CSV file @@ -180,16 +162,8 @@ def run_strategy(algorithm, market_data): start_date=datetime.utcnow() - timedelta(days=1), end_date=datetime.utcnow(), ) - - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) - # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue(os.path.isfile(file_path)) \ No newline at end of file diff --git a/tests/app/backtesting/test_run_backtests.py b/tests/app/backtesting/test_run_backtests.py index cb6c9dde..d42b3a6c 100644 --- a/tests/app/backtesting/test_run_backtests.py +++ b/tests/app/backtesting/test_run_backtests.py @@ -4,6 +4,7 @@ from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \ TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm +from investing_algorithm_framework.services import BacktestReportWriterService from investing_algorithm_framework.domain import DATETIME_FORMAT_BACKTESTING @@ -76,16 +77,9 @@ def test_run_backtests(self): end_date=datetime.utcnow(), ) + # Check if the backtest reports exist for report in reports: - csv_file_path = os.path.join( - self.resource_dir, - os.path.join( - "backtest_reports", - f"report_{report.name}_backtest_start_date_" - f"{report.backtest_start_date.strftime(DATETIME_FORMAT_BACKTESTING)}_backtest_end_date_" - f"{report.backtest_end_date.strftime(DATETIME_FORMAT_BACKTESTING)}_created_at_{report.created_at.strftime(DATETIME_FORMAT_BACKTESTING)}.csv" - ) + file_path = BacktestReportWriterService.create_report_name( + report, os.path.join(self.resource_dir, "backtest_reports") ) - - # Check if the backtest report exists - self.assertTrue(os.path.isfile(csv_file_path)) + self.assertTrue(os.path.isfile(file_path)) diff --git a/tests/domain/models/test_backtest_report.py b/tests/domain/models/test_backtest_report.py new file mode 100644 index 00000000..f3353574 --- /dev/null +++ b/tests/domain/models/test_backtest_report.py @@ -0,0 +1,50 @@ +import os +from unittest import TestCase + +from investing_algorithm_framework import load_backtest_report + + +class Test(TestCase): + + def setUp(self) -> None: + self.resource_dir = os.path.abspath( + os.path.join( + os.path.join( + os.path.join( + os.path.join( + os.path.realpath(__file__), + os.pardir + ), + os.pardir + ), + os.pardir + ), + "resources" + ) + ) + + def test_backtest_reports_evaluation(self): + path = os.path.join( + self.resource_dir, + "backtest_reports_for_testing", + "report_9-50-100_backtest_start_date_2021-12-21:00:00_" + "backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json" + ) + report = load_backtest_report(path) + self.assertEqual( + report.name, "9-50-100" + ) + self.assertEqual( + "2021-12-21 00:00:00", report.backtest_start_date + ) + self.assertEqual( + "2022-06-20 00:00:00", report.backtest_end_date + ) + self.assertEqual(10.713880999999981, report.total_net_gain) + self.assertEqual(2.6784702499999753, report.growth_rate) + self.assertEqual(2.6784702499999953, report.total_net_gain_percentage) + self.assertEqual(2.6784702499999753, report.growth_rate) + self.assertEqual(400.0, report.initial_unallocated) + self.assertEqual(42, report.number_of_orders) + self.assertEqual(2173, report.number_of_runs) + self.assertEqual("EUR", report.trading_symbol) diff --git a/tests/domain/models/test_backtest_reports_evaluation.py b/tests/domain/models/test_backtest_reports_evaluation.py index 4b9b15c3..5fade969 100644 --- a/tests/domain/models/test_backtest_reports_evaluation.py +++ b/tests/domain/models/test_backtest_reports_evaluation.py @@ -28,15 +28,12 @@ def test_backtest_reports_evaluation(self): path = os.path.join(self.resource_dir, "backtest_reports_for_testing") reports = load_backtest_reports(path) evaluation = BacktestReportsEvaluation(reports) - self.assertEqual(len(evaluation.backtest_reports), 27) + self.assertEqual(len(evaluation.backtest_reports), 6) first_backtest_report = evaluation.backtest_reports[0] time_frame = ( first_backtest_report.backtest_start_date, first_backtest_report.backtest_end_date ) - self.assertEqual(evaluation.profit_order[time_frame][0].name, "22-75-150") - self.assertEqual(evaluation.profit_order[time_frame][1].name, "23-75-150") - self.assertEqual(evaluation.profit_order[time_frame][2].name, "21-75-150") - self.assertEqual(evaluation.growth_order[time_frame][0].name, "22-75-150") - self.assertEqual(evaluation.growth_order[time_frame][1].name, "23-75-150") - self.assertEqual(evaluation.growth_order[time_frame][2].name, "25-75-150") + self.assertEqual( + "10-50-100", evaluation.profit_order[time_frame][0].name + ) diff --git a/tests/domain/test_load_backtest_reports.py b/tests/domain/test_load_backtest_reports.py new file mode 100644 index 00000000..7cd7d099 --- /dev/null +++ b/tests/domain/test_load_backtest_reports.py @@ -0,0 +1,26 @@ +import os +from unittest import TestCase + +from investing_algorithm_framework import load_backtest_reports + + +class Test(TestCase): + + def setUp(self) -> None: + self.resource_dir = os.path.abspath( + os.path.join( + os.path.join( + os.path.join( + os.path.realpath(__file__), + os.pardir + ), + os.pardir + ), + "resources" + ) + ) + + def test_backtest_reports_evaluation(self): + path = os.path.join(self.resource_dir, "backtest_reports_for_testing") + reports = load_backtest_reports(path) + print(len(reports)) diff --git a/tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-21 23:32:51.csv b/tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-21 23:32:51.csv deleted file mode 100644 index 9ff72016..00000000 --- a/tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-21 23:32:51.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -10-50-100,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,36,3,,22.22222222222222,72.22222222222221,17,2,195.45492869999998,-0.14466215000001625,-0.578648600000065,400.0,EUR,-0.9917445000000065,-3.966978000000026,,399.42135139999993,64.11764705882354,97.80284568235294 diff --git a/tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-22 00:16:29.csv b/tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-22 00:16:29.csv deleted file mode 100644 index 9ff72016..00000000 --- a/tests/resources/backtest_reports_for_testing/report_10-50-1002024-03-22 00:16:29.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -10-50-100,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,36,3,,22.22222222222222,72.22222222222221,17,2,195.45492869999998,-0.14466215000001625,-0.578648600000065,400.0,EUR,-0.9917445000000065,-3.966978000000026,,399.42135139999993,64.11764705882354,97.80284568235294 diff --git a/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json b/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json new file mode 100644 index 00000000..a5a7e3ae --- /dev/null +++ b/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json @@ -0,0 +1,1226 @@ +{ + "name": "10-50-100", + "context": {}, + "strategy_identifiers": [], + "backtest_start_date": "2021-12-21 00:00:00", + "backtest_end_date": "2022-06-20 00:00:00", + "number_of_runs": 2173, + "symbols": null, + "market": null, + "number_of_days": 181, + "number_of_orders": 42, + "number_of_positions": 1, + "market_data_file": null, + "percentage_positive_trades": 47.61904761904761, + "percentage_negative_trades": 52.38095238095239, + "number_of_trades_closed": 21, + "number_of_trades_open": 0, + "total_cost": -1.4210854715202004e-14, + "growth_rate": 3.2093905000000262, + "growth": 12.837562000000105, + "initial_unallocated": 400.0, + "trading_symbol": "EUR", + "total_net_gain_percentage": 3.2093905000000054, + "total_net_gain": 12.837562000000021, + "total_value": 412.8375620000001, + "average_trade_duration": 66.38095238095238, + "average_trade_size": 100.76857009523812, + "positions": [ + { + "symbol": "EUR", + "amount": 412.8375620000001, + "cost": 412.8375620000001, + "price": 1, + "value": 412.8375620000001, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0.0, + "amount_pending_sell": 0.0, + "percentage_of_portfolio": 100.0 + }, + { + "symbol": "BTC", + "amount": 0.0, + "cost": 0.0, + "price": 19235.629999999997, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + }, + { + "symbol": "DOT", + "amount": 0.0, + "cost": 0.0, + "price": 7.045, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + } + ], + "trades": [ + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0036, + "open_price": 28481.28, + "current_price": 19235.629999999997, + "closed_price": 27562.52, + "opened_at": "2022-05-20 04:00:00", + "closed_at": "2022-05-20 20:00:00", + "change": 0, + "absolute_change": -3.307535999999999 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 10.2184, + "open_price": 10.120000000000001, + "current_price": 7.045, + "closed_price": 10.365, + "opened_at": "2022-05-17 18:00:00", + "closed_at": "2022-05-18 02:00:00", + "change": 0, + "absolute_change": 2.5035079999999965 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.9589, + "open_price": 17.495, + "current_price": 7.045, + "closed_price": 16.93, + "opened_at": "2022-04-23 22:00:00", + "closed_at": "2022-04-24 22:00:00", + "change": 0, + "absolute_change": -3.3667785000000094 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 6.1637, + "open_price": 16.93, + "current_price": 7.045, + "closed_price": 17.015, + "opened_at": "2022-04-19 10:00:00", + "closed_at": "2022-04-22 12:00:00", + "change": 0, + "absolute_change": 0.5239145000000036 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0027, + "open_price": 37871.104999999996, + "current_price": 19235.629999999997, + "closed_price": 37527.7, + "opened_at": "2022-04-19 04:00:00", + "closed_at": "2022-04-22 10:00:00", + "change": 0, + "absolute_change": -0.9271935000000013 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0024, + "open_price": 42244.905, + "current_price": 19235.629999999997, + "closed_price": 41831.869999999995, + "opened_at": "2022-04-02 08:00:00", + "closed_at": "2022-04-03 06:00:00", + "change": 0, + "absolute_change": -0.9912840000000074 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.1619, + "open_price": 20.295, + "current_price": 7.045, + "closed_price": 20.17, + "opened_at": "2022-04-02 06:00:00", + "closed_at": "2022-04-06 00:00:00", + "change": 0, + "absolute_change": -0.6452375000000075 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.1968, + "open_price": 20.39, + "current_price": 7.045, + "closed_price": 19.465, + "opened_at": "2022-03-31 06:00:00", + "closed_at": "2022-03-31 18:00:00", + "change": 0, + "absolute_change": -4.807040000000001 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.1598, + "open_price": 20.119999999999997, + "current_price": 7.045, + "closed_price": 20.16, + "opened_at": "2022-03-30 20:00:00", + "closed_at": "2022-03-31 00:00:00", + "change": 0, + "absolute_change": 0.20639200000002234 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.1381, + "open_price": 20.195, + "current_price": 7.045, + "closed_price": 20.235, + "opened_at": "2022-03-30 16:00:00", + "closed_at": "2022-03-30 20:00:00", + "change": 0, + "absolute_change": 0.20552399999999693 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0025, + "open_price": 38909.95, + "current_price": 19235.629999999997, + "closed_price": 42264.625, + "opened_at": "2022-03-22 04:00:00", + "closed_at": "2022-03-31 02:00:00", + "change": 0, + "absolute_change": 8.386687500000008 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.7499, + "open_price": 17.479999999999997, + "current_price": 7.045, + "closed_price": 19.745, + "opened_at": "2022-03-22 02:00:00", + "closed_at": "2022-03-30 16:00:00", + "change": 0, + "absolute_change": 13.023523500000024 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 6.0392, + "open_price": 16.575, + "current_price": 7.045, + "closed_price": 16.845, + "opened_at": "2022-03-16 06:00:00", + "closed_at": "2022-03-20 20:00:00", + "change": 0, + "absolute_change": 1.630583999999999 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0027, + "open_price": 36619.759999999995, + "current_price": 19235.629999999997, + "closed_price": 37504.685, + "opened_at": "2022-02-28 16:00:00", + "closed_at": "2022-03-04 08:00:00", + "change": 0, + "absolute_change": 2.389297499999998 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.0932, + "open_price": 19.27, + "current_price": 7.045, + "closed_price": 18.945, + "opened_at": "2022-02-09 22:00:00", + "closed_at": "2022-02-10 14:00:00", + "change": 0, + "absolute_change": -1.6552899999999937 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.4693, + "open_price": 17.72, + "current_price": 7.045, + "closed_price": 18.619999999999997, + "opened_at": "2022-02-04 22:00:00", + "closed_at": "2022-02-08 20:00:00", + "change": 0, + "absolute_change": 4.922369999999987 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0027, + "open_price": 35526.104999999996, + "current_price": 19235.629999999997, + "closed_price": 38148.075, + "opened_at": "2022-02-04 20:00:00", + "closed_at": "2022-02-11 12:00:00", + "change": 0, + "absolute_change": 7.079319000000012 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0028, + "open_price": 34212.79, + "current_price": 19235.629999999997, + "closed_price": 33083.82, + "opened_at": "2022-02-01 00:00:00", + "closed_at": "2022-02-02 18:00:00", + "change": 0, + "absolute_change": -3.1611159999999927 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.7445, + "open_price": 17.215, + "current_price": 7.045, + "closed_price": 16.39, + "opened_at": "2022-02-01 00:00:00", + "closed_at": "2022-02-03 08:00:00", + "change": 0, + "absolute_change": -4.739212499999994 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0026, + "open_price": 37765.19, + "current_price": 19235.629999999997, + "closed_price": 37330.135, + "opened_at": "2022-01-15 06:00:00", + "closed_at": "2022-01-17 06:00:00", + "change": 0, + "absolute_change": -1.1311429999999945 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0022, + "open_price": 45016.75, + "current_price": 19235.629999999997, + "closed_price": 43515.965, + "opened_at": "2021-12-27 02:00:00", + "closed_at": "2021-12-28 06:00:00", + "change": 0, + "absolute_change": -3.3017269999999996 + } + ], + "orders": [ + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 27562.52, + "amount": 0.0036, + "net_gain": -3.307535999999994, + "trade_closed_at": "2022-05-20 20:00:00", + "trade_closed_price": 27562.52, + "created_at": "2022-05-20 18:00:00", + "updated_at": "2022-05-20 20:00:00", + "filled": 0.0036, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 28481.28, + "amount": 0.0036, + "net_gain": -3.307535999999994, + "trade_closed_at": "2022-05-20 20:00:00", + "trade_closed_price": 27562.52, + "created_at": "2022-05-20 04:00:00", + "updated_at": "2022-05-20 06:00:00", + "filled": 0.0036, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 10.365, + "amount": 10.2184, + "net_gain": 2.503507999999992, + "trade_closed_at": "2022-05-18 02:00:00", + "trade_closed_price": 10.365, + "created_at": "2022-05-18 00:00:00", + "updated_at": "2022-05-18 02:00:00", + "filled": 10.2184, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 10.120000000000001, + "amount": 10.2184, + "net_gain": 2.503507999999992, + "trade_closed_at": "2022-05-18 02:00:00", + "trade_closed_price": 10.365, + "created_at": "2022-05-17 18:00:00", + "updated_at": "2022-05-17 20:00:00", + "filled": 10.2184, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.93, + "amount": 5.9589, + "net_gain": -3.3667785000000077, + "trade_closed_at": "2022-04-24 22:00:00", + "trade_closed_price": 16.93, + "created_at": "2022-04-24 20:00:00", + "updated_at": "2022-04-24 22:00:00", + "filled": 5.9589, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.495, + "amount": 5.9589, + "net_gain": -3.3667785000000077, + "trade_closed_at": "2022-04-24 22:00:00", + "trade_closed_price": 16.93, + "created_at": "2022-04-23 22:00:00", + "updated_at": "2022-04-24 00:00:00", + "filled": 5.9589, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37527.7, + "amount": 0.0027, + "net_gain": -0.9271934999999969, + "trade_closed_at": "2022-04-22 10:00:00", + "trade_closed_price": 37527.7, + "created_at": "2022-04-22 08:00:00", + "updated_at": "2022-04-22 10:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.015, + "amount": 6.1637, + "net_gain": 0.5239145000000053, + "trade_closed_at": "2022-04-22 12:00:00", + "trade_closed_price": 17.015, + "created_at": "2022-04-22 08:00:00", + "updated_at": "2022-04-22 12:00:00", + "filled": 6.1637, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.93, + "amount": 6.1637, + "net_gain": 0.5239145000000053, + "trade_closed_at": "2022-04-22 12:00:00", + "trade_closed_price": 17.015, + "created_at": "2022-04-19 10:00:00", + "updated_at": "2022-04-19 12:00:00", + "filled": 6.1637, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37871.104999999996, + "amount": 0.0027, + "net_gain": -0.9271934999999969, + "trade_closed_at": "2022-04-22 10:00:00", + "trade_closed_price": 37527.7, + "created_at": "2022-04-19 04:00:00", + "updated_at": "2022-04-19 06:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.17, + "amount": 5.1619, + "net_gain": -0.6452375, + "trade_closed_at": "2022-04-06 00:00:00", + "trade_closed_price": 20.17, + "created_at": "2022-04-05 22:00:00", + "updated_at": "2022-04-06 00:00:00", + "filled": 5.1619, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 41831.869999999995, + "amount": 0.0024, + "net_gain": -0.9912840000000083, + "trade_closed_at": "2022-04-03 06:00:00", + "trade_closed_price": 41831.869999999995, + "created_at": "2022-04-03 04:00:00", + "updated_at": "2022-04-03 06:00:00", + "filled": 0.0024, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 42244.905, + "amount": 0.0024, + "net_gain": -0.9912840000000083, + "trade_closed_at": "2022-04-03 06:00:00", + "trade_closed_price": 41831.869999999995, + "created_at": "2022-04-02 08:00:00", + "updated_at": "2022-04-02 10:00:00", + "filled": 0.0024, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.295, + "amount": 5.1619, + "net_gain": -0.6452375, + "trade_closed_at": "2022-04-06 00:00:00", + "trade_closed_price": 20.17, + "created_at": "2022-04-02 06:00:00", + "updated_at": "2022-04-02 08:00:00", + "filled": 5.1619, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19.465, + "amount": 5.1968, + "net_gain": -4.807040000000003, + "trade_closed_at": "2022-03-31 18:00:00", + "trade_closed_price": 19.465, + "created_at": "2022-03-31 16:00:00", + "updated_at": "2022-03-31 18:00:00", + "filled": 5.1968, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.39, + "amount": 5.1968, + "net_gain": -4.807040000000003, + "trade_closed_at": "2022-03-31 18:00:00", + "trade_closed_price": 19.465, + "created_at": "2022-03-31 06:00:00", + "updated_at": "2022-03-31 08:00:00", + "filled": 5.1968, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 42264.625, + "amount": 0.0025, + "net_gain": 8.386687500000008, + "trade_closed_at": "2022-03-31 02:00:00", + "trade_closed_price": 42264.625, + "created_at": "2022-03-31 00:00:00", + "updated_at": "2022-03-31 02:00:00", + "filled": 0.0025, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.16, + "amount": 5.1598, + "net_gain": 0.20639200000001393, + "trade_closed_at": "2022-03-31 00:00:00", + "trade_closed_price": 20.16, + "created_at": "2022-03-30 22:00:00", + "updated_at": "2022-03-31 00:00:00", + "filled": 5.1598, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.119999999999997, + "amount": 5.1598, + "net_gain": 0.20639200000001393, + "trade_closed_at": "2022-03-31 00:00:00", + "trade_closed_price": 20.16, + "created_at": "2022-03-30 20:00:00", + "updated_at": "2022-03-30 22:00:00", + "filled": 5.1598, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.235, + "amount": 5.1381, + "net_gain": 0.2055239999999956, + "trade_closed_at": "2022-03-30 20:00:00", + "trade_closed_price": 20.235, + "created_at": "2022-03-30 18:00:00", + "updated_at": "2022-03-30 20:00:00", + "filled": 5.1381, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.195, + "amount": 5.1381, + "net_gain": 0.2055239999999956, + "trade_closed_at": "2022-03-30 20:00:00", + "trade_closed_price": 20.235, + "created_at": "2022-03-30 16:00:00", + "updated_at": "2022-03-30 18:00:00", + "filled": 5.1381, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19.745, + "amount": 5.7499, + "net_gain": 13.023523500000024, + "trade_closed_at": "2022-03-30 16:00:00", + "trade_closed_price": 19.745, + "created_at": "2022-03-30 14:00:00", + "updated_at": "2022-03-30 16:00:00", + "filled": 5.7499, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 38909.95, + "amount": 0.0025, + "net_gain": 8.386687500000008, + "trade_closed_at": "2022-03-31 02:00:00", + "trade_closed_price": 42264.625, + "created_at": "2022-03-22 04:00:00", + "updated_at": "2022-03-22 06:00:00", + "filled": 0.0025, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.479999999999997, + "amount": 5.7499, + "net_gain": 13.023523500000024, + "trade_closed_at": "2022-03-30 16:00:00", + "trade_closed_price": 19.745, + "created_at": "2022-03-22 02:00:00", + "updated_at": "2022-03-22 04:00:00", + "filled": 5.7499, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.845, + "amount": 6.0392, + "net_gain": 1.6305839999999974, + "trade_closed_at": "2022-03-20 20:00:00", + "trade_closed_price": 16.845, + "created_at": "2022-03-20 18:00:00", + "updated_at": "2022-03-20 20:00:00", + "filled": 6.0392, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.575, + "amount": 6.0392, + "net_gain": 1.6305839999999974, + "trade_closed_at": "2022-03-20 20:00:00", + "trade_closed_price": 16.845, + "created_at": "2022-03-16 06:00:00", + "updated_at": "2022-03-16 08:00:00", + "filled": 6.0392, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37504.685, + "amount": 0.0027, + "net_gain": 2.389297500000008, + "trade_closed_at": "2022-03-04 08:00:00", + "trade_closed_price": 37504.685, + "created_at": "2022-03-04 06:00:00", + "updated_at": "2022-03-04 08:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 36619.759999999995, + "amount": 0.0027, + "net_gain": 2.389297500000008, + "trade_closed_at": "2022-03-04 08:00:00", + "trade_closed_price": 37504.685, + "created_at": "2022-02-28 16:00:00", + "updated_at": "2022-02-28 18:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 38148.075, + "amount": 0.0027, + "net_gain": 7.0793190000000035, + "trade_closed_at": "2022-02-11 12:00:00", + "trade_closed_price": 38148.075, + "created_at": "2022-02-11 10:00:00", + "updated_at": "2022-02-11 12:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 18.945, + "amount": 5.0932, + "net_gain": -1.6552899999999966, + "trade_closed_at": "2022-02-10 14:00:00", + "trade_closed_price": 18.945, + "created_at": "2022-02-10 12:00:00", + "updated_at": "2022-02-10 14:00:00", + "filled": 5.0932, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19.27, + "amount": 5.0932, + "net_gain": -1.6552899999999966, + "trade_closed_at": "2022-02-10 14:00:00", + "trade_closed_price": 18.945, + "created_at": "2022-02-09 22:00:00", + "updated_at": "2022-02-10 00:00:00", + "filled": 5.0932, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 18.619999999999997, + "amount": 5.4693, + "net_gain": 4.922369999999992, + "trade_closed_at": "2022-02-08 20:00:00", + "trade_closed_price": 18.619999999999997, + "created_at": "2022-02-08 18:00:00", + "updated_at": "2022-02-08 20:00:00", + "filled": 5.4693, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.72, + "amount": 5.4693, + "net_gain": 4.922369999999992, + "trade_closed_at": "2022-02-08 20:00:00", + "trade_closed_price": 18.619999999999997, + "created_at": "2022-02-04 22:00:00", + "updated_at": "2022-02-05 00:00:00", + "filled": 5.4693, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 35526.104999999996, + "amount": 0.0027, + "net_gain": 7.0793190000000035, + "trade_closed_at": "2022-02-11 12:00:00", + "trade_closed_price": 38148.075, + "created_at": "2022-02-04 20:00:00", + "updated_at": "2022-02-04 22:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.39, + "amount": 5.7445, + "net_gain": -4.739212499999996, + "trade_closed_at": "2022-02-03 08:00:00", + "trade_closed_price": 16.39, + "created_at": "2022-02-03 06:00:00", + "updated_at": "2022-02-03 08:00:00", + "filled": 5.7445, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 33083.82, + "amount": 0.0028, + "net_gain": -3.1611160000000034, + "trade_closed_at": "2022-02-02 18:00:00", + "trade_closed_price": 33083.82, + "created_at": "2022-02-02 16:00:00", + "updated_at": "2022-02-02 18:00:00", + "filled": 0.0028, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 34212.79, + "amount": 0.0028, + "net_gain": -3.1611160000000034, + "trade_closed_at": "2022-02-02 18:00:00", + "trade_closed_price": 33083.82, + "created_at": "2022-02-01 00:00:00", + "updated_at": "2022-02-01 02:00:00", + "filled": 0.0028, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.215, + "amount": 5.7445, + "net_gain": -4.739212499999996, + "trade_closed_at": "2022-02-03 08:00:00", + "trade_closed_price": 16.39, + "created_at": "2022-02-01 00:00:00", + "updated_at": "2022-02-01 04:00:00", + "filled": 5.7445, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37330.135, + "amount": 0.0026, + "net_gain": -1.1311430000000007, + "trade_closed_at": "2022-01-17 06:00:00", + "trade_closed_price": 37330.135, + "created_at": "2022-01-17 04:00:00", + "updated_at": "2022-01-17 06:00:00", + "filled": 0.0026, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37765.19, + "amount": 0.0026, + "net_gain": -1.1311430000000007, + "trade_closed_at": "2022-01-17 06:00:00", + "trade_closed_price": 37330.135, + "created_at": "2022-01-15 06:00:00", + "updated_at": "2022-01-15 08:00:00", + "filled": 0.0026, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 43515.965, + "amount": 0.0022, + "net_gain": -3.301727000000008, + "trade_closed_at": "2021-12-28 06:00:00", + "trade_closed_price": 43515.965, + "created_at": "2021-12-28 04:00:00", + "updated_at": "2021-12-28 06:00:00", + "filled": 0.0022, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 45016.75, + "amount": 0.0022, + "net_gain": -3.301727000000008, + "trade_closed_at": "2021-12-28 06:00:00", + "trade_closed_price": 43515.965, + "created_at": "2021-12-27 02:00:00", + "updated_at": "2021-12-27 04:00:00", + "filled": 0.0022, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + } + ], + "created_at": "2024-04-25 13:52:37" +} \ No newline at end of file diff --git a/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:54.json b/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:54.json new file mode 100644 index 00000000..f070140d --- /dev/null +++ b/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:54.json @@ -0,0 +1,1294 @@ +{ + "name": "10-50-100", + "context": {}, + "strategy_identifiers": [], + "backtest_start_date": "2022-06-10 00:00:00", + "backtest_end_date": "2023-01-10 00:00:00", + "number_of_runs": 2569, + "symbols": null, + "market": null, + "number_of_days": 214, + "number_of_orders": 44, + "number_of_positions": 3, + "market_data_file": null, + "percentage_positive_trades": 18.181818181818183, + "percentage_negative_trades": 77.27272727272727, + "number_of_trades_closed": 21, + "number_of_trades_open": 2, + "total_cost": 186.64053600000003, + "growth_rate": -5.170270125000016, + "growth": -20.681080500000064, + "initial_unallocated": 400.0, + "trading_symbol": "EUR", + "total_net_gain_percentage": -6.230079749999998, + "total_net_gain": -24.920318999999992, + "total_value": 379.31891949999994, + "average_trade_duration": 54.666666666666664, + "average_trade_size": 96.42433528571428, + "positions": [ + { + "symbol": "EUR", + "amount": 188.43914499999994, + "cost": 188.43914499999994, + "price": 1, + "value": 188.43914499999994, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0.0, + "amount_pending_sell": 0.0, + "percentage_of_portfolio": 49.67828792942662 + }, + { + "symbol": "BTC", + "amount": 0.0058, + "cost": 92.87073099999999, + "price": 16038.015, + "value": 93.02048699999999, + "growth": 0.14975599999999645, + "growth_rate": 0.161252095668329, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 24.52302856989447 + }, + { + "symbol": "DOT", + "amount": 21.355, + "cost": 93.769805, + "price": 4.5825, + "value": 97.8592875, + "growth": 4.089482499999988, + "growth_rate": 4.361193350034148, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 25.79868350067891 + } + ], + "trades": [ + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "OPEN", + "amount": 0.0058, + "open_price": 16012.195, + "current_price": 16038.015, + "closed_price": null, + "opened_at": "2023-01-08 22:00:00", + "closed_at": null, + "change": 0.161252095668329, + "absolute_change": 0 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "OPEN", + "amount": 21.355, + "open_price": 4.391, + "current_price": 4.5825, + "closed_price": null, + "opened_at": "2023-01-08 12:00:00", + "closed_at": null, + "change": 4.361193350034148, + "absolute_change": 0 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15853.27, + "current_price": 16038.015, + "closed_price": 15778.795, + "opened_at": "2022-12-26 06:00:00", + "closed_at": "2022-12-26 20:00:00", + "change": 0, + "absolute_change": -0.4394024999999999 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15850.17, + "current_price": 16038.015, + "closed_price": 15831.685000000001, + "opened_at": "2022-12-24 18:00:00", + "closed_at": "2022-12-25 04:00:00", + "change": 0, + "absolute_change": -0.1090614999999957 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0057, + "open_price": 16423.975, + "current_price": 16038.015, + "closed_price": 16335.6, + "opened_at": "2022-12-13 08:00:00", + "closed_at": "2022-12-16 02:00:00", + "change": 0, + "absolute_change": -0.5037374999999855 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0057, + "open_price": 16266.675, + "current_price": 16038.015, + "closed_price": 16097.795, + "opened_at": "2022-12-09 04:00:00", + "closed_at": "2022-12-12 06:00:00", + "change": 0, + "absolute_change": -0.9626159999999828 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0058, + "open_price": 16201.025000000001, + "current_price": 16038.015, + "closed_price": 16043.84, + "opened_at": "2022-12-06 18:00:00", + "closed_at": "2022-12-07 12:00:00", + "change": 0, + "absolute_change": -0.9116730000000075 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0058, + "open_price": 16295.425, + "current_price": 16038.015, + "closed_price": 16173.285, + "opened_at": "2022-12-05 00:00:00", + "closed_at": "2022-12-06 14:00:00", + "change": 0, + "absolute_change": -0.7084119999999956 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15842.86, + "current_price": 16038.015, + "closed_price": 16169.130000000001, + "opened_at": "2022-11-29 16:00:00", + "closed_at": "2022-12-03 06:00:00", + "change": 0, + "absolute_change": 1.9249930000000006 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 13.2067, + "open_price": 7.32, + "current_price": 4.5825, + "closed_price": 6.57, + "opened_at": "2022-11-07 20:00:00", + "closed_at": "2022-11-08 06:00:00", + "change": 0, + "absolute_change": -9.905025000000009 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 14.5002, + "open_price": 6.62, + "current_price": 4.5825, + "closed_price": 6.8100000000000005, + "opened_at": "2022-11-03 22:00:00", + "closed_at": "2022-11-07 12:00:00", + "change": 0, + "absolute_change": 2.755038000000013 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0046, + "open_price": 20780.614999999998, + "current_price": 16038.015, + "closed_price": 20774.495000000003, + "opened_at": "2022-11-03 16:00:00", + "closed_at": "2022-11-07 10:00:00", + "change": 0, + "absolute_change": -0.028151999999977306 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0048, + "open_price": 19937.42, + "current_price": 16038.015, + "closed_price": 19530.1, + "opened_at": "2022-10-17 10:00:00", + "closed_at": "2022-10-19 00:00:00", + "change": 0, + "absolute_change": -1.955135999999996 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0048, + "open_price": 20098.595, + "current_price": 16038.015, + "closed_price": 19814.379999999997, + "opened_at": "2022-09-29 00:00:00", + "closed_at": "2022-09-29 18:00:00", + "change": 0, + "absolute_change": -1.3642320000000154 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 14.4912, + "open_price": 6.755, + "current_price": 4.5825, + "closed_price": 6.555, + "opened_at": "2022-09-26 16:00:00", + "closed_at": "2022-09-28 12:00:00", + "change": 0, + "absolute_change": -2.8982400000000013 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0049, + "open_price": 19819.32, + "current_price": 16038.015, + "closed_price": 19539.96, + "opened_at": "2022-09-26 14:00:00", + "closed_at": "2022-09-28 10:00:00", + "change": 0, + "absolute_change": -1.368864000000002 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 13.0149, + "open_price": 7.545, + "current_price": 4.5825, + "closed_price": 7.449999999999999, + "opened_at": "2022-09-09 04:00:00", + "closed_at": "2022-09-13 04:00:00", + "change": 0, + "absolute_change": -1.2364155000000068 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0042, + "open_price": 23541.17, + "current_price": 16038.015, + "closed_price": 23606.475, + "opened_at": "2022-08-11 00:00:00", + "closed_at": "2022-08-16 00:00:00", + "change": 0, + "absolute_change": 0.274281000000002 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 10.7186, + "open_price": 9.225000000000001, + "current_price": 4.5825, + "closed_price": 8.945, + "opened_at": "2022-08-10 14:00:00", + "closed_at": "2022-08-14 16:00:00", + "change": 0, + "absolute_change": -3.0012080000000054 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 12.3923, + "open_price": 8.05, + "current_price": 4.5825, + "closed_price": 7.92, + "opened_at": "2022-08-04 02:00:00", + "closed_at": "2022-08-04 10:00:00", + "change": 0, + "absolute_change": -1.6109990000000067 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0043, + "open_price": 23002.074999999997, + "current_price": 16038.015, + "closed_price": 22559.055, + "opened_at": "2022-08-03 20:00:00", + "closed_at": "2022-08-04 14:00:00", + "change": 0, + "absolute_change": -1.9049859999999939 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 13.2978, + "open_price": 7.52, + "current_price": 4.5825, + "closed_price": 7.574999999999999, + "opened_at": "2022-06-24 04:00:00", + "closed_at": "2022-06-27 14:00:00", + "change": 0, + "absolute_change": 0.731379000000004 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.005, + "open_price": 19905.03, + "current_price": 16038.015, + "closed_price": 19565.46, + "opened_at": "2022-06-23 22:00:00", + "closed_at": "2022-06-27 16:00:00", + "change": 0, + "absolute_change": -1.6978500000000025 + } + ], + "orders": [ + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16012.195, + "amount": 0.0058, + "net_gain": 0.0, + "trade_closed_at": null, + "trade_closed_price": null, + "created_at": "2023-01-08 22:00:00", + "updated_at": "2023-01-09 00:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.391, + "amount": 21.355, + "net_gain": 0.0, + "trade_closed_at": null, + "trade_closed_price": null, + "created_at": "2023-01-08 12:00:00", + "updated_at": "2023-01-08 14:00:00", + "filled": 21.355, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15778.795, + "amount": 0.0059, + "net_gain": -0.43940250000000214, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 18:00:00", + "updated_at": "2022-12-26 20:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15853.27, + "amount": 0.0059, + "net_gain": -0.43940250000000214, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 06:00:00", + "updated_at": "2022-12-26 08:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15831.685000000001, + "amount": 0.0059, + "net_gain": -0.1090614999999927, + "trade_closed_at": "2022-12-25 04:00:00", + "trade_closed_price": 15831.685000000001, + "created_at": "2022-12-25 02:00:00", + "updated_at": "2022-12-25 04:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15850.17, + "amount": 0.0059, + "net_gain": -0.1090614999999927, + "trade_closed_at": "2022-12-25 04:00:00", + "trade_closed_price": 15831.685000000001, + "created_at": "2022-12-24 18:00:00", + "updated_at": "2022-12-24 20:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16335.6, + "amount": 0.0057, + "net_gain": -0.5037374999999896, + "trade_closed_at": "2022-12-16 02:00:00", + "trade_closed_price": 16335.6, + "created_at": "2022-12-16 00:00:00", + "updated_at": "2022-12-16 02:00:00", + "filled": 0.0057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16423.975, + "amount": 0.0057, + "net_gain": -0.5037374999999896, + "trade_closed_at": "2022-12-16 02:00:00", + "trade_closed_price": 16335.6, + "created_at": "2022-12-13 08:00:00", + "updated_at": "2022-12-13 10:00:00", + "filled": 0.0057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16097.795, + "amount": 0.0057, + "net_gain": -0.9626159999999955, + "trade_closed_at": "2022-12-12 06:00:00", + "trade_closed_price": 16097.795, + "created_at": "2022-12-12 04:00:00", + "updated_at": "2022-12-12 06:00:00", + "filled": 0.0057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16266.675, + "amount": 0.0057, + "net_gain": -0.9626159999999955, + "trade_closed_at": "2022-12-12 06:00:00", + "trade_closed_price": 16097.795, + "created_at": "2022-12-09 04:00:00", + "updated_at": "2022-12-09 06:00:00", + "filled": 0.0057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16043.84, + "amount": 0.0058, + "net_gain": -0.9116730000000075, + "trade_closed_at": "2022-12-07 12:00:00", + "trade_closed_price": 16043.84, + "created_at": "2022-12-07 10:00:00", + "updated_at": "2022-12-07 12:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16201.025000000001, + "amount": 0.0058, + "net_gain": -0.9116730000000075, + "trade_closed_at": "2022-12-07 12:00:00", + "trade_closed_price": 16043.84, + "created_at": "2022-12-06 18:00:00", + "updated_at": "2022-12-06 20:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16173.285, + "amount": 0.0058, + "net_gain": -0.7084119999999966, + "trade_closed_at": "2022-12-06 14:00:00", + "trade_closed_price": 16173.285, + "created_at": "2022-12-06 12:00:00", + "updated_at": "2022-12-06 14:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16295.425, + "amount": 0.0058, + "net_gain": -0.7084119999999966, + "trade_closed_at": "2022-12-06 14:00:00", + "trade_closed_price": 16173.285, + "created_at": "2022-12-05 00:00:00", + "updated_at": "2022-12-05 02:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16169.130000000001, + "amount": 0.0059, + "net_gain": 1.9249930000000026, + "trade_closed_at": "2022-12-03 06:00:00", + "trade_closed_price": 16169.130000000001, + "created_at": "2022-12-03 04:00:00", + "updated_at": "2022-12-03 06:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15842.86, + "amount": 0.0059, + "net_gain": 1.9249930000000026, + "trade_closed_at": "2022-12-03 06:00:00", + "trade_closed_price": 16169.130000000001, + "created_at": "2022-11-29 16:00:00", + "updated_at": "2022-11-29 18:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.57, + "amount": 13.2067, + "net_gain": -9.905025, + "trade_closed_at": "2022-11-08 06:00:00", + "trade_closed_price": 6.57, + "created_at": "2022-11-08 04:00:00", + "updated_at": "2022-11-08 06:00:00", + "filled": 13.2067, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.32, + "amount": 13.2067, + "net_gain": -9.905025, + "trade_closed_at": "2022-11-08 06:00:00", + "trade_closed_price": 6.57, + "created_at": "2022-11-07 20:00:00", + "updated_at": "2022-11-07 22:00:00", + "filled": 13.2067, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.8100000000000005, + "amount": 14.5002, + "net_gain": 2.7550380000000056, + "trade_closed_at": "2022-11-07 12:00:00", + "trade_closed_price": 6.8100000000000005, + "created_at": "2022-11-07 10:00:00", + "updated_at": "2022-11-07 12:00:00", + "filled": 14.5002, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20774.495000000003, + "amount": 0.0046, + "net_gain": -0.02815199999997858, + "trade_closed_at": "2022-11-07 10:00:00", + "trade_closed_price": 20774.495000000003, + "created_at": "2022-11-07 08:00:00", + "updated_at": "2022-11-07 10:00:00", + "filled": 0.0046, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.62, + "amount": 14.5002, + "net_gain": 2.7550380000000056, + "trade_closed_at": "2022-11-07 12:00:00", + "trade_closed_price": 6.8100000000000005, + "created_at": "2022-11-03 22:00:00", + "updated_at": "2022-11-04 00:00:00", + "filled": 14.5002, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20780.614999999998, + "amount": 0.0046, + "net_gain": -0.02815199999997858, + "trade_closed_at": "2022-11-07 10:00:00", + "trade_closed_price": 20774.495000000003, + "created_at": "2022-11-03 16:00:00", + "updated_at": "2022-11-03 18:00:00", + "filled": 0.0046, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19530.1, + "amount": 0.0048, + "net_gain": -1.9551359999999984, + "trade_closed_at": "2022-10-19 00:00:00", + "trade_closed_price": 19530.1, + "created_at": "2022-10-18 22:00:00", + "updated_at": "2022-10-19 00:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19937.42, + "amount": 0.0048, + "net_gain": -1.9551359999999984, + "trade_closed_at": "2022-10-19 00:00:00", + "trade_closed_price": 19530.1, + "created_at": "2022-10-17 10:00:00", + "updated_at": "2022-10-17 12:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19814.379999999997, + "amount": 0.0048, + "net_gain": -1.364232000000018, + "trade_closed_at": "2022-09-29 18:00:00", + "trade_closed_price": 19814.379999999997, + "created_at": "2022-09-29 16:00:00", + "updated_at": "2022-09-29 18:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20098.595, + "amount": 0.0048, + "net_gain": -1.364232000000018, + "trade_closed_at": "2022-09-29 18:00:00", + "trade_closed_price": 19814.379999999997, + "created_at": "2022-09-29 00:00:00", + "updated_at": "2022-09-29 02:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19539.96, + "amount": 0.0049, + "net_gain": -1.3688640000000027, + "trade_closed_at": "2022-09-28 10:00:00", + "trade_closed_price": 19539.96, + "created_at": "2022-09-28 08:00:00", + "updated_at": "2022-09-28 10:00:00", + "filled": 0.0049, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.555, + "amount": 14.4912, + "net_gain": -2.8982400000000026, + "trade_closed_at": "2022-09-28 12:00:00", + "trade_closed_price": 6.555, + "created_at": "2022-09-28 08:00:00", + "updated_at": "2022-09-28 12:00:00", + "filled": 14.4912, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.755, + "amount": 14.4912, + "net_gain": -2.8982400000000026, + "trade_closed_at": "2022-09-28 12:00:00", + "trade_closed_price": 6.555, + "created_at": "2022-09-26 16:00:00", + "updated_at": "2022-09-26 18:00:00", + "filled": 14.4912, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19819.32, + "amount": 0.0049, + "net_gain": -1.3688640000000027, + "trade_closed_at": "2022-09-28 10:00:00", + "trade_closed_price": 19539.96, + "created_at": "2022-09-26 14:00:00", + "updated_at": "2022-09-26 16:00:00", + "filled": 0.0049, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.449999999999999, + "amount": 13.0149, + "net_gain": -1.2364155000000083, + "trade_closed_at": "2022-09-13 04:00:00", + "trade_closed_price": 7.449999999999999, + "created_at": "2022-09-13 02:00:00", + "updated_at": "2022-09-13 04:00:00", + "filled": 13.0149, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.545, + "amount": 13.0149, + "net_gain": -1.2364155000000083, + "trade_closed_at": "2022-09-13 04:00:00", + "trade_closed_price": 7.449999999999999, + "created_at": "2022-09-09 04:00:00", + "updated_at": "2022-09-09 06:00:00", + "filled": 13.0149, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 23606.475, + "amount": 0.0042, + "net_gain": 0.2742810000000012, + "trade_closed_at": "2022-08-16 00:00:00", + "trade_closed_price": 23606.475, + "created_at": "2022-08-15 22:00:00", + "updated_at": "2022-08-16 00:00:00", + "filled": 0.0042, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 8.945, + "amount": 10.7186, + "net_gain": -3.001208000000012, + "trade_closed_at": "2022-08-14 16:00:00", + "trade_closed_price": 8.945, + "created_at": "2022-08-14 14:00:00", + "updated_at": "2022-08-14 16:00:00", + "filled": 10.7186, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 23541.17, + "amount": 0.0042, + "net_gain": 0.2742810000000012, + "trade_closed_at": "2022-08-16 00:00:00", + "trade_closed_price": 23606.475, + "created_at": "2022-08-11 00:00:00", + "updated_at": "2022-08-11 02:00:00", + "filled": 0.0042, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 9.225000000000001, + "amount": 10.7186, + "net_gain": -3.001208000000012, + "trade_closed_at": "2022-08-14 16:00:00", + "trade_closed_price": 8.945, + "created_at": "2022-08-10 14:00:00", + "updated_at": "2022-08-10 16:00:00", + "filled": 10.7186, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 22559.055, + "amount": 0.0043, + "net_gain": -1.9049859999999863, + "trade_closed_at": "2022-08-04 14:00:00", + "trade_closed_price": 22559.055, + "created_at": "2022-08-04 12:00:00", + "updated_at": "2022-08-04 14:00:00", + "filled": 0.0043, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.92, + "amount": 12.3923, + "net_gain": -1.6109990000000098, + "trade_closed_at": "2022-08-04 10:00:00", + "trade_closed_price": 7.92, + "created_at": "2022-08-04 08:00:00", + "updated_at": "2022-08-04 10:00:00", + "filled": 12.3923, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 8.05, + "amount": 12.3923, + "net_gain": -1.6109990000000098, + "trade_closed_at": "2022-08-04 10:00:00", + "trade_closed_price": 7.92, + "created_at": "2022-08-04 02:00:00", + "updated_at": "2022-08-04 04:00:00", + "filled": 12.3923, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 23002.074999999997, + "amount": 0.0043, + "net_gain": -1.9049859999999863, + "trade_closed_at": "2022-08-04 14:00:00", + "trade_closed_price": 22559.055, + "created_at": "2022-08-03 20:00:00", + "updated_at": "2022-08-03 22:00:00", + "filled": 0.0043, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19565.46, + "amount": 0.005, + "net_gain": -1.6978499999999985, + "trade_closed_at": "2022-06-27 16:00:00", + "trade_closed_price": 19565.46, + "created_at": "2022-06-27 14:00:00", + "updated_at": "2022-06-27 16:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.574999999999999, + "amount": 13.2978, + "net_gain": 0.7313789999999962, + "trade_closed_at": "2022-06-27 14:00:00", + "trade_closed_price": 7.574999999999999, + "created_at": "2022-06-27 12:00:00", + "updated_at": "2022-06-27 14:00:00", + "filled": 13.2978, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.52, + "amount": 13.2978, + "net_gain": 0.7313789999999962, + "trade_closed_at": "2022-06-27 14:00:00", + "trade_closed_price": 7.574999999999999, + "created_at": "2022-06-24 04:00:00", + "updated_at": "2022-06-24 06:00:00", + "filled": 13.2978, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19905.03, + "amount": 0.005, + "net_gain": -1.6978499999999985, + "trade_closed_at": "2022-06-27 16:00:00", + "trade_closed_price": 19565.46, + "created_at": "2022-06-23 22:00:00", + "updated_at": "2022-06-24 00:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + } + ], + "created_at": "2024-04-25 13:54:01" +} \ No newline at end of file diff --git a/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:53.json b/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:53.json new file mode 100644 index 00000000..59f386c6 --- /dev/null +++ b/tests/resources/backtest_reports_for_testing/report_10-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:53.json @@ -0,0 +1,1281 @@ +{ + "name": "10-50-100", + "context": {}, + "strategy_identifiers": [], + "backtest_start_date": "2022-12-20 00:00:00", + "backtest_end_date": "2023-06-01 00:00:00", + "number_of_runs": 1957, + "symbols": null, + "market": null, + "number_of_days": 163, + "number_of_orders": 44, + "number_of_positions": 1, + "market_data_file": null, + "percentage_positive_trades": 22.727272727272727, + "percentage_negative_trades": 77.27272727272727, + "number_of_trades_closed": 22, + "number_of_trades_open": 0, + "total_cost": 1.4210854715202004e-14, + "growth_rate": 2.508658175000008, + "growth": 10.034632700000031, + "initial_unallocated": 400.0, + "trading_symbol": "EUR", + "total_net_gain_percentage": 2.5086581750000154, + "total_net_gain": 10.034632700000062, + "total_value": 410.03463270000003, + "average_trade_duration": 65.45454545454545, + "average_trade_size": 105.95494051363639, + "positions": [ + { + "symbol": "EUR", + "amount": 410.03463270000003, + "cost": 410.03463270000003, + "price": 1, + "value": 410.03463270000003, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0.0, + "amount_pending_sell": 0.0, + "percentage_of_portfolio": 100.0 + }, + { + "symbol": "BTC", + "amount": 0.0, + "cost": 0.0, + "price": 25496.73, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + }, + { + "symbol": "DOT", + "amount": 0.0, + "cost": 0.0, + "price": 4.9785, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + } + ], + "trades": [ + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 20.6078, + "open_price": 5.004, + "current_price": 4.9785, + "closed_price": 4.885, + "opened_at": "2023-05-23 10:00:00", + "closed_at": "2023-05-24 14:00:00", + "change": 0, + "absolute_change": -2.4523281999999824 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0041, + "open_price": 25097.05, + "current_price": 25496.73, + "closed_price": 24920.845, + "opened_at": "2023-05-20 22:00:00", + "closed_at": "2023-05-21 18:00:00", + "change": 0, + "absolute_change": -0.7224404999999905 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0041, + "open_price": 25253.309999999998, + "current_price": 25496.73, + "closed_price": 24998.004999999997, + "opened_at": "2023-05-18 02:00:00", + "closed_at": "2023-05-19 06:00:00", + "change": 0, + "absolute_change": -1.0467505000000017 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 20.735, + "open_price": 5.019, + "current_price": 4.9785, + "closed_price": 4.9215, + "opened_at": "2023-05-18 02:00:00", + "closed_at": "2023-05-21 16:00:00", + "change": 0, + "absolute_change": -2.021662500000005 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0039, + "open_price": 26978.895, + "current_price": 25496.73, + "closed_price": 26014.935, + "opened_at": "2023-04-30 16:00:00", + "closed_at": "2023-05-01 04:00:00", + "change": 0, + "absolute_change": -3.759444000000002 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 19.4111, + "open_price": 5.4495000000000005, + "current_price": 4.9785, + "closed_price": 5.2905, + "opened_at": "2023-04-29 12:00:00", + "closed_at": "2023-05-01 06:00:00", + "change": 0, + "absolute_change": -3.0863649000000066 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0038, + "open_price": 27745.405, + "current_price": 25496.73, + "closed_price": 26854.125, + "opened_at": "2023-04-18 22:00:00", + "closed_at": "2023-04-19 14:00:00", + "change": 0, + "absolute_change": -3.3868639999999886 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 17.3047, + "open_price": 6.2375, + "current_price": 4.9785, + "closed_price": 5.9345, + "opened_at": "2023-04-18 06:00:00", + "closed_at": "2023-04-19 16:00:00", + "change": 0, + "absolute_change": -5.2433241000000095 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0041, + "open_price": 26119.065000000002, + "current_price": 25496.73, + "closed_price": 25865.705, + "opened_at": "2023-04-05 12:00:00", + "closed_at": "2023-04-06 04:00:00", + "change": 0, + "absolute_change": -1.0387759999999986 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0041, + "open_price": 26170.36, + "current_price": 25496.73, + "closed_price": 25758.385000000002, + "opened_at": "2023-03-24 04:00:00", + "closed_at": "2023-03-25 02:00:00", + "change": 0, + "absolute_change": -1.6890974999999884 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0051, + "open_price": 21658.64, + "current_price": 25496.73, + "closed_price": 21172.035000000003, + "opened_at": "2023-02-07 22:00:00", + "closed_at": "2023-02-09 04:00:00", + "change": 0, + "absolute_change": -2.481685499999969 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 17.231, + "open_price": 6.429, + "current_price": 4.9785, + "closed_price": 6.072, + "opened_at": "2023-02-07 22:00:00", + "closed_at": "2023-02-09 20:00:00", + "change": 0, + "absolute_change": -6.151466999999997 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 18.4906, + "open_price": 5.962999999999999, + "current_price": 4.9785, + "closed_price": 6.131, + "opened_at": "2023-02-02 10:00:00", + "closed_at": "2023-02-06 00:00:00", + "change": 0, + "absolute_change": 3.1064208000000235 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.005, + "open_price": 21646.98, + "current_price": 25496.73, + "closed_price": 21441.1, + "opened_at": "2023-02-02 04:00:00", + "closed_at": "2023-02-05 16:00:00", + "change": 0, + "absolute_change": -1.0293999999999954 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 18.8685, + "open_price": 5.894, + "current_price": 4.9785, + "closed_price": 5.776, + "opened_at": "2023-01-26 12:00:00", + "closed_at": "2023-01-30 16:00:00", + "change": 0, + "absolute_change": -2.2264830000000018 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0052, + "open_price": 21212.68, + "current_price": 25496.73, + "closed_price": 20908.79, + "opened_at": "2023-01-26 04:00:00", + "closed_at": "2023-01-31 00:00:00", + "change": 0, + "absolute_change": -1.5802280000000053 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 19.5136, + "open_price": 5.631, + "current_price": 4.9785, + "closed_price": 5.6370000000000005, + "opened_at": "2023-01-20 20:00:00", + "closed_at": "2023-01-25 04:00:00", + "change": 0, + "absolute_change": 0.11708160000000589 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0055, + "open_price": 19751.965, + "current_price": 25496.73, + "closed_price": 20697.87, + "opened_at": "2023-01-20 18:00:00", + "closed_at": "2023-01-25 02:00:00", + "change": 0, + "absolute_change": 5.202477499999986 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0062, + "open_price": 16012.195, + "current_price": 25496.73, + "closed_price": 19220.955, + "opened_at": "2023-01-08 22:00:00", + "closed_at": "2023-01-19 04:00:00", + "change": 0, + "absolute_change": 19.894312000000014 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 22.7405, + "open_price": 4.391, + "current_price": 4.9785, + "closed_price": 5.28, + "opened_at": "2023-01-08 12:00:00", + "closed_at": "2023-01-16 16:00:00", + "change": 0, + "absolute_change": 20.216304500000007 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0063, + "open_price": 15853.27, + "current_price": 25496.73, + "closed_price": 15778.795, + "opened_at": "2022-12-26 06:00:00", + "closed_at": "2022-12-26 20:00:00", + "change": 0, + "absolute_change": -0.46919250000000545 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0063, + "open_price": 15850.17, + "current_price": 25496.73, + "closed_price": 15831.685000000001, + "opened_at": "2022-12-24 18:00:00", + "closed_at": "2022-12-25 04:00:00", + "change": 0, + "absolute_change": -0.1164554999999865 + } + ], + "orders": [ + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.885, + "amount": 20.6078, + "net_gain": -2.4523281999999953, + "trade_closed_at": "2023-05-24 14:00:00", + "trade_closed_price": 4.885, + "created_at": "2023-05-24 12:00:00", + "updated_at": "2023-05-24 14:00:00", + "filled": 20.6078, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.004, + "amount": 20.6078, + "net_gain": -2.4523281999999953, + "trade_closed_at": "2023-05-24 14:00:00", + "trade_closed_price": 4.885, + "created_at": "2023-05-23 10:00:00", + "updated_at": "2023-05-23 12:00:00", + "filled": 20.6078, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 24920.845, + "amount": 0.0041, + "net_gain": -0.7224404999999923, + "trade_closed_at": "2023-05-21 18:00:00", + "trade_closed_price": 24920.845, + "created_at": "2023-05-21 16:00:00", + "updated_at": "2023-05-21 18:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.9215, + "amount": 20.735, + "net_gain": -2.021662500000003, + "trade_closed_at": "2023-05-21 16:00:00", + "trade_closed_price": 4.9215, + "created_at": "2023-05-21 14:00:00", + "updated_at": "2023-05-21 16:00:00", + "filled": 20.735, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25097.05, + "amount": 0.0041, + "net_gain": -0.7224404999999923, + "trade_closed_at": "2023-05-21 18:00:00", + "trade_closed_price": 24920.845, + "created_at": "2023-05-20 22:00:00", + "updated_at": "2023-05-21 00:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 24998.004999999997, + "amount": 0.0041, + "net_gain": -1.0467505000000012, + "trade_closed_at": "2023-05-19 06:00:00", + "trade_closed_price": 24998.004999999997, + "created_at": "2023-05-19 04:00:00", + "updated_at": "2023-05-19 06:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25253.309999999998, + "amount": 0.0041, + "net_gain": -1.0467505000000012, + "trade_closed_at": "2023-05-19 06:00:00", + "trade_closed_price": 24998.004999999997, + "created_at": "2023-05-18 02:00:00", + "updated_at": "2023-05-18 04:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.019, + "amount": 20.735, + "net_gain": -2.021662500000003, + "trade_closed_at": "2023-05-21 16:00:00", + "trade_closed_price": 4.9215, + "created_at": "2023-05-18 02:00:00", + "updated_at": "2023-05-18 06:00:00", + "filled": 20.735, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26014.935, + "amount": 0.0039, + "net_gain": -3.7594439999999962, + "trade_closed_at": "2023-05-01 04:00:00", + "trade_closed_price": 26014.935, + "created_at": "2023-05-01 02:00:00", + "updated_at": "2023-05-01 04:00:00", + "filled": 0.0039, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.2905, + "amount": 19.4111, + "net_gain": -3.0863649000000137, + "trade_closed_at": "2023-05-01 06:00:00", + "trade_closed_price": 5.2905, + "created_at": "2023-05-01 02:00:00", + "updated_at": "2023-05-01 06:00:00", + "filled": 19.4111, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26978.895, + "amount": 0.0039, + "net_gain": -3.7594439999999962, + "trade_closed_at": "2023-05-01 04:00:00", + "trade_closed_price": 26014.935, + "created_at": "2023-04-30 16:00:00", + "updated_at": "2023-04-30 18:00:00", + "filled": 0.0039, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.4495000000000005, + "amount": 19.4111, + "net_gain": -3.0863649000000137, + "trade_closed_at": "2023-05-01 06:00:00", + "trade_closed_price": 5.2905, + "created_at": "2023-04-29 12:00:00", + "updated_at": "2023-04-29 14:00:00", + "filled": 19.4111, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26854.125, + "amount": 0.0038, + "net_gain": -3.3868639999999957, + "trade_closed_at": "2023-04-19 14:00:00", + "trade_closed_price": 26854.125, + "created_at": "2023-04-19 12:00:00", + "updated_at": "2023-04-19 14:00:00", + "filled": 0.0038, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.9345, + "amount": 17.3047, + "net_gain": -5.243324099999999, + "trade_closed_at": "2023-04-19 16:00:00", + "trade_closed_price": 5.9345, + "created_at": "2023-04-19 12:00:00", + "updated_at": "2023-04-19 16:00:00", + "filled": 17.3047, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 27745.405, + "amount": 0.0038, + "net_gain": -3.3868639999999957, + "trade_closed_at": "2023-04-19 14:00:00", + "trade_closed_price": 26854.125, + "created_at": "2023-04-18 22:00:00", + "updated_at": "2023-04-19 00:00:00", + "filled": 0.0038, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.2375, + "amount": 17.3047, + "net_gain": -5.243324099999999, + "trade_closed_at": "2023-04-19 16:00:00", + "trade_closed_price": 5.9345, + "created_at": "2023-04-18 06:00:00", + "updated_at": "2023-04-18 08:00:00", + "filled": 17.3047, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25865.705, + "amount": 0.0041, + "net_gain": -1.0387760000000024, + "trade_closed_at": "2023-04-06 04:00:00", + "trade_closed_price": 25865.705, + "created_at": "2023-04-06 02:00:00", + "updated_at": "2023-04-06 04:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26119.065000000002, + "amount": 0.0041, + "net_gain": -1.0387760000000024, + "trade_closed_at": "2023-04-06 04:00:00", + "trade_closed_price": 25865.705, + "created_at": "2023-04-05 12:00:00", + "updated_at": "2023-04-05 14:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25758.385000000002, + "amount": 0.0041, + "net_gain": -1.6890974999999941, + "trade_closed_at": "2023-03-25 02:00:00", + "trade_closed_price": 25758.385000000002, + "created_at": "2023-03-25 00:00:00", + "updated_at": "2023-03-25 02:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26170.36, + "amount": 0.0041, + "net_gain": -1.6890974999999941, + "trade_closed_at": "2023-03-25 02:00:00", + "trade_closed_price": 25758.385000000002, + "created_at": "2023-03-24 04:00:00", + "updated_at": "2023-03-24 06:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.072, + "amount": 17.231, + "net_gain": -6.151467000000004, + "trade_closed_at": "2023-02-09 20:00:00", + "trade_closed_price": 6.072, + "created_at": "2023-02-09 18:00:00", + "updated_at": "2023-02-09 20:00:00", + "filled": 17.231, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21172.035000000003, + "amount": 0.0051, + "net_gain": -2.4816854999999793, + "trade_closed_at": "2023-02-09 04:00:00", + "trade_closed_price": 21172.035000000003, + "created_at": "2023-02-09 02:00:00", + "updated_at": "2023-02-09 04:00:00", + "filled": 0.0051, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21658.64, + "amount": 0.0051, + "net_gain": -2.4816854999999793, + "trade_closed_at": "2023-02-09 04:00:00", + "trade_closed_price": 21172.035000000003, + "created_at": "2023-02-07 22:00:00", + "updated_at": "2023-02-08 00:00:00", + "filled": 0.0051, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.429, + "amount": 17.231, + "net_gain": -6.151467000000004, + "trade_closed_at": "2023-02-09 20:00:00", + "trade_closed_price": 6.072, + "created_at": "2023-02-07 22:00:00", + "updated_at": "2023-02-08 02:00:00", + "filled": 17.231, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.131, + "amount": 18.4906, + "net_gain": 3.106420800000019, + "trade_closed_at": "2023-02-06 00:00:00", + "trade_closed_price": 6.131, + "created_at": "2023-02-05 22:00:00", + "updated_at": "2023-02-06 00:00:00", + "filled": 18.4906, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21441.1, + "amount": 0.005, + "net_gain": -1.0294000000000052, + "trade_closed_at": "2023-02-05 16:00:00", + "trade_closed_price": 21441.1, + "created_at": "2023-02-05 14:00:00", + "updated_at": "2023-02-05 16:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.962999999999999, + "amount": 18.4906, + "net_gain": 3.106420800000019, + "trade_closed_at": "2023-02-06 00:00:00", + "trade_closed_price": 6.131, + "created_at": "2023-02-02 10:00:00", + "updated_at": "2023-02-02 12:00:00", + "filled": 18.4906, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21646.98, + "amount": 0.005, + "net_gain": -1.0294000000000052, + "trade_closed_at": "2023-02-05 16:00:00", + "trade_closed_price": 21441.1, + "created_at": "2023-02-02 04:00:00", + "updated_at": "2023-02-02 06:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20908.79, + "amount": 0.0052, + "net_gain": -1.5802279999999969, + "trade_closed_at": "2023-01-31 00:00:00", + "trade_closed_price": 20908.79, + "created_at": "2023-01-30 22:00:00", + "updated_at": "2023-01-31 00:00:00", + "filled": 0.0052, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.776, + "amount": 18.8685, + "net_gain": -2.226483000000006, + "trade_closed_at": "2023-01-30 16:00:00", + "trade_closed_price": 5.776, + "created_at": "2023-01-30 14:00:00", + "updated_at": "2023-01-30 16:00:00", + "filled": 18.8685, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.894, + "amount": 18.8685, + "net_gain": -2.226483000000006, + "trade_closed_at": "2023-01-30 16:00:00", + "trade_closed_price": 5.776, + "created_at": "2023-01-26 12:00:00", + "updated_at": "2023-01-26 14:00:00", + "filled": 18.8685, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21212.68, + "amount": 0.0052, + "net_gain": -1.5802279999999969, + "trade_closed_at": "2023-01-31 00:00:00", + "trade_closed_price": 20908.79, + "created_at": "2023-01-26 04:00:00", + "updated_at": "2023-01-26 06:00:00", + "filled": 0.0052, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.6370000000000005, + "amount": 19.5136, + "net_gain": 0.11708160000000443, + "trade_closed_at": "2023-01-25 04:00:00", + "trade_closed_price": 5.6370000000000005, + "created_at": "2023-01-25 02:00:00", + "updated_at": "2023-01-25 04:00:00", + "filled": 19.5136, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20697.87, + "amount": 0.0055, + "net_gain": 5.202477499999993, + "trade_closed_at": "2023-01-25 02:00:00", + "trade_closed_price": 20697.87, + "created_at": "2023-01-25 00:00:00", + "updated_at": "2023-01-25 02:00:00", + "filled": 0.0055, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.631, + "amount": 19.5136, + "net_gain": 0.11708160000000443, + "trade_closed_at": "2023-01-25 04:00:00", + "trade_closed_price": 5.6370000000000005, + "created_at": "2023-01-20 20:00:00", + "updated_at": "2023-01-20 22:00:00", + "filled": 19.5136, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19751.965, + "amount": 0.0055, + "net_gain": 5.202477499999993, + "trade_closed_at": "2023-01-25 02:00:00", + "trade_closed_price": 20697.87, + "created_at": "2023-01-20 18:00:00", + "updated_at": "2023-01-20 20:00:00", + "filled": 0.0055, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19220.955, + "amount": 0.0062, + "net_gain": 19.894312000000014, + "trade_closed_at": "2023-01-19 04:00:00", + "trade_closed_price": 19220.955, + "created_at": "2023-01-19 02:00:00", + "updated_at": "2023-01-19 04:00:00", + "filled": 0.0062, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.28, + "amount": 22.7405, + "net_gain": 20.216304500000007, + "trade_closed_at": "2023-01-16 16:00:00", + "trade_closed_price": 5.28, + "created_at": "2023-01-16 14:00:00", + "updated_at": "2023-01-16 16:00:00", + "filled": 22.7405, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16012.195, + "amount": 0.0062, + "net_gain": 19.894312000000014, + "trade_closed_at": "2023-01-19 04:00:00", + "trade_closed_price": 19220.955, + "created_at": "2023-01-08 22:00:00", + "updated_at": "2023-01-09 00:00:00", + "filled": 0.0062, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.391, + "amount": 22.7405, + "net_gain": 20.216304500000007, + "trade_closed_at": "2023-01-16 16:00:00", + "trade_closed_price": 5.28, + "created_at": "2023-01-08 12:00:00", + "updated_at": "2023-01-08 14:00:00", + "filled": 22.7405, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15778.795, + "amount": 0.0063, + "net_gain": -0.4691925000000023, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 18:00:00", + "updated_at": "2022-12-26 20:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15853.27, + "amount": 0.0063, + "net_gain": -0.4691925000000023, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 06:00:00", + "updated_at": "2022-12-26 08:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15831.685000000001, + "amount": 0.0063, + "net_gain": -0.1164554999999922, + "trade_closed_at": "2022-12-25 04:00:00", + "trade_closed_price": 15831.685000000001, + "created_at": "2022-12-25 02:00:00", + "updated_at": "2022-12-25 04:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15850.17, + "amount": 0.0063, + "net_gain": -0.1164554999999922, + "trade_closed_at": "2022-12-25 04:00:00", + "trade_closed_price": 15831.685000000001, + "created_at": "2022-12-24 18:00:00", + "updated_at": "2022-12-24 20:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + } + ], + "created_at": "2024-04-25 13:53:13" +} \ No newline at end of file diff --git a/tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-21 23:33:42.csv b/tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-21 23:33:42.csv deleted file mode 100644 index 92f441b3..00000000 --- a/tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-21 23:33:42.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -10-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,18,3,,33.33333333333333,55.55555555555556,8,2,202.82403499999998,3.7154006500000203,14.861602600000083,400.0,EUR,2.850797774999999,11.403191099999995,,414.8616026000001,118.75,100.53243475 diff --git a/tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-22 00:17:23.csv b/tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-22 00:17:23.csv deleted file mode 100644 index 92f441b3..00000000 --- a/tests/resources/backtest_reports_for_testing/report_10-75-1502024-03-22 00:17:23.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -10-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,18,3,,33.33333333333333,55.55555555555556,8,2,202.82403499999998,3.7154006500000203,14.861602600000083,400.0,EUR,2.850797774999999,11.403191099999995,,414.8616026000001,118.75,100.53243475 diff --git a/tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-21 23:33:09.csv b/tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-21 23:33:09.csv deleted file mode 100644 index c34ae60b..00000000 --- a/tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-21 23:33:09.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -11-50-100,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,38,3,,26.31578947368421,68.42105263157895,18,2,195.49798909999998,-0.2006302249999834,-0.8025208999999336,400.0,EUR,-1.027895275000012,-4.111581100000048,,399.19747910000007,60.55555555555556,97.61557944999998 diff --git a/tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-22 00:16:48.csv b/tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-22 00:16:48.csv deleted file mode 100644 index c34ae60b..00000000 --- a/tests/resources/backtest_reports_for_testing/report_11-50-1002024-03-22 00:16:48.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -11-50-100,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,38,3,,26.31578947368421,68.42105263157895,18,2,195.49798909999998,-0.2006302249999834,-0.8025208999999336,400.0,EUR,-1.027895275000012,-4.111581100000048,,399.19747910000007,60.55555555555556,97.61557944999998 diff --git a/tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-21 23:33:58.csv b/tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-21 23:33:58.csv deleted file mode 100644 index dc4cec32..00000000 --- a/tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-21 23:33:58.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -11-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,18,3,,33.33333333333333,55.55555555555556,8,2,203.05743735,3.7441725500000014,14.976690200000007,400.0,EUR,2.9204444874999975,11.68177794999999,,414.9766902,118.75,100.53202069374998 diff --git a/tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-22 00:17:44.csv b/tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-22 00:17:44.csv deleted file mode 100644 index dc4cec32..00000000 --- a/tests/resources/backtest_reports_for_testing/report_11-75-1502024-03-22 00:17:44.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -11-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,18,3,,33.33333333333333,55.55555555555556,8,2,203.05743735,3.7441725500000014,14.976690200000007,400.0,EUR,2.9204444874999975,11.68177794999999,,414.9766902,118.75,100.53202069374998 diff --git a/tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-21 23:34:15.csv b/tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-21 23:34:15.csv deleted file mode 100644 index f7b95247..00000000 --- a/tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-21 23:34:15.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -20-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,12,3,,50.0,33.33333333333333,5,2,209.63473159999995,5.918960150000032,23.67584060000013,400.0,EUR,5.262716899999997,21.05086759999999,,423.67584060000013,154.0,99.10319362 diff --git a/tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-22 00:18:06.csv b/tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-22 00:18:06.csv deleted file mode 100644 index f7b95247..00000000 --- a/tests/resources/backtest_reports_for_testing/report_20-75-1502024-03-22 00:18:06.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -20-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,12,3,,50.0,33.33333333333333,5,2,209.63473159999995,5.918960150000032,23.67584060000013,400.0,EUR,5.262716899999997,21.05086759999999,,423.67584060000013,154.0,99.10319362 diff --git a/tests/resources/backtest_reports_for_testing/report_20-75-2002024-03-22 00:20:26.csv b/tests/resources/backtest_reports_for_testing/report_20-75-2002024-03-22 00:20:26.csv deleted file mode 100644 index 5fafee41..00000000 --- a/tests/resources/backtest_reports_for_testing/report_20-75-2002024-03-22 00:20:26.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -20-75-200,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,13,2,,46.15384615384615,46.15384615384615,6,1,104.37204,5.233143525000003,20.93257410000001,400.0,EUR,4.616204774999999,18.464819099999996,,420.9325741,155.33333333333334,100.79321844166667 diff --git a/tests/resources/backtest_reports_for_testing/report_21-75-1502024-03-22 00:18:27.csv b/tests/resources/backtest_reports_for_testing/report_21-75-1502024-03-22 00:18:27.csv deleted file mode 100644 index 25d11ae4..00000000 --- a/tests/resources/backtest_reports_for_testing/report_21-75-1502024-03-22 00:18:27.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -21-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,10,3,,60.0,20.0,4,2,209.49562075,6.695456825000008,26.78182730000003,400.0,EUR,5.855954637500005,23.42381855000002,,426.78182730000003,191.0,98.87281781249999 diff --git a/tests/resources/backtest_reports_for_testing/report_21-75-2002024-03-22 00:20:54.csv b/tests/resources/backtest_reports_for_testing/report_21-75-2002024-03-22 00:20:54.csv deleted file mode 100644 index 50d79f01..00000000 --- a/tests/resources/backtest_reports_for_testing/report_21-75-2002024-03-22 00:20:54.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -21-75-200,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,13,2,,46.15384615384615,46.15384615384615,6,1,103.34110500000004,6.636504387499982,26.54601754999993,400.0,EUR,5.761831887499997,23.047327549999988,,426.54601754999993,172.0,101.741479175 diff --git a/tests/resources/backtest_reports_for_testing/report_22-75-1502024-03-22 00:18:47.csv b/tests/resources/backtest_reports_for_testing/report_22-75-1502024-03-22 00:18:47.csv deleted file mode 100644 index 8a2ad3b6..00000000 --- a/tests/resources/backtest_reports_for_testing/report_22-75-1502024-03-22 00:18:47.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -22-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,8,3,,75.0,0.0,3,2,209.400554,6.942043949999971,27.76817579999988,400.0,EUR,6.034142700000007,24.13657080000003,,427.7681757999999,254.0,99.13892541666667 diff --git a/tests/resources/backtest_reports_for_testing/report_22-75-2002024-03-22 00:21:15.csv b/tests/resources/backtest_reports_for_testing/report_22-75-2002024-03-22 00:21:15.csv deleted file mode 100644 index 18491118..00000000 --- a/tests/resources/backtest_reports_for_testing/report_22-75-2002024-03-22 00:21:15.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -22-75-200,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,13,2,,46.15384615384615,46.15384615384615,6,1,103.34110500000004,6.636504387499982,26.54601754999993,400.0,EUR,5.761831887499997,23.047327549999988,,426.54601754999993,172.0,101.741479175 diff --git a/tests/resources/backtest_reports_for_testing/report_23-75-1502024-03-22 00:19:10.csv b/tests/resources/backtest_reports_for_testing/report_23-75-1502024-03-22 00:19:10.csv deleted file mode 100644 index f04f19bf..00000000 --- a/tests/resources/backtest_reports_for_testing/report_23-75-1502024-03-22 00:19:10.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -23-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,8,3,,75.0,0.0,3,2,209.30213260000002,6.843549550000006,27.374198200000023,400.0,EUR,5.935685050000003,23.74274020000001,,427.3741982,253.33333333333334,99.18567791666668 diff --git a/tests/resources/backtest_reports_for_testing/report_23-75-2002024-03-22 00:21:38.csv b/tests/resources/backtest_reports_for_testing/report_23-75-2002024-03-22 00:21:38.csv deleted file mode 100644 index 820b6564..00000000 --- a/tests/resources/backtest_reports_for_testing/report_23-75-2002024-03-22 00:21:38.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -23-75-200,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,13,2,,46.15384615384615,46.15384615384615,6,1,103.34110500000004,6.636504387499982,26.54601754999993,400.0,EUR,5.761831887499997,23.047327549999988,,426.54601754999993,172.0,101.741479175 diff --git a/tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-21 23:34:30.csv b/tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-21 23:34:30.csv deleted file mode 100644 index ce6f0cb3..00000000 --- a/tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-21 23:34:30.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -24-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,10,3,,60.0,20.0,4,2,208.94325000000003,6.516407424999997,26.065629699999988,400.0,EUR,5.602303675000002,22.409214700000007,,426.0656297,205.0,99.444293275 diff --git a/tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-22 00:19:34.csv b/tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-22 00:19:34.csv deleted file mode 100644 index ce6f0cb3..00000000 --- a/tests/resources/backtest_reports_for_testing/report_24-75-1502024-03-22 00:19:34.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -24-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,10,3,,60.0,20.0,4,2,208.94325000000003,6.516407424999997,26.065629699999988,400.0,EUR,5.602303675000002,22.409214700000007,,426.0656297,205.0,99.444293275 diff --git a/tests/resources/backtest_reports_for_testing/report_24-75-2002024-03-22 00:22:00.csv b/tests/resources/backtest_reports_for_testing/report_24-75-2002024-03-22 00:22:00.csv deleted file mode 100644 index b0346c72..00000000 --- a/tests/resources/backtest_reports_for_testing/report_24-75-2002024-03-22 00:22:00.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -24-75-200,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,13,2,,46.15384615384615,46.15384615384615,6,1,103.34110500000004,6.636504387499982,26.54601754999993,400.0,EUR,5.761831887499997,23.047327549999988,,426.54601754999993,172.0,101.741479175 diff --git a/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-21 23:34:46.csv b/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-21 23:34:46.csv deleted file mode 100644 index 1a72caba..00000000 --- a/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-21 23:34:46.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -25-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,10,3,,60.0,20.0,4,2,209.02241725,6.757128025000014,27.028512100000057,400.0,EUR,5.810640212499995,23.24256084999998,,427.02851210000006,204.5,98.82267235 diff --git a/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:19:55.csv b/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:19:55.csv deleted file mode 100644 index 1a72caba..00000000 --- a/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:19:55.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -25-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,10,3,,60.0,20.0,4,2,209.02241725,6.757128025000014,27.028512100000057,400.0,EUR,5.810640212499995,23.24256084999998,,427.02851210000006,204.5,98.82267235 diff --git a/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:22:22.csv b/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:22:22.csv deleted file mode 100644 index 1a72caba..00000000 --- a/tests/resources/backtest_reports_for_testing/report_25-75-1502024-03-22 00:22:22.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -25-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,10,3,,60.0,20.0,4,2,209.02241725,6.757128025000014,27.028512100000057,400.0,EUR,5.810640212499995,23.24256084999998,,427.02851210000006,204.5,98.82267235 diff --git a/tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-21 23:32:32.csv b/tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-21 23:32:32.csv deleted file mode 100644 index 3a4f0baf..00000000 --- a/tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-21 23:32:32.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -9-50-100,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,36,3,,22.22222222222222,72.22222222222221,17,2,194.85166639999997,-0.7483954375000508,-2.993581750000203,400.0,EUR,-1.5952976375000125,-6.38119055000005,,397.0064182499998,64.58823529411765,97.6909654882353 diff --git a/tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-22 00:16:10.csv b/tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-22 00:16:10.csv deleted file mode 100644 index 3a4f0baf..00000000 --- a/tests/resources/backtest_reports_for_testing/report_9-50-1002024-03-22 00:16:10.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -9-50-100,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,36,3,,22.22222222222222,72.22222222222221,17,2,194.85166639999997,-0.7483954375000508,-2.993581750000203,400.0,EUR,-1.5952976375000125,-6.38119055000005,,397.0064182499998,64.58823529411765,97.6909654882353 diff --git a/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json b/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json new file mode 100644 index 00000000..7453611f --- /dev/null +++ b/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2021-12-21:00:00_backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json @@ -0,0 +1,1226 @@ +{ + "name": "9-50-100", + "context": {}, + "strategy_identifiers": [], + "backtest_start_date": "2021-12-21 00:00:00", + "backtest_end_date": "2022-06-20 00:00:00", + "number_of_runs": 2173, + "symbols": null, + "market": null, + "number_of_days": 181, + "number_of_orders": 42, + "number_of_positions": 1, + "market_data_file": null, + "percentage_positive_trades": 42.857142857142854, + "percentage_negative_trades": 57.14285714285714, + "number_of_trades_closed": 21, + "number_of_trades_open": 0, + "total_cost": 2.842170943040401e-14, + "growth_rate": 2.6784702499999753, + "growth": 10.713880999999901, + "initial_unallocated": 400.0, + "trading_symbol": "EUR", + "total_net_gain_percentage": 2.6784702499999953, + "total_net_gain": 10.713880999999981, + "total_value": 410.7138809999999, + "average_trade_duration": 62.95238095238095, + "average_trade_size": 100.48173273809523, + "positions": [ + { + "symbol": "EUR", + "amount": 410.7138809999999, + "cost": 410.7138809999999, + "price": 1, + "value": 410.7138809999999, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0.0, + "amount_pending_sell": 0.0, + "percentage_of_portfolio": 100.0 + }, + { + "symbol": "BTC", + "amount": 0.0, + "cost": 0.0, + "price": 19235.629999999997, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + }, + { + "symbol": "DOT", + "amount": 0.0, + "cost": 0.0, + "price": 7.045, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + } + ], + "trades": [ + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0036, + "open_price": 28481.28, + "current_price": 19235.629999999997, + "closed_price": 27562.52, + "opened_at": "2022-05-20 04:00:00", + "closed_at": "2022-05-20 20:00:00", + "change": 0, + "absolute_change": -3.307535999999999 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 10.0637, + "open_price": 10.215, + "current_price": 7.045, + "closed_price": 10.495000000000001, + "opened_at": "2022-05-17 16:00:00", + "closed_at": "2022-05-18 00:00:00", + "change": 0, + "absolute_change": 2.817836000000014 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 9.8057, + "open_price": 10.525, + "current_price": 7.045, + "closed_price": 10.36, + "opened_at": "2022-05-17 12:00:00", + "closed_at": "2022-05-17 16:00:00", + "change": 0, + "absolute_change": -1.6179405000000031 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.9151, + "open_price": 17.62, + "current_price": 7.045, + "closed_price": 16.93, + "opened_at": "2022-04-23 20:00:00", + "closed_at": "2022-04-24 22:00:00", + "change": 0, + "absolute_change": -4.081419000000011 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 6.191, + "open_price": 16.795, + "current_price": 7.045, + "closed_price": 16.955, + "opened_at": "2022-04-19 08:00:00", + "closed_at": "2022-04-22 08:00:00", + "change": 0, + "absolute_change": 0.9905599999999879 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0024, + "open_price": 42244.905, + "current_price": 19235.629999999997, + "closed_price": 41553.785, + "opened_at": "2022-04-02 08:00:00", + "closed_at": "2022-04-03 04:00:00", + "change": 0, + "absolute_change": -1.6586879999999837 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.1517, + "open_price": 20.295, + "current_price": 7.045, + "closed_price": 20.17, + "opened_at": "2022-04-02 06:00:00", + "closed_at": "2022-04-06 00:00:00", + "change": 0, + "absolute_change": -0.6439625000000007 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.1865, + "open_price": 20.39, + "current_price": 7.045, + "closed_price": 19.465, + "opened_at": "2022-03-31 06:00:00", + "closed_at": "2022-03-31 18:00:00", + "change": 0, + "absolute_change": -4.7975125000000105 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.135, + "open_price": 20.195, + "current_price": 7.045, + "closed_price": 20.16, + "opened_at": "2022-03-30 16:00:00", + "closed_at": "2022-03-31 00:00:00", + "change": 0, + "absolute_change": -0.1797250000000048 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0025, + "open_price": 38909.95, + "current_price": 19235.629999999997, + "closed_price": 42264.625, + "opened_at": "2022-03-22 04:00:00", + "closed_at": "2022-03-31 02:00:00", + "change": 0, + "absolute_change": 8.386687500000008 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.7464, + "open_price": 17.479999999999997, + "current_price": 7.045, + "closed_price": 19.745, + "opened_at": "2022-03-22 02:00:00", + "closed_at": "2022-03-30 16:00:00", + "change": 0, + "absolute_change": 13.015596000000016 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 6.0356, + "open_price": 16.575, + "current_price": 7.045, + "closed_price": 16.845, + "opened_at": "2022-03-16 06:00:00", + "closed_at": "2022-03-20 20:00:00", + "change": 0, + "absolute_change": 1.6296119999999945 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0027, + "open_price": 36619.759999999995, + "current_price": 19235.629999999997, + "closed_price": 37376.525, + "opened_at": "2022-02-28 16:00:00", + "closed_at": "2022-03-04 06:00:00", + "change": 0, + "absolute_change": 2.043265500000018 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.0966, + "open_price": 19.27, + "current_price": 7.045, + "closed_price": 18.945, + "opened_at": "2022-02-09 22:00:00", + "closed_at": "2022-02-10 14:00:00", + "change": 0, + "absolute_change": -1.6563949999999892 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.4971, + "open_price": 17.615000000000002, + "current_price": 7.045, + "closed_price": 18.619999999999997, + "opened_at": "2022-02-04 20:00:00", + "closed_at": "2022-02-08 20:00:00", + "change": 0, + "absolute_change": 5.524585499999972 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0027, + "open_price": 35449.845, + "current_price": 19235.629999999997, + "closed_price": 38013.615, + "opened_at": "2022-02-04 18:00:00", + "closed_at": "2022-02-11 10:00:00", + "change": 0, + "absolute_change": 6.922178999999986 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0028, + "open_price": 34335.1, + "current_price": 19235.629999999997, + "closed_price": 33083.82, + "opened_at": "2022-01-31 22:00:00", + "closed_at": "2022-02-02 18:00:00", + "change": 0, + "absolute_change": -3.5035839999999894 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 5.718, + "open_price": 17.345, + "current_price": 7.045, + "closed_price": 16.314999999999998, + "opened_at": "2022-01-31 22:00:00", + "closed_at": "2022-02-03 06:00:00", + "change": 0, + "absolute_change": -5.889540000000011 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0026, + "open_price": 37953.66, + "current_price": 19235.629999999997, + "closed_price": 37551.8, + "opened_at": "2022-01-16 16:00:00", + "closed_at": "2022-01-17 04:00:00", + "change": 0, + "absolute_change": -1.0448360000000037 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0026, + "open_price": 37669.43, + "current_price": 19235.629999999997, + "closed_price": 37931.085, + "opened_at": "2022-01-15 04:00:00", + "closed_at": "2022-01-16 16:00:00", + "change": 0, + "absolute_change": 0.680302999999995 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0022, + "open_price": 44841.240000000005, + "current_price": 19235.629999999997, + "closed_price": 43515.965, + "opened_at": "2021-12-27 00:00:00", + "closed_at": "2021-12-28 06:00:00", + "change": 0, + "absolute_change": -2.9156050000000135 + } + ], + "orders": [ + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 27562.52, + "amount": 0.0036, + "net_gain": -3.307535999999994, + "trade_closed_at": "2022-05-20 20:00:00", + "trade_closed_price": 27562.52, + "created_at": "2022-05-20 18:00:00", + "updated_at": "2022-05-20 20:00:00", + "filled": 0.0036, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 28481.28, + "amount": 0.0036, + "net_gain": -3.307535999999994, + "trade_closed_at": "2022-05-20 20:00:00", + "trade_closed_price": 27562.52, + "created_at": "2022-05-20 04:00:00", + "updated_at": "2022-05-20 06:00:00", + "filled": 0.0036, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 10.495000000000001, + "amount": 10.0637, + "net_gain": 2.8178360000000118, + "trade_closed_at": "2022-05-18 00:00:00", + "trade_closed_price": 10.495000000000001, + "created_at": "2022-05-17 22:00:00", + "updated_at": "2022-05-18 00:00:00", + "filled": 10.0637, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 10.215, + "amount": 10.0637, + "net_gain": 2.8178360000000118, + "trade_closed_at": "2022-05-18 00:00:00", + "trade_closed_price": 10.495000000000001, + "created_at": "2022-05-17 16:00:00", + "updated_at": "2022-05-17 18:00:00", + "filled": 10.0637, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 10.36, + "amount": 9.8057, + "net_gain": -1.617940500000009, + "trade_closed_at": "2022-05-17 16:00:00", + "trade_closed_price": 10.36, + "created_at": "2022-05-17 14:00:00", + "updated_at": "2022-05-17 16:00:00", + "filled": 9.8057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 10.525, + "amount": 9.8057, + "net_gain": -1.617940500000009, + "trade_closed_at": "2022-05-17 16:00:00", + "trade_closed_price": 10.36, + "created_at": "2022-05-17 12:00:00", + "updated_at": "2022-05-17 14:00:00", + "filled": 9.8057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.93, + "amount": 5.9151, + "net_gain": -4.0814190000000075, + "trade_closed_at": "2022-04-24 22:00:00", + "trade_closed_price": 16.93, + "created_at": "2022-04-24 20:00:00", + "updated_at": "2022-04-24 22:00:00", + "filled": 5.9151, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.62, + "amount": 5.9151, + "net_gain": -4.0814190000000075, + "trade_closed_at": "2022-04-24 22:00:00", + "trade_closed_price": 16.93, + "created_at": "2022-04-23 20:00:00", + "updated_at": "2022-04-23 22:00:00", + "filled": 5.9151, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.955, + "amount": 6.191, + "net_gain": 0.9905599999999789, + "trade_closed_at": "2022-04-22 08:00:00", + "trade_closed_price": 16.955, + "created_at": "2022-04-22 06:00:00", + "updated_at": "2022-04-22 08:00:00", + "filled": 6.191, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.795, + "amount": 6.191, + "net_gain": 0.9905599999999789, + "trade_closed_at": "2022-04-22 08:00:00", + "trade_closed_price": 16.955, + "created_at": "2022-04-19 08:00:00", + "updated_at": "2022-04-19 10:00:00", + "filled": 6.191, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.17, + "amount": 5.1517, + "net_gain": -0.6439625, + "trade_closed_at": "2022-04-06 00:00:00", + "trade_closed_price": 20.17, + "created_at": "2022-04-05 22:00:00", + "updated_at": "2022-04-06 00:00:00", + "filled": 5.1517, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 41553.785, + "amount": 0.0024, + "net_gain": -1.6586879999999886, + "trade_closed_at": "2022-04-03 04:00:00", + "trade_closed_price": 41553.785, + "created_at": "2022-04-03 02:00:00", + "updated_at": "2022-04-03 04:00:00", + "filled": 0.0024, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 42244.905, + "amount": 0.0024, + "net_gain": -1.6586879999999886, + "trade_closed_at": "2022-04-03 04:00:00", + "trade_closed_price": 41553.785, + "created_at": "2022-04-02 08:00:00", + "updated_at": "2022-04-02 10:00:00", + "filled": 0.0024, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.295, + "amount": 5.1517, + "net_gain": -0.6439625, + "trade_closed_at": "2022-04-06 00:00:00", + "trade_closed_price": 20.17, + "created_at": "2022-04-02 06:00:00", + "updated_at": "2022-04-02 08:00:00", + "filled": 5.1517, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19.465, + "amount": 5.1865, + "net_gain": -4.797512500000003, + "trade_closed_at": "2022-03-31 18:00:00", + "trade_closed_price": 19.465, + "created_at": "2022-03-31 16:00:00", + "updated_at": "2022-03-31 18:00:00", + "filled": 5.1865, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.39, + "amount": 5.1865, + "net_gain": -4.797512500000003, + "trade_closed_at": "2022-03-31 18:00:00", + "trade_closed_price": 19.465, + "created_at": "2022-03-31 06:00:00", + "updated_at": "2022-03-31 08:00:00", + "filled": 5.1865, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 42264.625, + "amount": 0.0025, + "net_gain": 8.386687500000008, + "trade_closed_at": "2022-03-31 02:00:00", + "trade_closed_price": 42264.625, + "created_at": "2022-03-31 00:00:00", + "updated_at": "2022-03-31 02:00:00", + "filled": 0.0025, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.16, + "amount": 5.135, + "net_gain": -0.17972500000000072, + "trade_closed_at": "2022-03-31 00:00:00", + "trade_closed_price": 20.16, + "created_at": "2022-03-30 22:00:00", + "updated_at": "2022-03-31 00:00:00", + "filled": 5.135, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20.195, + "amount": 5.135, + "net_gain": -0.17972500000000072, + "trade_closed_at": "2022-03-31 00:00:00", + "trade_closed_price": 20.16, + "created_at": "2022-03-30 16:00:00", + "updated_at": "2022-03-30 18:00:00", + "filled": 5.135, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19.745, + "amount": 5.7464, + "net_gain": 13.015596000000025, + "trade_closed_at": "2022-03-30 16:00:00", + "trade_closed_price": 19.745, + "created_at": "2022-03-30 14:00:00", + "updated_at": "2022-03-30 16:00:00", + "filled": 5.7464, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 38909.95, + "amount": 0.0025, + "net_gain": 8.386687500000008, + "trade_closed_at": "2022-03-31 02:00:00", + "trade_closed_price": 42264.625, + "created_at": "2022-03-22 04:00:00", + "updated_at": "2022-03-22 06:00:00", + "filled": 0.0025, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.479999999999997, + "amount": 5.7464, + "net_gain": 13.015596000000025, + "trade_closed_at": "2022-03-30 16:00:00", + "trade_closed_price": 19.745, + "created_at": "2022-03-22 02:00:00", + "updated_at": "2022-03-22 04:00:00", + "filled": 5.7464, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.845, + "amount": 6.0356, + "net_gain": 1.6296119999999974, + "trade_closed_at": "2022-03-20 20:00:00", + "trade_closed_price": 16.845, + "created_at": "2022-03-20 18:00:00", + "updated_at": "2022-03-20 20:00:00", + "filled": 6.0356, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.575, + "amount": 6.0356, + "net_gain": 1.6296119999999974, + "trade_closed_at": "2022-03-20 20:00:00", + "trade_closed_price": 16.845, + "created_at": "2022-03-16 06:00:00", + "updated_at": "2022-03-16 08:00:00", + "filled": 6.0356, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37376.525, + "amount": 0.0027, + "net_gain": 2.043265500000018, + "trade_closed_at": "2022-03-04 06:00:00", + "trade_closed_price": 37376.525, + "created_at": "2022-03-04 04:00:00", + "updated_at": "2022-03-04 06:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 36619.759999999995, + "amount": 0.0027, + "net_gain": 2.043265500000018, + "trade_closed_at": "2022-03-04 06:00:00", + "trade_closed_price": 37376.525, + "created_at": "2022-02-28 16:00:00", + "updated_at": "2022-02-28 18:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 38013.615, + "amount": 0.0027, + "net_gain": 6.922178999999992, + "trade_closed_at": "2022-02-11 10:00:00", + "trade_closed_price": 38013.615, + "created_at": "2022-02-11 08:00:00", + "updated_at": "2022-02-11 10:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 18.945, + "amount": 5.0966, + "net_gain": -1.6563949999999963, + "trade_closed_at": "2022-02-10 14:00:00", + "trade_closed_price": 18.945, + "created_at": "2022-02-10 12:00:00", + "updated_at": "2022-02-10 14:00:00", + "filled": 5.0966, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19.27, + "amount": 5.0966, + "net_gain": -1.6563949999999963, + "trade_closed_at": "2022-02-10 14:00:00", + "trade_closed_price": 18.945, + "created_at": "2022-02-09 22:00:00", + "updated_at": "2022-02-10 00:00:00", + "filled": 5.0966, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 18.619999999999997, + "amount": 5.4971, + "net_gain": 5.524585499999975, + "trade_closed_at": "2022-02-08 20:00:00", + "trade_closed_price": 18.619999999999997, + "created_at": "2022-02-08 18:00:00", + "updated_at": "2022-02-08 20:00:00", + "filled": 5.4971, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.615000000000002, + "amount": 5.4971, + "net_gain": 5.524585499999975, + "trade_closed_at": "2022-02-08 20:00:00", + "trade_closed_price": 18.619999999999997, + "created_at": "2022-02-04 20:00:00", + "updated_at": "2022-02-04 22:00:00", + "filled": 5.4971, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 35449.845, + "amount": 0.0027, + "net_gain": 6.922178999999992, + "trade_closed_at": "2022-02-11 10:00:00", + "trade_closed_price": 38013.615, + "created_at": "2022-02-04 18:00:00", + "updated_at": "2022-02-04 20:00:00", + "filled": 0.0027, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16.314999999999998, + "amount": 5.718, + "net_gain": -5.889540000000006, + "trade_closed_at": "2022-02-03 06:00:00", + "trade_closed_price": 16.314999999999998, + "created_at": "2022-02-03 04:00:00", + "updated_at": "2022-02-03 06:00:00", + "filled": 5.718, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 33083.82, + "amount": 0.0028, + "net_gain": -3.503583999999997, + "trade_closed_at": "2022-02-02 18:00:00", + "trade_closed_price": 33083.82, + "created_at": "2022-02-02 16:00:00", + "updated_at": "2022-02-02 18:00:00", + "filled": 0.0028, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 34335.1, + "amount": 0.0028, + "net_gain": -3.503583999999997, + "trade_closed_at": "2022-02-02 18:00:00", + "trade_closed_price": 33083.82, + "created_at": "2022-01-31 22:00:00", + "updated_at": "2022-02-01 00:00:00", + "filled": 0.0028, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 17.345, + "amount": 5.718, + "net_gain": -5.889540000000006, + "trade_closed_at": "2022-02-03 06:00:00", + "trade_closed_price": 16.314999999999998, + "created_at": "2022-01-31 22:00:00", + "updated_at": "2022-02-01 02:00:00", + "filled": 5.718, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37551.8, + "amount": 0.0026, + "net_gain": -1.0448360000000014, + "trade_closed_at": "2022-01-17 04:00:00", + "trade_closed_price": 37551.8, + "created_at": "2022-01-17 02:00:00", + "updated_at": "2022-01-17 04:00:00", + "filled": 0.0026, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37953.66, + "amount": 0.0026, + "net_gain": -1.0448360000000014, + "trade_closed_at": "2022-01-17 04:00:00", + "trade_closed_price": 37551.8, + "created_at": "2022-01-16 16:00:00", + "updated_at": "2022-01-16 18:00:00", + "filled": 0.0026, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37931.085, + "amount": 0.0026, + "net_gain": 0.680302999999997, + "trade_closed_at": "2022-01-16 16:00:00", + "trade_closed_price": 37931.085, + "created_at": "2022-01-16 14:00:00", + "updated_at": "2022-01-16 16:00:00", + "filled": 0.0026, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 37669.43, + "amount": 0.0026, + "net_gain": 0.680302999999997, + "trade_closed_at": "2022-01-16 16:00:00", + "trade_closed_price": 37931.085, + "created_at": "2022-01-15 04:00:00", + "updated_at": "2022-01-15 06:00:00", + "filled": 0.0026, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 43515.965, + "amount": 0.0022, + "net_gain": -2.9156050000000193, + "trade_closed_at": "2021-12-28 06:00:00", + "trade_closed_price": 43515.965, + "created_at": "2021-12-28 04:00:00", + "updated_at": "2021-12-28 06:00:00", + "filled": 0.0022, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 44841.240000000005, + "amount": 0.0022, + "net_gain": -2.9156050000000193, + "trade_closed_at": "2021-12-28 06:00:00", + "trade_closed_price": 43515.965, + "created_at": "2021-12-27 00:00:00", + "updated_at": "2021-12-27 02:00:00", + "filled": 0.0022, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + } + ], + "created_at": "2024-04-25 13:52:17" +} \ No newline at end of file diff --git a/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:53.json b/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:53.json new file mode 100644 index 00000000..f86eb134 --- /dev/null +++ b/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-06-10:00:00_backtest_end_date_2023-01-10:00:00_created_at_2024-04-25:13:53.json @@ -0,0 +1,1459 @@ +{ + "name": "9-50-100", + "context": {}, + "strategy_identifiers": [], + "backtest_start_date": "2022-06-10 00:00:00", + "backtest_end_date": "2023-01-10 00:00:00", + "number_of_runs": 2569, + "symbols": null, + "market": null, + "number_of_days": 214, + "number_of_orders": 50, + "number_of_positions": 3, + "market_data_file": null, + "percentage_positive_trades": 20.0, + "percentage_negative_trades": 72.0, + "number_of_trades_closed": 24, + "number_of_trades_open": 2, + "total_cost": 186.85423839999999, + "growth_rate": -5.19176303750001, + "growth": -20.76705215000004, + "initial_unallocated": 400.0, + "trading_symbol": "EUR", + "total_net_gain_percentage": -6.016107249999995, + "total_net_gain": -24.06442899999998, + "total_value": 379.23294784999996, + "average_trade_duration": 50.25, + "average_trade_size": 96.4556, + "positions": [ + { + "symbol": "EUR", + "amount": 189.0813326, + "cost": 189.0813326, + "price": 1, + "value": 189.0813326, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0.0, + "amount_pending_sell": 0.0, + "percentage_of_portfolio": 49.85888849372559 + }, + { + "symbol": "BTC", + "amount": 0.0058, + "cost": 92.87073099999999, + "price": 16038.015, + "value": 93.02048699999999, + "growth": 0.14975599999999645, + "growth_rate": 0.161252095668329, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 24.528587910772163 + }, + { + "symbol": "DOT", + "amount": 21.1961, + "cost": 93.9835074, + "price": 4.5825, + "value": 97.13112825, + "growth": 3.14762085000001, + "growth_rate": 3.3491204330176023, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 25.612523595502257 + } + ], + "trades": [ + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "OPEN", + "amount": 0.0058, + "open_price": 16012.195, + "current_price": 16038.015, + "closed_price": null, + "opened_at": "2023-01-08 22:00:00", + "closed_at": null, + "change": 0.161252095668329, + "absolute_change": 0 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "OPEN", + "amount": 21.1961, + "open_price": 4.433999999999999, + "current_price": 4.5825, + "closed_price": null, + "opened_at": "2023-01-08 14:00:00", + "closed_at": null, + "change": 3.3491204330176023, + "absolute_change": 0 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15889.505000000001, + "current_price": 16038.015, + "closed_price": 15778.795, + "opened_at": "2022-12-26 04:00:00", + "closed_at": "2022-12-26 20:00:00", + "change": 0, + "absolute_change": -0.6531889999999976 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15828.42, + "current_price": 16038.015, + "closed_price": 15838.494999999999, + "opened_at": "2022-12-24 22:00:00", + "closed_at": "2022-12-25 02:00:00", + "change": 0, + "absolute_change": 0.05944250000000295 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15842.42, + "current_price": 16038.015, + "closed_price": 15837.505000000001, + "opened_at": "2022-12-24 16:00:00", + "closed_at": "2022-12-24 22:00:00", + "change": 0, + "absolute_change": -0.02899849999998594 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0057, + "open_price": 16423.975, + "current_price": 16038.015, + "closed_price": 16315.115, + "opened_at": "2022-12-13 08:00:00", + "closed_at": "2022-12-16 00:00:00", + "change": 0, + "absolute_change": -0.6205019999999877 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0058, + "open_price": 16282.18, + "current_price": 16038.015, + "closed_price": 16097.795, + "opened_at": "2022-12-09 02:00:00", + "closed_at": "2022-12-12 06:00:00", + "change": 0, + "absolute_change": -1.0694330000000036 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0058, + "open_price": 16182.045, + "current_price": 16038.015, + "closed_price": 16043.84, + "opened_at": "2022-12-06 16:00:00", + "closed_at": "2022-12-07 12:00:00", + "change": 0, + "absolute_change": -0.8015889999999928 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0058, + "open_price": 16295.425, + "current_price": 16038.015, + "closed_price": 16148.385, + "opened_at": "2022-12-05 00:00:00", + "closed_at": "2022-12-06 12:00:00", + "change": 0, + "absolute_change": -0.8528319999999923 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15842.86, + "current_price": 16038.015, + "closed_price": 16124.61, + "opened_at": "2022-11-29 16:00:00", + "closed_at": "2022-12-03 08:00:00", + "change": 0, + "absolute_change": 1.6623249999999956 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0059, + "open_price": 15928.48, + "current_price": 16038.015, + "closed_price": 15889.494999999999, + "opened_at": "2022-11-27 20:00:00", + "closed_at": "2022-11-28 00:00:00", + "change": 0, + "absolute_change": -0.23001150000000337 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 13.2656, + "open_price": 7.32, + "current_price": 4.5825, + "closed_price": 6.57, + "opened_at": "2022-11-07 20:00:00", + "closed_at": "2022-11-08 06:00:00", + "change": 0, + "absolute_change": -9.949200000000005 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 14.5159, + "open_price": 6.65, + "current_price": 4.5825, + "closed_price": 6.8100000000000005, + "opened_at": "2022-11-03 20:00:00", + "closed_at": "2022-11-07 12:00:00", + "change": 0, + "absolute_change": 2.3225440000000077 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0046, + "open_price": 20780.614999999998, + "current_price": 16038.015, + "closed_price": 20774.495000000003, + "opened_at": "2022-11-03 16:00:00", + "closed_at": "2022-11-07 10:00:00", + "change": 0, + "absolute_change": -0.028151999999977306 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0048, + "open_price": 19937.42, + "current_price": 16038.015, + "closed_price": 19530.1, + "opened_at": "2022-10-17 10:00:00", + "closed_at": "2022-10-19 00:00:00", + "change": 0, + "absolute_change": -1.955135999999996 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 14.9434, + "open_price": 6.529999999999999, + "current_price": 4.5825, + "closed_price": 6.38, + "opened_at": "2022-10-09 08:00:00", + "closed_at": "2022-10-11 02:00:00", + "change": 0, + "absolute_change": -2.241509999999991 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0048, + "open_price": 20098.595, + "current_price": 16038.015, + "closed_price": 19814.379999999997, + "opened_at": "2022-09-29 00:00:00", + "closed_at": "2022-09-29 18:00:00", + "change": 0, + "absolute_change": -1.3642320000000154 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 14.6593, + "open_price": 6.734999999999999, + "current_price": 4.5825, + "closed_price": 6.575, + "opened_at": "2022-09-26 14:00:00", + "closed_at": "2022-09-28 08:00:00", + "change": 0, + "absolute_change": -2.345487999999989 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.005, + "open_price": 19718.035, + "current_price": 16038.015, + "closed_price": 19539.96, + "opened_at": "2022-09-26 12:00:00", + "closed_at": "2022-09-28 10:00:00", + "change": 0, + "absolute_change": -0.8903750000000059 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 13.2524, + "open_price": 7.449999999999999, + "current_price": 4.5825, + "closed_price": 7.449999999999999, + "opened_at": "2022-09-09 02:00:00", + "closed_at": "2022-09-13 04:00:00", + "change": 0, + "absolute_change": 0.0 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0042, + "open_price": 23246.945, + "current_price": 16038.015, + "closed_price": 23675.2, + "opened_at": "2022-08-10 22:00:00", + "closed_at": "2022-08-15 22:00:00", + "change": 0, + "absolute_change": 1.798671000000013 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 10.6914, + "open_price": 9.275, + "current_price": 4.5825, + "closed_price": 8.945, + "opened_at": "2022-08-10 16:00:00", + "closed_at": "2022-08-14 16:00:00", + "change": 0, + "absolute_change": -3.5281619999999947 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 12.5214, + "open_price": 7.99, + "current_price": 4.5825, + "closed_price": 7.92, + "opened_at": "2022-08-04 00:00:00", + "closed_at": "2022-08-04 10:00:00", + "change": 0, + "absolute_change": -0.876497999999998 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0043, + "open_price": 23110.375, + "current_price": 16038.015, + "closed_price": 22492.04, + "opened_at": "2022-08-03 18:00:00", + "closed_at": "2022-08-04 12:00:00", + "change": 0, + "absolute_change": -2.6588404999999966 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 13.1926, + "open_price": 7.58, + "current_price": 4.5825, + "closed_price": 7.574999999999999, + "opened_at": "2022-06-24 02:00:00", + "closed_at": "2022-06-27 16:00:00", + "change": 0, + "absolute_change": -0.06596300000001065 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.005, + "open_price": 19840.89, + "current_price": 16038.015, + "closed_price": 19891.43, + "opened_at": "2022-06-23 20:00:00", + "closed_at": "2022-06-27 14:00:00", + "change": 0, + "absolute_change": 0.25270000000000437 + } + ], + "orders": [ + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16012.195, + "amount": 0.0058, + "net_gain": 0.0, + "trade_closed_at": null, + "trade_closed_price": null, + "created_at": "2023-01-08 22:00:00", + "updated_at": "2023-01-09 00:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.433999999999999, + "amount": 21.1961, + "net_gain": 0.0, + "trade_closed_at": null, + "trade_closed_price": null, + "created_at": "2023-01-08 14:00:00", + "updated_at": "2023-01-08 16:00:00", + "filled": 21.1961, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15778.795, + "amount": 0.0059, + "net_gain": -0.6531890000000056, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 18:00:00", + "updated_at": "2022-12-26 20:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15889.505000000001, + "amount": 0.0059, + "net_gain": -0.6531890000000056, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 04:00:00", + "updated_at": "2022-12-26 06:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15838.494999999999, + "amount": 0.0059, + "net_gain": 0.059442499999993556, + "trade_closed_at": "2022-12-25 02:00:00", + "trade_closed_price": 15838.494999999999, + "created_at": "2022-12-25 00:00:00", + "updated_at": "2022-12-25 02:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15828.42, + "amount": 0.0059, + "net_gain": 0.059442499999993556, + "trade_closed_at": "2022-12-25 02:00:00", + "trade_closed_price": 15838.494999999999, + "created_at": "2022-12-24 22:00:00", + "updated_at": "2022-12-25 00:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15837.505000000001, + "amount": 0.0059, + "net_gain": -0.028998499999994418, + "trade_closed_at": "2022-12-24 22:00:00", + "trade_closed_price": 15837.505000000001, + "created_at": "2022-12-24 20:00:00", + "updated_at": "2022-12-24 22:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15842.42, + "amount": 0.0059, + "net_gain": -0.028998499999994418, + "trade_closed_at": "2022-12-24 22:00:00", + "trade_closed_price": 15837.505000000001, + "created_at": "2022-12-24 16:00:00", + "updated_at": "2022-12-24 18:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16315.115, + "amount": 0.0057, + "net_gain": -0.620501999999993, + "trade_closed_at": "2022-12-16 00:00:00", + "trade_closed_price": 16315.115, + "created_at": "2022-12-15 22:00:00", + "updated_at": "2022-12-16 00:00:00", + "filled": 0.0057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16423.975, + "amount": 0.0057, + "net_gain": -0.620501999999993, + "trade_closed_at": "2022-12-16 00:00:00", + "trade_closed_price": 16315.115, + "created_at": "2022-12-13 08:00:00", + "updated_at": "2022-12-13 10:00:00", + "filled": 0.0057, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16097.795, + "amount": 0.0058, + "net_gain": -1.0694330000000012, + "trade_closed_at": "2022-12-12 06:00:00", + "trade_closed_price": 16097.795, + "created_at": "2022-12-12 04:00:00", + "updated_at": "2022-12-12 06:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16282.18, + "amount": 0.0058, + "net_gain": -1.0694330000000012, + "trade_closed_at": "2022-12-12 06:00:00", + "trade_closed_price": 16097.795, + "created_at": "2022-12-09 02:00:00", + "updated_at": "2022-12-09 04:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16043.84, + "amount": 0.0058, + "net_gain": -0.8015889999999996, + "trade_closed_at": "2022-12-07 12:00:00", + "trade_closed_price": 16043.84, + "created_at": "2022-12-07 10:00:00", + "updated_at": "2022-12-07 12:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16182.045, + "amount": 0.0058, + "net_gain": -0.8015889999999996, + "trade_closed_at": "2022-12-07 12:00:00", + "trade_closed_price": 16043.84, + "created_at": "2022-12-06 16:00:00", + "updated_at": "2022-12-06 18:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16148.385, + "amount": 0.0058, + "net_gain": -0.8528319999999945, + "trade_closed_at": "2022-12-06 12:00:00", + "trade_closed_price": 16148.385, + "created_at": "2022-12-06 10:00:00", + "updated_at": "2022-12-06 12:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16295.425, + "amount": 0.0058, + "net_gain": -0.8528319999999945, + "trade_closed_at": "2022-12-06 12:00:00", + "trade_closed_price": 16148.385, + "created_at": "2022-12-05 00:00:00", + "updated_at": "2022-12-05 02:00:00", + "filled": 0.0058, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16124.61, + "amount": 0.0059, + "net_gain": 1.662325, + "trade_closed_at": "2022-12-03 08:00:00", + "trade_closed_price": 16124.61, + "created_at": "2022-12-03 06:00:00", + "updated_at": "2022-12-03 08:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15842.86, + "amount": 0.0059, + "net_gain": 1.662325, + "trade_closed_at": "2022-12-03 08:00:00", + "trade_closed_price": 16124.61, + "created_at": "2022-11-29 16:00:00", + "updated_at": "2022-11-29 18:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15889.494999999999, + "amount": 0.0059, + "net_gain": -0.23001150000000342, + "trade_closed_at": "2022-11-28 00:00:00", + "trade_closed_price": 15889.494999999999, + "created_at": "2022-11-27 22:00:00", + "updated_at": "2022-11-28 00:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15928.48, + "amount": 0.0059, + "net_gain": -0.23001150000000342, + "trade_closed_at": "2022-11-28 00:00:00", + "trade_closed_price": 15889.494999999999, + "created_at": "2022-11-27 20:00:00", + "updated_at": "2022-11-27 22:00:00", + "filled": 0.0059, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.57, + "amount": 13.2656, + "net_gain": -9.9492, + "trade_closed_at": "2022-11-08 06:00:00", + "trade_closed_price": 6.57, + "created_at": "2022-11-08 04:00:00", + "updated_at": "2022-11-08 06:00:00", + "filled": 13.2656, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.32, + "amount": 13.2656, + "net_gain": -9.9492, + "trade_closed_at": "2022-11-08 06:00:00", + "trade_closed_price": 6.57, + "created_at": "2022-11-07 20:00:00", + "updated_at": "2022-11-07 22:00:00", + "filled": 13.2656, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.8100000000000005, + "amount": 14.5159, + "net_gain": 2.322544000000002, + "trade_closed_at": "2022-11-07 12:00:00", + "trade_closed_price": 6.8100000000000005, + "created_at": "2022-11-07 10:00:00", + "updated_at": "2022-11-07 12:00:00", + "filled": 14.5159, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20774.495000000003, + "amount": 0.0046, + "net_gain": -0.02815199999997858, + "trade_closed_at": "2022-11-07 10:00:00", + "trade_closed_price": 20774.495000000003, + "created_at": "2022-11-07 08:00:00", + "updated_at": "2022-11-07 10:00:00", + "filled": 0.0046, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.65, + "amount": 14.5159, + "net_gain": 2.322544000000002, + "trade_closed_at": "2022-11-07 12:00:00", + "trade_closed_price": 6.8100000000000005, + "created_at": "2022-11-03 20:00:00", + "updated_at": "2022-11-03 22:00:00", + "filled": 14.5159, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20780.614999999998, + "amount": 0.0046, + "net_gain": -0.02815199999997858, + "trade_closed_at": "2022-11-07 10:00:00", + "trade_closed_price": 20774.495000000003, + "created_at": "2022-11-03 16:00:00", + "updated_at": "2022-11-03 18:00:00", + "filled": 0.0046, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19530.1, + "amount": 0.0048, + "net_gain": -1.9551359999999984, + "trade_closed_at": "2022-10-19 00:00:00", + "trade_closed_price": 19530.1, + "created_at": "2022-10-18 22:00:00", + "updated_at": "2022-10-19 00:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19937.42, + "amount": 0.0048, + "net_gain": -1.9551359999999984, + "trade_closed_at": "2022-10-19 00:00:00", + "trade_closed_price": 19530.1, + "created_at": "2022-10-17 10:00:00", + "updated_at": "2022-10-17 12:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.38, + "amount": 14.9434, + "net_gain": -2.241509999999992, + "trade_closed_at": "2022-10-11 02:00:00", + "trade_closed_price": 6.38, + "created_at": "2022-10-11 00:00:00", + "updated_at": "2022-10-11 02:00:00", + "filled": 14.9434, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.529999999999999, + "amount": 14.9434, + "net_gain": -2.241509999999992, + "trade_closed_at": "2022-10-11 02:00:00", + "trade_closed_price": 6.38, + "created_at": "2022-10-09 08:00:00", + "updated_at": "2022-10-09 10:00:00", + "filled": 14.9434, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19814.379999999997, + "amount": 0.0048, + "net_gain": -1.364232000000018, + "trade_closed_at": "2022-09-29 18:00:00", + "trade_closed_price": 19814.379999999997, + "created_at": "2022-09-29 16:00:00", + "updated_at": "2022-09-29 18:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20098.595, + "amount": 0.0048, + "net_gain": -1.364232000000018, + "trade_closed_at": "2022-09-29 18:00:00", + "trade_closed_price": 19814.379999999997, + "created_at": "2022-09-29 00:00:00", + "updated_at": "2022-09-29 02:00:00", + "filled": 0.0048, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19539.96, + "amount": 0.005, + "net_gain": -0.8903750000000037, + "trade_closed_at": "2022-09-28 10:00:00", + "trade_closed_price": 19539.96, + "created_at": "2022-09-28 08:00:00", + "updated_at": "2022-09-28 10:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.575, + "amount": 14.6593, + "net_gain": -2.345487999999989, + "trade_closed_at": "2022-09-28 08:00:00", + "trade_closed_price": 6.575, + "created_at": "2022-09-28 06:00:00", + "updated_at": "2022-09-28 08:00:00", + "filled": 14.6593, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.734999999999999, + "amount": 14.6593, + "net_gain": -2.345487999999989, + "trade_closed_at": "2022-09-28 08:00:00", + "trade_closed_price": 6.575, + "created_at": "2022-09-26 14:00:00", + "updated_at": "2022-09-26 16:00:00", + "filled": 14.6593, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19718.035, + "amount": 0.005, + "net_gain": -0.8903750000000037, + "trade_closed_at": "2022-09-28 10:00:00", + "trade_closed_price": 19539.96, + "created_at": "2022-09-26 12:00:00", + "updated_at": "2022-09-26 14:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.449999999999999, + "amount": 13.2524, + "net_gain": 0.0, + "trade_closed_at": "2022-09-13 04:00:00", + "trade_closed_price": 7.449999999999999, + "created_at": "2022-09-13 02:00:00", + "updated_at": "2022-09-13 04:00:00", + "filled": 13.2524, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.449999999999999, + "amount": 13.2524, + "net_gain": 0.0, + "trade_closed_at": "2022-09-13 04:00:00", + "trade_closed_price": 7.449999999999999, + "created_at": "2022-09-09 02:00:00", + "updated_at": "2022-09-09 04:00:00", + "filled": 13.2524, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 23675.2, + "amount": 0.0042, + "net_gain": 1.7986710000000041, + "trade_closed_at": "2022-08-15 22:00:00", + "trade_closed_price": 23675.2, + "created_at": "2022-08-15 20:00:00", + "updated_at": "2022-08-15 22:00:00", + "filled": 0.0042, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 8.945, + "amount": 10.6914, + "net_gain": -3.528162000000001, + "trade_closed_at": "2022-08-14 16:00:00", + "trade_closed_price": 8.945, + "created_at": "2022-08-14 14:00:00", + "updated_at": "2022-08-14 16:00:00", + "filled": 10.6914, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 23246.945, + "amount": 0.0042, + "net_gain": 1.7986710000000041, + "trade_closed_at": "2022-08-15 22:00:00", + "trade_closed_price": 23675.2, + "created_at": "2022-08-10 22:00:00", + "updated_at": "2022-08-11 00:00:00", + "filled": 0.0042, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 9.275, + "amount": 10.6914, + "net_gain": -3.528162000000001, + "trade_closed_at": "2022-08-14 16:00:00", + "trade_closed_price": 8.945, + "created_at": "2022-08-10 16:00:00", + "updated_at": "2022-08-10 18:00:00", + "filled": 10.6914, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 22492.04, + "amount": 0.0043, + "net_gain": -2.658840499999996, + "trade_closed_at": "2022-08-04 12:00:00", + "trade_closed_price": 22492.04, + "created_at": "2022-08-04 10:00:00", + "updated_at": "2022-08-04 12:00:00", + "filled": 0.0043, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.92, + "amount": 12.5214, + "net_gain": -0.8764980000000036, + "trade_closed_at": "2022-08-04 10:00:00", + "trade_closed_price": 7.92, + "created_at": "2022-08-04 08:00:00", + "updated_at": "2022-08-04 10:00:00", + "filled": 12.5214, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.99, + "amount": 12.5214, + "net_gain": -0.8764980000000036, + "trade_closed_at": "2022-08-04 10:00:00", + "trade_closed_price": 7.92, + "created_at": "2022-08-04 00:00:00", + "updated_at": "2022-08-04 02:00:00", + "filled": 12.5214, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 23110.375, + "amount": 0.0043, + "net_gain": -2.658840499999996, + "trade_closed_at": "2022-08-04 12:00:00", + "trade_closed_price": 22492.04, + "created_at": "2022-08-03 18:00:00", + "updated_at": "2022-08-03 20:00:00", + "filled": 0.0043, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19891.43, + "amount": 0.005, + "net_gain": 0.25270000000000437, + "trade_closed_at": "2022-06-27 14:00:00", + "trade_closed_price": 19891.43, + "created_at": "2022-06-27 12:00:00", + "updated_at": "2022-06-27 14:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.574999999999999, + "amount": 13.1926, + "net_gain": -0.06596300000001032, + "trade_closed_at": "2022-06-27 16:00:00", + "trade_closed_price": 7.574999999999999, + "created_at": "2022-06-27 12:00:00", + "updated_at": "2022-06-27 16:00:00", + "filled": 13.1926, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 7.58, + "amount": 13.1926, + "net_gain": -0.06596300000001032, + "trade_closed_at": "2022-06-27 16:00:00", + "trade_closed_price": 7.574999999999999, + "created_at": "2022-06-24 02:00:00", + "updated_at": "2022-06-24 04:00:00", + "filled": 13.1926, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19840.89, + "amount": 0.005, + "net_gain": 0.25270000000000437, + "trade_closed_at": "2022-06-27 14:00:00", + "trade_closed_price": 19891.43, + "created_at": "2022-06-23 20:00:00", + "updated_at": "2022-06-23 22:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + } + ], + "created_at": "2024-04-25 13:53:38" +} \ No newline at end of file diff --git a/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:52.json b/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:52.json new file mode 100644 index 00000000..0b324e10 --- /dev/null +++ b/tests/resources/backtest_reports_for_testing/report_9-50-100_backtest_start_date_2022-12-20:00:00_backtest_end_date_2023-06-01:00:00_created_at_2024-04-25:13:52.json @@ -0,0 +1,1336 @@ +{ + "name": "9-50-100", + "context": {}, + "strategy_identifiers": [], + "backtest_start_date": "2022-12-20 00:00:00", + "backtest_end_date": "2023-06-01 00:00:00", + "number_of_runs": 1957, + "symbols": null, + "market": null, + "number_of_days": 163, + "number_of_orders": 46, + "number_of_positions": 1, + "market_data_file": null, + "percentage_positive_trades": 26.08695652173913, + "percentage_negative_trades": 73.91304347826086, + "number_of_trades_closed": 23, + "number_of_trades_open": 0, + "total_cost": -2.842170943040401e-14, + "growth_rate": 2.2294337750000466, + "growth": 8.917735100000186, + "initial_unallocated": 400.0, + "trading_symbol": "EUR", + "total_net_gain_percentage": 2.2294337750000097, + "total_net_gain": 8.917735100000039, + "total_value": 408.9177351000002, + "average_trade_duration": 58.52173913043478, + "average_trade_size": 105.02655334130436, + "positions": [ + { + "symbol": "EUR", + "amount": 408.9177351000002, + "cost": 408.9177351000002, + "price": 1, + "value": 408.9177351000002, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0.0, + "amount_pending_sell": 0.0, + "percentage_of_portfolio": 100.0 + }, + { + "symbol": "BTC", + "amount": 0.0, + "cost": 0.0, + "price": 25496.73, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + }, + { + "symbol": "DOT", + "amount": 0.0, + "cost": 0.0, + "price": 4.9785, + "value": 0.0, + "growth": 0.0, + "growth_rate": 0.0, + "amount_pending_buy": 0, + "amount_pending_sell": 0, + "percentage_of_portfolio": 0.0 + } + ], + "trades": [ + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 20.5646, + "open_price": 4.9885, + "current_price": 4.9785, + "closed_price": 4.9190000000000005, + "opened_at": "2023-05-23 08:00:00", + "closed_at": "2023-05-24 12:00:00", + "change": 0, + "absolute_change": -1.4292396999999823 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0041, + "open_price": 25097.05, + "current_price": 25496.73, + "closed_price": 24920.845, + "opened_at": "2023-05-20 22:00:00", + "closed_at": "2023-05-21 18:00:00", + "change": 0, + "absolute_change": -0.7224404999999905 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.004, + "open_price": 25313.295, + "current_price": 25496.73, + "closed_price": 24963.495000000003, + "opened_at": "2023-05-18 00:00:00", + "closed_at": "2023-05-19 04:00:00", + "change": 0, + "absolute_change": -1.3991999999999933 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 20.7109, + "open_price": 4.998, + "current_price": 4.9785, + "closed_price": 4.9215, + "opened_at": "2023-05-18 00:00:00", + "closed_at": "2023-05-21 16:00:00", + "change": 0, + "absolute_change": -1.5843838499999947 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0038, + "open_price": 26978.895, + "current_price": 25496.73, + "closed_price": 26014.935, + "opened_at": "2023-04-30 16:00:00", + "closed_at": "2023-05-01 04:00:00", + "change": 0, + "absolute_change": -3.663047999999989 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 19.3871, + "open_price": 5.4185, + "current_price": 4.9785, + "closed_price": 5.2905, + "opened_at": "2023-04-29 10:00:00", + "closed_at": "2023-05-01 06:00:00", + "change": 0, + "absolute_change": -2.4815487999999988 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 17.1645, + "open_price": 6.182, + "current_price": 4.9785, + "closed_price": 5.9345, + "opened_at": "2023-04-18 04:00:00", + "closed_at": "2023-04-19 14:00:00", + "change": 0, + "absolute_change": -4.248213750000005 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.004, + "open_price": 26144.72, + "current_price": 25496.73, + "closed_price": 25820.89, + "opened_at": "2023-04-05 10:00:00", + "closed_at": "2023-04-06 02:00:00", + "change": 0, + "absolute_change": -1.295320000000018 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.004, + "open_price": 26210.345, + "current_price": 25496.73, + "closed_price": 25758.385000000002, + "opened_at": "2023-03-24 02:00:00", + "closed_at": "2023-03-25 02:00:00", + "change": 0, + "absolute_change": -1.8078399999999846 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 16.9905, + "open_price": 6.364, + "current_price": 4.9785, + "closed_price": 6.072, + "opened_at": "2023-02-09 08:00:00", + "closed_at": "2023-02-09 20:00:00", + "change": 0, + "absolute_change": -4.961225999999996 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 17.0524, + "open_price": 6.429, + "current_price": 4.9785, + "closed_price": 6.2035, + "opened_at": "2023-02-07 22:00:00", + "closed_at": "2023-02-09 08:00:00", + "change": 0, + "absolute_change": -3.845316199999999 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.005, + "open_price": 21604.995000000003, + "current_price": 25496.73, + "closed_price": 21172.035000000003, + "opened_at": "2023-02-07 20:00:00", + "closed_at": "2023-02-09 04:00:00", + "change": 0, + "absolute_change": -2.1647999999999854 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.005, + "open_price": 21707.995000000003, + "current_price": 25496.73, + "closed_price": 21441.1, + "opened_at": "2023-02-02 02:00:00", + "closed_at": "2023-02-05 16:00:00", + "change": 0, + "absolute_change": -1.3344750000000118 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 18.7064, + "open_price": 5.949, + "current_price": 4.9785, + "closed_price": 5.7545, + "opened_at": "2023-01-27 16:00:00", + "closed_at": "2023-01-30 14:00:00", + "change": 0, + "absolute_change": -3.6383948000000004 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 19.0372, + "open_price": 5.8235, + "current_price": 4.9785, + "closed_price": 5.912000000000001, + "opened_at": "2023-01-26 10:00:00", + "closed_at": "2023-01-27 16:00:00", + "change": 0, + "absolute_change": 1.6847922000000182 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0052, + "open_price": 21243.75, + "current_price": 25496.73, + "closed_price": 20927.125, + "opened_at": "2023-01-26 02:00:00", + "closed_at": "2023-01-30 22:00:00", + "change": 0, + "absolute_change": -1.6464500000000015 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 19.4519, + "open_price": 5.631, + "current_price": 4.9785, + "closed_price": 5.6370000000000005, + "opened_at": "2023-01-20 20:00:00", + "closed_at": "2023-01-25 04:00:00", + "change": 0, + "absolute_change": 0.11671140000001401 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0055, + "open_price": 19751.965, + "current_price": 25496.73, + "closed_price": 20697.87, + "opened_at": "2023-01-20 18:00:00", + "closed_at": "2023-01-25 02:00:00", + "change": 0, + "absolute_change": 5.202477499999986 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0062, + "open_price": 16012.195, + "current_price": 25496.73, + "closed_price": 19196.215, + "opened_at": "2023-01-08 22:00:00", + "closed_at": "2023-01-19 02:00:00", + "change": 0, + "absolute_change": 19.740924000000007 + }, + { + "target_symbol": "DOT", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 22.5161, + "open_price": 4.433999999999999, + "current_price": 4.9785, + "closed_price": 5.28, + "opened_at": "2023-01-08 14:00:00", + "closed_at": "2023-01-16 16:00:00", + "change": 0, + "absolute_change": 19.04862060000002 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0062, + "open_price": 15889.505000000001, + "current_price": 25496.73, + "closed_price": 15778.795, + "opened_at": "2022-12-26 04:00:00", + "closed_at": "2022-12-26 20:00:00", + "change": 0, + "absolute_change": -0.6864020000000011 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0063, + "open_price": 15828.42, + "current_price": 25496.73, + "closed_price": 15838.494999999999, + "opened_at": "2022-12-24 22:00:00", + "closed_at": "2022-12-25 02:00:00", + "change": 0, + "absolute_change": 0.06347249999998894 + }, + { + "target_symbol": "BTC", + "trading_symbol": "EUR", + "status": "CLOSED", + "amount": 0.0063, + "open_price": 15842.42, + "current_price": 25496.73, + "closed_price": 15837.505000000001, + "opened_at": "2022-12-24 16:00:00", + "closed_at": "2022-12-24 22:00:00", + "change": 0, + "absolute_change": -0.030964499999996065 + } + ], + "orders": [ + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.9190000000000005, + "amount": 20.5646, + "net_gain": -1.4292396999999932, + "trade_closed_at": "2023-05-24 12:00:00", + "trade_closed_price": 4.9190000000000005, + "created_at": "2023-05-24 10:00:00", + "updated_at": "2023-05-24 12:00:00", + "filled": 20.5646, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.9885, + "amount": 20.5646, + "net_gain": -1.4292396999999932, + "trade_closed_at": "2023-05-24 12:00:00", + "trade_closed_price": 4.9190000000000005, + "created_at": "2023-05-23 08:00:00", + "updated_at": "2023-05-23 10:00:00", + "filled": 20.5646, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 24920.845, + "amount": 0.0041, + "net_gain": -0.7224404999999923, + "trade_closed_at": "2023-05-21 18:00:00", + "trade_closed_price": 24920.845, + "created_at": "2023-05-21 16:00:00", + "updated_at": "2023-05-21 18:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.9215, + "amount": 20.7109, + "net_gain": -1.5843838500000047, + "trade_closed_at": "2023-05-21 16:00:00", + "trade_closed_price": 4.9215, + "created_at": "2023-05-21 14:00:00", + "updated_at": "2023-05-21 16:00:00", + "filled": 20.7109, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25097.05, + "amount": 0.0041, + "net_gain": -0.7224404999999923, + "trade_closed_at": "2023-05-21 18:00:00", + "trade_closed_price": 24920.845, + "created_at": "2023-05-20 22:00:00", + "updated_at": "2023-05-21 00:00:00", + "filled": 0.0041, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 24963.495000000003, + "amount": 0.004, + "net_gain": -1.3991999999999825, + "trade_closed_at": "2023-05-19 04:00:00", + "trade_closed_price": 24963.495000000003, + "created_at": "2023-05-19 02:00:00", + "updated_at": "2023-05-19 04:00:00", + "filled": 0.004, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25313.295, + "amount": 0.004, + "net_gain": -1.3991999999999825, + "trade_closed_at": "2023-05-19 04:00:00", + "trade_closed_price": 24963.495000000003, + "created_at": "2023-05-18 00:00:00", + "updated_at": "2023-05-18 02:00:00", + "filled": 0.004, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.998, + "amount": 20.7109, + "net_gain": -1.5843838500000047, + "trade_closed_at": "2023-05-21 16:00:00", + "trade_closed_price": 4.9215, + "created_at": "2023-05-18 00:00:00", + "updated_at": "2023-05-18 04:00:00", + "filled": 20.7109, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26014.935, + "amount": 0.0038, + "net_gain": -3.6630479999999968, + "trade_closed_at": "2023-05-01 04:00:00", + "trade_closed_price": 26014.935, + "created_at": "2023-05-01 02:00:00", + "updated_at": "2023-05-01 04:00:00", + "filled": 0.0038, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.2905, + "amount": 19.3871, + "net_gain": -2.4815488000000023, + "trade_closed_at": "2023-05-01 06:00:00", + "trade_closed_price": 5.2905, + "created_at": "2023-05-01 02:00:00", + "updated_at": "2023-05-01 06:00:00", + "filled": 19.3871, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26978.895, + "amount": 0.0038, + "net_gain": -3.6630479999999968, + "trade_closed_at": "2023-05-01 04:00:00", + "trade_closed_price": 26014.935, + "created_at": "2023-04-30 16:00:00", + "updated_at": "2023-04-30 18:00:00", + "filled": 0.0038, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.4185, + "amount": 19.3871, + "net_gain": -2.4815488000000023, + "trade_closed_at": "2023-05-01 06:00:00", + "trade_closed_price": 5.2905, + "created_at": "2023-04-29 10:00:00", + "updated_at": "2023-04-29 12:00:00", + "filled": 19.3871, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.9345, + "amount": 17.1645, + "net_gain": -4.248213750000009, + "trade_closed_at": "2023-04-19 14:00:00", + "trade_closed_price": 5.9345, + "created_at": "2023-04-19 12:00:00", + "updated_at": "2023-04-19 14:00:00", + "filled": 17.1645, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.182, + "amount": 17.1645, + "net_gain": -4.248213750000009, + "trade_closed_at": "2023-04-19 14:00:00", + "trade_closed_price": 5.9345, + "created_at": "2023-04-18 04:00:00", + "updated_at": "2023-04-18 06:00:00", + "filled": 17.1645, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25820.89, + "amount": 0.004, + "net_gain": -1.295320000000007, + "trade_closed_at": "2023-04-06 02:00:00", + "trade_closed_price": 25820.89, + "created_at": "2023-04-06 00:00:00", + "updated_at": "2023-04-06 02:00:00", + "filled": 0.004, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26144.72, + "amount": 0.004, + "net_gain": -1.295320000000007, + "trade_closed_at": "2023-04-06 02:00:00", + "trade_closed_price": 25820.89, + "created_at": "2023-04-05 10:00:00", + "updated_at": "2023-04-05 12:00:00", + "filled": 0.004, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 25758.385000000002, + "amount": 0.004, + "net_gain": -1.8078399999999966, + "trade_closed_at": "2023-03-25 02:00:00", + "trade_closed_price": 25758.385000000002, + "created_at": "2023-03-25 00:00:00", + "updated_at": "2023-03-25 02:00:00", + "filled": 0.004, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 26210.345, + "amount": 0.004, + "net_gain": -1.8078399999999966, + "trade_closed_at": "2023-03-25 02:00:00", + "trade_closed_price": 25758.385000000002, + "created_at": "2023-03-24 02:00:00", + "updated_at": "2023-03-24 04:00:00", + "filled": 0.004, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.072, + "amount": 16.9905, + "net_gain": -4.961225999999997, + "trade_closed_at": "2023-02-09 20:00:00", + "trade_closed_price": 6.072, + "created_at": "2023-02-09 18:00:00", + "updated_at": "2023-02-09 20:00:00", + "filled": 16.9905, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.364, + "amount": 16.9905, + "net_gain": -4.961225999999997, + "trade_closed_at": "2023-02-09 20:00:00", + "trade_closed_price": 6.072, + "created_at": "2023-02-09 08:00:00", + "updated_at": "2023-02-09 10:00:00", + "filled": 16.9905, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.2035, + "amount": 17.0524, + "net_gain": -3.845316200000004, + "trade_closed_at": "2023-02-09 08:00:00", + "trade_closed_price": 6.2035, + "created_at": "2023-02-09 06:00:00", + "updated_at": "2023-02-09 08:00:00", + "filled": 17.0524, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21172.035000000003, + "amount": 0.005, + "net_gain": -2.1647999999999956, + "trade_closed_at": "2023-02-09 04:00:00", + "trade_closed_price": 21172.035000000003, + "created_at": "2023-02-09 02:00:00", + "updated_at": "2023-02-09 04:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 6.429, + "amount": 17.0524, + "net_gain": -3.845316200000004, + "trade_closed_at": "2023-02-09 08:00:00", + "trade_closed_price": 6.2035, + "created_at": "2023-02-07 22:00:00", + "updated_at": "2023-02-08 00:00:00", + "filled": 17.0524, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21604.995000000003, + "amount": 0.005, + "net_gain": -2.1647999999999956, + "trade_closed_at": "2023-02-09 04:00:00", + "trade_closed_price": 21172.035000000003, + "created_at": "2023-02-07 20:00:00", + "updated_at": "2023-02-07 22:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21441.1, + "amount": 0.005, + "net_gain": -1.3344750000000205, + "trade_closed_at": "2023-02-05 16:00:00", + "trade_closed_price": 21441.1, + "created_at": "2023-02-05 14:00:00", + "updated_at": "2023-02-05 16:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21707.995000000003, + "amount": 0.005, + "net_gain": -1.3344750000000205, + "trade_closed_at": "2023-02-05 16:00:00", + "trade_closed_price": 21441.1, + "created_at": "2023-02-02 02:00:00", + "updated_at": "2023-02-02 04:00:00", + "filled": 0.005, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20927.125, + "amount": 0.0052, + "net_gain": -1.64645, + "trade_closed_at": "2023-01-30 22:00:00", + "trade_closed_price": 20927.125, + "created_at": "2023-01-30 20:00:00", + "updated_at": "2023-01-30 22:00:00", + "filled": 0.0052, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.7545, + "amount": 18.7064, + "net_gain": -3.6383947999999937, + "trade_closed_at": "2023-01-30 14:00:00", + "trade_closed_price": 5.7545, + "created_at": "2023-01-30 12:00:00", + "updated_at": "2023-01-30 14:00:00", + "filled": 18.7064, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.949, + "amount": 18.7064, + "net_gain": -3.6383947999999937, + "trade_closed_at": "2023-01-30 14:00:00", + "trade_closed_price": 5.7545, + "created_at": "2023-01-27 16:00:00", + "updated_at": "2023-01-27 18:00:00", + "filled": 18.7064, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.912000000000001, + "amount": 19.0372, + "net_gain": 1.684792200000013, + "trade_closed_at": "2023-01-27 16:00:00", + "trade_closed_price": 5.912000000000001, + "created_at": "2023-01-27 14:00:00", + "updated_at": "2023-01-27 16:00:00", + "filled": 19.0372, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.8235, + "amount": 19.0372, + "net_gain": 1.684792200000013, + "trade_closed_at": "2023-01-27 16:00:00", + "trade_closed_price": 5.912000000000001, + "created_at": "2023-01-26 10:00:00", + "updated_at": "2023-01-26 12:00:00", + "filled": 19.0372, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 21243.75, + "amount": 0.0052, + "net_gain": -1.64645, + "trade_closed_at": "2023-01-30 22:00:00", + "trade_closed_price": 20927.125, + "created_at": "2023-01-26 02:00:00", + "updated_at": "2023-01-26 04:00:00", + "filled": 0.0052, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.6370000000000005, + "amount": 19.4519, + "net_gain": 0.11671140000000442, + "trade_closed_at": "2023-01-25 04:00:00", + "trade_closed_price": 5.6370000000000005, + "created_at": "2023-01-25 02:00:00", + "updated_at": "2023-01-25 04:00:00", + "filled": 19.4519, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 20697.87, + "amount": 0.0055, + "net_gain": 5.202477499999993, + "trade_closed_at": "2023-01-25 02:00:00", + "trade_closed_price": 20697.87, + "created_at": "2023-01-25 00:00:00", + "updated_at": "2023-01-25 02:00:00", + "filled": 0.0055, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.631, + "amount": 19.4519, + "net_gain": 0.11671140000000442, + "trade_closed_at": "2023-01-25 04:00:00", + "trade_closed_price": 5.6370000000000005, + "created_at": "2023-01-20 20:00:00", + "updated_at": "2023-01-20 22:00:00", + "filled": 19.4519, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19751.965, + "amount": 0.0055, + "net_gain": 5.202477499999993, + "trade_closed_at": "2023-01-25 02:00:00", + "trade_closed_price": 20697.87, + "created_at": "2023-01-20 18:00:00", + "updated_at": "2023-01-20 20:00:00", + "filled": 0.0055, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 19196.215, + "amount": 0.0062, + "net_gain": 19.740924000000003, + "trade_closed_at": "2023-01-19 02:00:00", + "trade_closed_price": 19196.215, + "created_at": "2023-01-19 00:00:00", + "updated_at": "2023-01-19 02:00:00", + "filled": 0.0062, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 5.28, + "amount": 22.5161, + "net_gain": 19.048620600000024, + "trade_closed_at": "2023-01-16 16:00:00", + "trade_closed_price": 5.28, + "created_at": "2023-01-16 14:00:00", + "updated_at": "2023-01-16 16:00:00", + "filled": 22.5161, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 16012.195, + "amount": 0.0062, + "net_gain": 19.740924000000003, + "trade_closed_at": "2023-01-19 02:00:00", + "trade_closed_price": 19196.215, + "created_at": "2023-01-08 22:00:00", + "updated_at": "2023-01-09 00:00:00", + "filled": 0.0062, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "DOT", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 4.433999999999999, + "amount": 22.5161, + "net_gain": 19.048620600000024, + "trade_closed_at": "2023-01-16 16:00:00", + "trade_closed_price": 5.28, + "created_at": "2023-01-08 14:00:00", + "updated_at": "2023-01-08 16:00:00", + "filled": 22.5161, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15778.795, + "amount": 0.0062, + "net_gain": -0.6864020000000058, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 18:00:00", + "updated_at": "2022-12-26 20:00:00", + "filled": 0.0062, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15889.505000000001, + "amount": 0.0062, + "net_gain": -0.6864020000000058, + "trade_closed_at": "2022-12-26 20:00:00", + "trade_closed_price": 15778.795, + "created_at": "2022-12-26 04:00:00", + "updated_at": "2022-12-26 06:00:00", + "filled": 0.0062, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15838.494999999999, + "amount": 0.0063, + "net_gain": 0.06347249999999312, + "trade_closed_at": "2022-12-25 02:00:00", + "trade_closed_price": 15838.494999999999, + "created_at": "2022-12-25 00:00:00", + "updated_at": "2022-12-25 02:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15828.42, + "amount": 0.0063, + "net_gain": 0.06347249999999312, + "trade_closed_at": "2022-12-25 02:00:00", + "trade_closed_price": 15838.494999999999, + "created_at": "2022-12-24 22:00:00", + "updated_at": "2022-12-25 00:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "SELL", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15837.505000000001, + "amount": 0.0063, + "net_gain": -0.030964499999994042, + "trade_closed_at": "2022-12-24 22:00:00", + "trade_closed_price": 15837.505000000001, + "created_at": "2022-12-24 20:00:00", + "updated_at": "2022-12-24 22:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + }, + { + "external_id": null, + "target_symbol": "BTC", + "trading_symbol": "EUR", + "order_side": "BUY", + "order_type": "LIMIT", + "status": "CLOSED", + "price": 15842.42, + "amount": 0.0063, + "net_gain": -0.030964499999994042, + "trade_closed_at": "2022-12-24 22:00:00", + "trade_closed_price": 15837.505000000001, + "created_at": "2022-12-24 16:00:00", + "updated_at": "2022-12-24 18:00:00", + "filled": 0.0063, + "remaining": 0.0, + "cost": null, + "order_fee_currency": null, + "order_fee_rate": null, + "order_fee": null + } + ], + "created_at": "2024-04-25 13:52:55" +} \ No newline at end of file diff --git a/tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-21 23:33:25.csv b/tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-21 23:33:25.csv deleted file mode 100644 index 58d9209a..00000000 --- a/tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-21 23:33:25.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -9-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,24,3,,25.0,66.66666666666666,11,2,201.47576389999998,2.4613143374999993,9.845257349999997,400.0,EUR,1.5842656375000046,6.337062550000018,,409.84525735,90.0,100.28118696818181 diff --git a/tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-22 00:17:06.csv b/tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-22 00:17:06.csv deleted file mode 100644 index 58d9209a..00000000 --- a/tests/resources/backtest_reports_for_testing/report_9-75-1502024-03-22 00:17:06.csv +++ /dev/null @@ -1,2 +0,0 @@ -name,strategy_identifiers,backtest_start_date,backtest_end_date,number_of_runs,symbols,market,number_of_days,number_of_orders,number_of_positions,market_data_file,percentage_positive_trades,percentage_negative_trades,number_of_trades_closed,number_of_trades_open,total_cost,growth_rate,growth,initial_unallocated,trading_symbol,total_net_gain_percentage,total_net_gain,backtest_data_index_date,total_value,average_trade_duration,average_trade_size -9-75-150,[],2023-08-24 00:00:00,2023-12-02 00:00:00,1201,,,100,24,3,,25.0,66.66666666666666,11,2,201.47576389999998,2.4613143374999993,9.845257349999997,400.0,EUR,1.5842656375000046,6.337062550000018,,409.84525735,90.0,100.28118696818181 diff --git a/tests/services/test_order_backtest_service.py b/tests/services/test_order_backtest_service.py index b5cfd429..83b90b3e 100644 --- a/tests/services/test_order_backtest_service.py +++ b/tests/services/test_order_backtest_service.py @@ -62,7 +62,6 @@ def setUp(self) -> None: self.app.container.order_service.override( OrderBacktestService( order_repository=self.app.container.order_repository(), - order_fee_repository=self.app.container.order_fee_repository(), position_repository=self.app.container.position_repository(), portfolio_repository=self.app.container.portfolio_repository(), portfolio_configuration_service=self.app.container\ From 88026fbe18362ff7d1d058ec4a3ce0ab6e2b5d02 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Thu, 25 Apr 2024 22:44:25 +0200 Subject: [PATCH 02/31] Remove unused configuration --- .../configuration_copy.json | 146 ------------------ 1 file changed, 146 deletions(-) delete mode 100644 examples/backtest_experiment/configuration_copy.json diff --git a/examples/backtest_experiment/configuration_copy.json b/examples/backtest_experiment/configuration_copy.json deleted file mode 100644 index 9694ba6a..00000000 --- a/examples/backtest_experiment/configuration_copy.json +++ /dev/null @@ -1,146 +0,0 @@ -[ - { - "name":"9-50-100", - "description":"9-50-100", - "fast":9, - "slow":50, - "trend":100, - "stop_loss_percentage":7 - }, - { - "name":"10-50-100", - "description":"10-50-100", - "fast":10, - "slow":50, - "trend":100, - "stop_loss_percentage":7 - }, - { - "name":"11-50-100", - "description":"11-50-100", - "fast":11, - "slow":50, - "trend":100, - "stop_loss_percentage":7 - }, - { - "name":"9-75-150", - "description":"9-75-150", - "fast":9, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"10-75-150", - "description":"10-75-150", - "fast":10, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"11-75-150", - "description":"11-75-150", - "fast":11, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"20-75-150", - "description":"20-75-150", - "fast":20, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"21-75-150", - "description":"21-75-150", - "fast":21, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"22-75-150", - "description":"22-75-150", - "fast":22, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"23-75-150", - "description":"23-75-150", - "fast":23, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"24-75-150", - "description":"24-75-150", - "fast":24, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"25-75-150", - "description":"25-75-150", - "fast":25, - "slow":75, - "trend":150, - "stop_loss_percentage":7 - }, - { - "name":"20-75-200", - "description":"20-75-200", - "fast":20, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"21-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"22-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"23-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"24-75-200", - "description":"24-75-200", - "fast":24, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - }, - { - "name":"25-75-150", - "description":"25-75-200", - "fast":25, - "slow":75, - "trend":200, - "stop_loss_percentage":7 - } -] \ No newline at end of file From 767d72314f00a0ab0740c260d880f08e73aa3f52 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Thu, 25 Apr 2024 22:50:48 +0200 Subject: [PATCH 03/31] Fix flake 8 warnings --- investing_algorithm_framework/__init__.py | 2 +- investing_algorithm_framework/app/app.py | 2 +- investing_algorithm_framework/domain/__init__.py | 3 ++- .../domain/models/backtesting/backtest_date_range.py | 2 +- .../domain/models/backtesting/backtest_position.py | 2 +- .../domain/models/trade/trade.py | 6 ++++-- .../domain/utils/__init__.py | 1 + investing_algorithm_framework/domain/utils/csv.py | 1 - .../models/market_data_sources/us_treasury_yield.py | 12 +++++++++--- 9 files changed, 20 insertions(+), 11 deletions(-) diff --git a/investing_algorithm_framework/__init__.py b/investing_algorithm_framework/__init__.py index 1a31511b..f3206023 100644 --- a/investing_algorithm_framework/__init__.py +++ b/investing_algorithm_framework/__init__.py @@ -9,7 +9,7 @@ Trade, OHLCVMarketDataSource, OrderBookMarketDataSource, SYMBOLS, \ TickerMarketDataSource, MarketService, BacktestReportsEvaluation, \ pretty_print_backtest_reports_evaluation, load_backtest_reports, \ - RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT,\ + RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT, \ load_backtest_report, BacktestDateRange from investing_algorithm_framework.infrastructure import \ CCXTOrderBookMarketDataSource, CCXTOHLCVMarketDataSource, \ diff --git a/investing_algorithm_framework/app/app.py b/investing_algorithm_framework/app/app.py index 42a2262a..2e78f236 100644 --- a/investing_algorithm_framework/app/app.py +++ b/investing_algorithm_framework/app/app.py @@ -7,7 +7,7 @@ from datetime import datetime from distutils.sysconfig import get_python_lib from time import sleep -from typing import List, Optional, Tuple +from typing import List, Optional from flask import Flask diff --git a/investing_algorithm_framework/domain/__init__.py b/investing_algorithm_framework/domain/__init__.py index 14995d53..2f953f17 100644 --- a/investing_algorithm_framework/domain/__init__.py +++ b/investing_algorithm_framework/domain/__init__.py @@ -26,7 +26,8 @@ from .stateless_actions import StatelessActions from .strategy import Strategy from .utils import random_string, append_dict_as_row_to_csv, \ - add_column_headers_to_csv, get_total_amount_of_rows, load_backtest_report,\ + add_column_headers_to_csv, get_total_amount_of_rows, \ + load_backtest_report, \ csv_to_list, StoppableThread, pretty_print_backtest_reports_evaluation, \ pretty_print_backtest, load_csv_into_dict, load_backtest_reports diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py b/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py index 35eee8a9..2a31e88b 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py @@ -5,7 +5,7 @@ class BacktestDateRange: """ Represents a date range for a backtest """ - def __init__(self, start_date, end_date = None, name = None): + def __init__(self, start_date, end_date=None, name=None): self._start_date = start_date self._end_date = end_date self._name = name diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_position.py b/investing_algorithm_framework/domain/models/backtesting/backtest_position.py index 976866a5..f9de1f9d 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_position.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_position.py @@ -117,4 +117,4 @@ def to_dict(self): "amount_pending_buy": self.amount_pending_buy, "amount_pending_sell": self.amount_pending_sell, "percentage_of_portfolio": self.percentage_of_portfolio - } \ No newline at end of file + } diff --git a/investing_algorithm_framework/domain/models/trade/trade.py b/investing_algorithm_framework/domain/models/trade/trade.py index b0a9b97a..33170507 100644 --- a/investing_algorithm_framework/domain/models/trade/trade.py +++ b/investing_algorithm_framework/domain/models/trade/trade.py @@ -239,8 +239,10 @@ def to_dict(self): "open_price": self.open_price, "current_price": self.current_price, "closed_price": self.closed_price, - "opened_at": self.opened_at.strftime(DATETIME_FORMAT) if self.opened_at else None, - "closed_at": self.closed_at.strftime(DATETIME_FORMAT) if self.closed_at else None, + "opened_at": self.opened_at.strftime(DATETIME_FORMAT) + if self.opened_at else None, + "closed_at": self.closed_at.strftime(DATETIME_FORMAT) + if self.closed_at else None, "change": self.percentage_change, "absolute_change": self.absolute_change, } diff --git a/investing_algorithm_framework/domain/utils/__init__.py b/investing_algorithm_framework/domain/utils/__init__.py index 00fb400b..efd6543a 100644 --- a/investing_algorithm_framework/domain/utils/__init__.py +++ b/investing_algorithm_framework/domain/utils/__init__.py @@ -17,5 +17,6 @@ 'pretty_print_backtest', 'pretty_print_backtest_reports_evaluation', 'load_csv_into_dict', + 'load_backtest_report', 'load_backtest_reports', ] diff --git a/investing_algorithm_framework/domain/utils/csv.py b/investing_algorithm_framework/domain/utils/csv.py index 0f3a8c8b..a31c49bf 100644 --- a/investing_algorithm_framework/domain/utils/csv.py +++ b/investing_algorithm_framework/domain/utils/csv.py @@ -1,5 +1,4 @@ import csv -import json import shutil import tempfile from typing import Dict, List diff --git a/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py b/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py index fe99e83d..00003346 100644 --- a/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py +++ b/investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py @@ -8,6 +8,10 @@ class UsTreasuryYieldDataSource(MarketDataSource): UsTreasuryYield is a subclass of MarketDataSource. It is used to get the US Treasury Yield data. """ + + def to_backtest_market_data_source(self) -> BacktestMarketDataSource: + pass + URL = "https://api.fiscaldata.treasury.gov/services/api/fiscal_service/" \ "v2/accounting/od/avg_interest_rates?" \ "filter=record_date:gte:2024-01-01" @@ -22,7 +26,8 @@ def get_data( response = requests.get(self.URL) if response.status_code == 200: - # Extract risk-free rate from API response (e.g., 10-year Treasury yield) + # Extract risk-free rate from API response + # (e.g., 10-year Treasury yield) treasury_yield_data = response.json() entries = treasury_yield_data["data"] for entry in entries: @@ -31,11 +36,12 @@ def get_data( print(entries[-1]["avg_interest_rate_amt"]) # print(treasury_yield_data) # ten_year_yield = treasury_yield_data["data"][0]["value"] - # risk_free_rate = ten_year_yield / 100 # Convert percentage to decimal + # risk_free_rate = ten_year_yield / 100 # Convert + # percentage to decimal # print("10-Year Treasury Yield (Risk-Free Rate):", risk_free_rate) else: print("Failed to retrieve Treasury yield data. Status code:", response.status_code) def to_backtest_market_data_source(self) -> BacktestMarketDataSource: - pass \ No newline at end of file + pass From b4317eab05393df627c697183ed09bb1fda8f15f Mon Sep 17 00:00:00 2001 From: PyPI Poetry Publish Bot Date: Thu, 25 Apr 2024 20:56:11 +0000 Subject: [PATCH 04/31] Change version to v3.6.0 --- __init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index 35e13386..5c2ca51b 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -__version__='v3.5.2' +__version__='v3.6.0' diff --git a/pyproject.toml b/pyproject.toml index 41da11b9..b381caec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "investing-algorithm-framework" -version = "v3.5.2" +version = "v3.6.0" description = "A framework for creating trading bots" authors = ["MDUYN"] readme = "README.md" From 1a92f2e6a9d7ff329bf9f183520418b99b047d5b Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:11:30 +0200 Subject: [PATCH 05/31] Fix data sources refactor --- investing_algorithm_framework/__init__.py | 4 + .../app/algorithm.py | 63 ++-- investing_algorithm_framework/app/app.py | 162 ++++----- .../models/backtesting/backtest_date_range.py | 17 + .../models/backtesting/backtest_report.py | 116 ++++--- .../backtest_reports_evaluation.py | 202 +++++++++++- .../domain/models/time_frame.py | 10 +- .../domain/services/market_data_sources.py | 199 +++++------ .../domain/services/market_service.py | 9 + .../domain/utils/backtesting.py | 308 ++++++------------ .../models/market_data_sources/ccxt.py | 161 +++++---- .../models/market_data_sources/csv.py | 84 +++-- .../market_service/ccxt_market_service.py | 23 +- .../services/__init__.py | 7 +- .../services/backtesting/__init__.py | 6 +- .../backtest_report_writer_service.py | 27 +- .../services/backtesting/backtest_service.py | 137 +++++--- .../services/backtesting/graphs.py | 62 ++++ .../market_data_source_service.py | 16 +- 19 files changed, 923 insertions(+), 690 deletions(-) create mode 100644 investing_algorithm_framework/services/backtesting/graphs.py diff --git a/investing_algorithm_framework/__init__.py b/investing_algorithm_framework/__init__.py index f3206023..e7cf2052 100644 --- a/investing_algorithm_framework/__init__.py +++ b/investing_algorithm_framework/__init__.py @@ -16,6 +16,8 @@ CCXTTickerMarketDataSource, CSVOHLCVMarketDataSource, \ CSVTickerMarketDataSource from .create_app import create_app +from investing_algorithm_framework.services import \ + create_trade_exit_markers_chart, create_trade_entry_markers_chart __all__ = [ "Algorithm", @@ -64,4 +66,6 @@ "DATETIME_FORMAT", "load_backtest_report", "BacktestDateRange", + "create_trade_exit_markers_chart", + "create_trade_entry_markers_chart" ] diff --git a/investing_algorithm_framework/app/algorithm.py b/investing_algorithm_framework/app/algorithm.py index 76c01d85..18105aed 100644 --- a/investing_algorithm_framework/app/algorithm.py +++ b/investing_algorithm_framework/app/algorithm.py @@ -22,17 +22,23 @@ class Algorithm: class is responsible for managing the strategies and executing them in the correct order. - :param name: The name of the algorithm - :param description: The description of the algorithm - :param context: The context of the algorithm, for backtest references + :param (optional) name: The name of the algorithm + :param (optional) description: The description of the algorithm + :param (optional) context: The context of the algorithm, for backtest references + :param (optional) strategy: A single strategy to add to the algorithm + :param (optional) data_sources: The list of data sources to + add to the algorithm """ def __init__( self, name: str = None, description: str = None, - context: Dict[str, str] = None + context: Dict = None, + strategy=None, + data_sources=None ): self._name = name + self._context = {} if name is None: self._name = f"algorithm_{random_string(10)}" @@ -42,20 +48,8 @@ def __init__( if description is not None: self._description = description - self._context = context - - if self.context is None: - self._context = {} - - # Check if the context is a dictionary with only string, - # float or int values - for key, value in self.context.items(): - if not isinstance(key, str) or \ - not isinstance(value, (str, float, int)): - raise OperationalException( - "The context of the algorithm must be a dictionary with " - "only string, float or int values." - ) + if context is not None: + self.add_context(context) self._strategies = [] self._tasks = [] @@ -66,12 +60,18 @@ def __init__( self.configuration_service: ConfigurationService self.portfolio_configuration_service: PortfolioConfigurationService self.strategy_orchestrator_service: StrategyOrchestratorService - self._market_data_sources = {} + self._data_sources = {} self._strategies = [] self._market_credential_service: MarketCredentialService self._market_data_source_service: MarketDataSourceService self.trade_service: TradeService + if strategy is not None: + self.add_strategy(strategy) + + if data_sources is not None: + self.add_data_sources(data_sources) + def initialize_services( self, configuration_service, @@ -95,7 +95,7 @@ def initialize_services( = portfolio_configuration_service self.strategy_orchestrator_service: StrategyOrchestratorService \ = strategy_orchestrator_service - self._market_data_sources = {} + self._data_sources = {} self._market_credential_service: MarketCredentialService \ = market_credential_service self._market_data_source_service: MarketDataSourceService \ @@ -119,6 +119,10 @@ def start(self, number_of_iterations=None, stateless=False): def name(self): return self._name + @property + def data_sources(self): + return self._data_sources + @property def identifier(self): """ @@ -151,6 +155,19 @@ def context(self): """ return self._context + def add_context(self, context: Dict): + # Check if the context is a dictionary with only string, + # float or int values + for key, value in self.context.items(): + if not isinstance(key, str) or \ + not isinstance(value, (str, float, int)): + raise OperationalException( + "The context for an algorithm must be a dictionary with " + "only string, float or int values." + ) + + self._context = context + @property def running(self) -> bool: """ @@ -739,6 +756,9 @@ def add_strategy(self, strategy): "with the same id in the algorithm" ) + if strategy.market_data_sources is not None: + self.add_data_sources(strategy.market_data_sources) + self._strategies.append(strategy) @property @@ -1029,6 +1049,9 @@ def add_task(self, task): self._tasks.append(task) + def add_data_sources(self, data_sources): + self._data_sources = data_sources + @property def tasks(self): return self._tasks diff --git a/investing_algorithm_framework/app/app.py b/investing_algorithm_framework/app/app.py index 2e78f236..f8c2548a 100644 --- a/investing_algorithm_framework/app/app.py +++ b/investing_algorithm_framework/app/app.py @@ -4,7 +4,6 @@ import shutil import threading from abc import abstractmethod -from datetime import datetime from distutils.sysconfig import get_python_lib from time import sleep from typing import List, Optional @@ -43,16 +42,18 @@ def on_run(self, app, algorithm: Algorithm): class App: def __init__(self, stateless=False, web=False): - self._flask_app: Flask = None + self._flask_app: Optional[Flask] = None self.container = None self._stateless = stateless self._web = web - self._algorithm: Algorithm = None + self._algorithm: Optional[Algorithm] = None self._started = False self._tasks = [] self._configuration_service = None - self._market_data_source_service: MarketDataSourceService = None - self._market_credential_service: MarketCredentialService = None + self._market_data_source_service: \ + Optional[MarketDataSourceService] = None + self._market_credential_service: \ + Optional[MarketCredentialService] = None self._on_initialize_hooks = [] self._on_after_initialize_hooks = [] @@ -95,6 +96,12 @@ def initialize(self, sync=False): if self.algorithm is None: raise OperationalException("No algorithm registered") + # Check if the algorithm has data sources registered + if len(self.algorithm.data_sources) == 0: + + for data_source in self.algorithm.data_sources: + self.add_market_data_source(data_source) + self.algorithm.initialize_services( configuration_service=self.container.configuration_service(), market_data_source_service=self.container @@ -237,9 +244,7 @@ def _initialize_standard(self): def _initialize_app_for_backtest( self, - backtest_start_date, - backtest_end_date, - market_data_sources, + backtest_date_range: BacktestDateRange, pending_order_check_interval=None, ) -> None: """ @@ -249,8 +254,7 @@ def _initialize_app_for_backtest( before running a backtest or a set of backtests and should be called once. - :param backtest_start_date: The start date of the backtest - :param backtest_end_date: The end date of the backtest + :param backtest_date_range: instance of BacktestDateRange :param pending_order_check_interval: The interval at which to check pending orders (e.g. 1h, 1d, 1w) :return: None @@ -259,8 +263,9 @@ def _initialize_app_for_backtest( configuration_service = self.container.configuration_service() configuration_service.config[BACKTESTING_FLAG] = True configuration_service.config[BACKTESTING_START_DATE] = \ - backtest_start_date - configuration_service.config[BACKTESTING_END_DATE] = backtest_end_date + backtest_date_range.start_date + configuration_service.config[BACKTESTING_END_DATE] = \ + backtest_date_range.end_date if pending_order_check_interval is not None: configuration_service.config[ @@ -270,9 +275,43 @@ def _initialize_app_for_backtest( # Create resource dir if not exits self._create_resource_directory_if_not_exists() + def _initialize_algorithm_for_backtest(self, algorithm): + configuration_service = self.container.configuration_service() + resource_dir = configuration_service.config[RESOURCE_DIRECTORY] + + # Create the database if not exists + configuration_service.config[DATABASE_DIRECTORY_PATH] = \ + os.path.join(resource_dir, "databases") + configuration_service.config[DATABASE_NAME] = \ + "backtest-database.sqlite3" + database_path = os.path.join( + configuration_service.config[DATABASE_DIRECTORY_PATH], + configuration_service.config[DATABASE_NAME] + ) + + if os.path.exists(database_path): + os.remove(database_path) + + configuration_service.config[SQLALCHEMY_DATABASE_URI] = \ + "sqlite:///" + os.path.join( + configuration_service.config[DATABASE_DIRECTORY_PATH], + configuration_service.config[DATABASE_NAME] + ) + self._create_database_if_not_exists() + setup_sqlalchemy(self) + create_all_tables() + # Override the MarketDataSourceService service with the backtest # market data source service equivalent. Additionally, convert the # market data sources to backtest market data sources + # Get all market data source services + market_data_sources = self._market_data_source_service\ + .get_market_data_sources() + + if algorithm.data_sources is not None \ + and len(algorithm.data_sources) > 0: + for data_source in algorithm.data_sources: + self.add_market_data_source(data_source) if market_data_sources is not None: backtest_market_data_sources = [ @@ -341,50 +380,6 @@ def _initialize_app_for_backtest( if portfolio_configuration_service.count() == 0: raise OperationalException("No portfolios configured") - def _initialize_algorithm(self): - self.algorithm.initialize_services( - configuration_service=self.container.configuration_service(), - portfolio_configuration_service=self.container - .portfolio_configuration_service(), - portfolio_service=self.container.portfolio_service(), - position_service=self.container.position_service(), - order_service=self.container.order_service(), - market_service=self.container.market_service(), - strategy_orchestrator_service=self.container - .strategy_orchestrator_service(), - market_credential_service=self.container - .market_credential_service(), - market_data_source_service=self.container - .market_data_source_service(), - trade_service=self.container.trade_service(), - ) - - def _initialize_algorithm_for_backtest(self, algorithm): - configuration_service = self.container.configuration_service() - resource_dir = configuration_service.config[RESOURCE_DIRECTORY] - - # Create the database if not exists - configuration_service.config[DATABASE_DIRECTORY_PATH] = \ - os.path.join(resource_dir, "databases") - configuration_service.config[DATABASE_NAME] = \ - "backtest-database.sqlite3" - database_path = os.path.join( - configuration_service.config[DATABASE_DIRECTORY_PATH], - configuration_service.config[DATABASE_NAME] - ) - - if os.path.exists(database_path): - os.remove(database_path) - - configuration_service.config[SQLALCHEMY_DATABASE_URI] = \ - "sqlite:///" + os.path.join( - configuration_service.config[DATABASE_DIRECTORY_PATH], - configuration_service.config[DATABASE_NAME] - ) - self._create_database_if_not_exists() - setup_sqlalchemy(self) - create_all_tables() - strategy_orchestrator_service = \ self.container.strategy_orchestrator_service() market_credential_service = self.container.market_credential_service() @@ -458,6 +453,7 @@ def run( stateless mode :param number_of_iterations: The number of iterations to run the algorithm for + :param sync: Whether to sync the portfolio with the exchange :return: None """ @@ -623,10 +619,9 @@ def _create_resource_directory_if_not_exists(self): "A resource directory is required for running a backtest." ) - if not os.path.exists(resource_dir): + if not os.path.isdir(resource_dir): try: os.makedirs(resource_dir) - open(resource_dir, 'w').close() except OSError as e: logger.error(e) raise OperationalException( @@ -673,8 +668,7 @@ def get_portfolio_configurations(self): def run_backtest( self, algorithm, - start_date, - end_date, + backtest_date_range: BacktestDateRange, pending_order_check_interval=None, output_directory=None ) -> BacktestReport: @@ -684,8 +678,8 @@ def run_backtest( :param algorithm: The algorithm to run a backtest for (instance of Algorithm) - :param start_date: The start date of the backtest - :param end_date: The end date of the backtest + :param backtest_date_range: The date range to run the backtest for + (instance of BacktestDateRange) :param pending_order_check_interval: The interval at which to check pending orders :param output_directory: The directory to write the backtest report to @@ -694,17 +688,12 @@ def run_backtest( logger.info("Initializing backtest") self.algorithm = algorithm - if end_date is None: - end_date = datetime.utcnow() - market_data_sources = self._market_data_source_service\ .get_market_data_sources() self._initialize_app_for_backtest( - backtest_start_date=start_date, - backtest_end_date=end_date, + backtest_date_range=backtest_date_range, pending_order_check_interval=pending_order_check_interval, - market_data_sources=market_data_sources ) self._initialize_algorithm_for_backtest( @@ -717,7 +706,7 @@ def run_backtest( # Run the backtest with the backtest_service and collect the report report = backtest_service.run_backtest( - algorithm=self.algorithm, start_date=start_date, end_date=end_date + algorithm=self.algorithm, backtest_date_range=backtest_date_range ) backtest_report_writer_service = self.container \ .backtest_report_writer_service() @@ -737,9 +726,7 @@ def run_backtest( def run_backtests( self, algorithms, - start_date: Optional[datetime] = None, - end_date: Optional[datetime] = None, - date_ranges: Optional[List[BacktestDateRange]] = None, + date_ranges: List[BacktestDateRange] = None, pending_order_check_interval=None, output_directory=None ) -> List[BacktestReport]: @@ -749,8 +736,6 @@ def run_backtests( :param algorithms: The algorithms to run backtests for (list of Algorithm instances) - :param start_date: The start date of the backtest - :param end_date: The end date of the backtest :param pending_order_check_interval: The interval at which to check :param date_ranges: The date ranges to run the backtests for (list of BacktestDateRange instances representing a start and end date) @@ -761,36 +746,17 @@ def run_backtests( logger.info("Initializing backtests") reports = [] - if start_date is not None: - - if end_date is None: - end_date = datetime.utcnow() - - date_ranges = [ - BacktestDateRange(start_date=start_date, end_date=end_date) - ] - else: - if date_ranges is None: - raise OperationalException("No date ranges specified") - - market_data_sources = self._market_data_source_service\ - .get_market_data_sources() - for date_range in date_ranges: date_range: BacktestDateRange = date_range - start_date = date_range.start_date - end_date = date_range.end_date self._initialize_app_for_backtest( - backtest_start_date=start_date, - backtest_end_date=end_date, + backtest_date_range=date_range, pending_order_check_interval=pending_order_check_interval, - market_data_sources=market_data_sources ) print( f"{COLOR_YELLOW}Running backtests for date " - f"range:{COLOR_RESET} {COLOR_GREEN}{start_date} - " - f"{end_date} for a " + f"range:{COLOR_RESET} {COLOR_GREEN}{date_range.name} {date_range.start_date} - " + f"{date_range.end_date} for a " f"total of {len(algorithms)} algorithms.{COLOR_RESET}" ) for algorithm in algorithms: @@ -803,9 +769,7 @@ def run_backtests( # Run the backtest with the backtest_service # and collect the report report = backtest_service.run_backtest( - algorithm=algorithm, - start_date=start_date, - end_date=end_date + algorithm=algorithm, backtest_date_range=date_range ) # Add date range name to report if present diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py b/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py index 2a31e88b..cca3a6c5 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py @@ -1,4 +1,5 @@ from datetime import datetime +from dateutil.parser import parse class BacktestDateRange: @@ -6,6 +7,13 @@ class BacktestDateRange: Represents a date range for a backtest """ def __init__(self, start_date, end_date=None, name=None): + + if isinstance(start_date, str): + start_date = parse(start_date) + + if end_date is not None and isinstance(end_date, str): + end_date = parse(end_date) + self._start_date = start_date self._end_date = end_date self._name = name @@ -13,6 +21,12 @@ def __init__(self, start_date, end_date=None, name=None): if end_date is None: self._end_date = datetime.now() + if end_date < start_date: + raise ValueError( + "End date cannot be before start date for a backtest " + "date range." + ) + @property def start_date(self): return self._start_date @@ -24,3 +38,6 @@ def end_date(self): @property def name(self): return self._name + + def __str__(self): + return f"{self.name}: {self._start_date} - {self._end_date}" diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py index d62876a0..04c63d84 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py @@ -1,7 +1,10 @@ from datetime import datetime +from pandas import DataFrame from investing_algorithm_framework.domain.models.base_model import BaseModel from investing_algorithm_framework.domain.models.time_unit import TimeUnit +from investing_algorithm_framework.domain.models\ + .backtesting.backtest_date_range import BacktestDateRange from investing_algorithm_framework.domain.constants import DATETIME_FORMAT @@ -9,21 +12,17 @@ class BacktestReport(BaseModel): def __init__( self, + backtest_date_range: BacktestDateRange, name=None, time_unit=None, interval=0, strategy_identifiers=None, initial_unallocated=0.0, number_of_runs=0, - backtest_start_date_data=None, - backtest_data_index_date=None, - backtest_start_date=None, - backtest_end_date=None, trading_time_frame=None, trading_time_frame_start_date=None, symbols=None, market=None, - number_of_days=0, number_of_orders=0, number_of_positions=0, market_data_file=None, @@ -48,15 +47,12 @@ def __init__( ): self._name = name self._strategy_identifiers = strategy_identifiers - self._backtest_start_date_data = backtest_start_date_data - self._backtest_start_date = backtest_start_date - self._backtest_end_date = backtest_end_date + self.backtest_date_range = backtest_date_range self._number_of_runs = number_of_runs self._trading_time_frame = trading_time_frame self._trading_time_frame_start_date = trading_time_frame_start_date self._symbols = symbols self._market = market - self._number_of_days = number_of_days self._number_of_orders = number_of_orders self._number_of_positions = number_of_positions self._market_data_file = market_data_file @@ -71,7 +67,6 @@ def __init__( self._trading_symbol = trading_symbol self._total_net_gain_percentage = total_net_gain_percentage self._total_net_gain = total_net_gain - self._backtest_data_index_date = backtest_data_index_date self._total_value = total_value self._positions = positions self._orders = orders @@ -82,6 +77,9 @@ def __init__( self._interval = interval self._time_unit = time_unit self._context = context + self._number_of_days = \ + (self.backtest_date_range.end_date + - self.backtest_date_range.start_date).days @property def name(self): @@ -107,18 +105,6 @@ def portfolio_id(self, portfolio_id): def symbols(self): return self._symbols - @property - def backtest_start_date_data(self): - return self._backtest_start_date_data - - @property - def backtest_start_date(self): - return self._backtest_start_date - - @property - def backtest_end_date(self): - return self._backtest_end_date - @property def trading_time_frame(self): return self._trading_time_frame @@ -147,18 +133,6 @@ def symbols(self, value): def market(self, value): self._market = value - @backtest_start_date.setter - def backtest_start_date(self, value): - self._backtest_start_date = value - - @backtest_start_date_data.setter - def backtest_start_date_data(self, value): - self._backtest_start_date_data = value - - @backtest_end_date.setter - def backtest_end_date(self, value): - self._backtest_end_date = value - @number_of_runs.setter def number_of_runs(self, value): self._number_of_runs = value @@ -171,10 +145,6 @@ def trading_time_frame(self, value): def trading_time_frame_start_date(self, value): self._trading_time_frame_start_date = value - @number_of_days.setter - def number_of_days(self, value): - self._number_of_days = value - @property def number_of_orders(self): return self._number_of_orders @@ -378,12 +348,22 @@ def get_runs_per_day(self): else: return 24 / self.interval + @property + def backtest_start_date(self): + return self.backtest_date_range.start_date + + @property + def backtest_end_date(self): + return self.backtest_date_range.end_date + def __repr__(self): return self.repr( name=self.name, - start_date=self.backtest_start_date, - end_date=self.backtest_end_date, - start_date_data=self.backtest_start_date_data, + backtest_date_range=self.backtest_date_range, + profit=self.get_profit(), + profit_percentage=self.get_profit_percentage(), + growth=self.get_growth(), + growth_percentage=self.get_growth_percentage(), ) def to_dict(self): @@ -391,13 +371,25 @@ def to_dict(self): Convert the backtest report to a dictionary. So it can be saved to a file. """ + + # Convert context to a dictionary + if self.context is not None: + + for key, value in self.context.items(): + if isinstance(value, datetime): + self.context[key] = value.strftime(DATETIME_FORMAT) + + if isinstance(value, DataFrame): + self.context[key] = value.to_json() + return { "name": self.name, "context": self.context if self.context is not None else {}, "strategy_identifiers": self.strategy_identifiers, - "backtest_start_date": self.backtest_start_date + "backtest_date_range_identifier": self.backtest_date_range.name, + "backtest_start_date": self.backtest_date_range.start_date .strftime(DATETIME_FORMAT), - "backtest_end_date": self.backtest_end_date + "backtest_end_date": self.backtest_date_range.end_date .strftime(DATETIME_FORMAT), "number_of_runs": self.number_of_runs, "symbols": self.symbols, @@ -434,15 +426,21 @@ def from_dict(data): """ Factory method to create a backtest report from a dictionary. """ + + backtest_date_range = BacktestDateRange( + start_date=datetime.strptime( + data["backtest_start_date"], DATETIME_FORMAT), + end_date=datetime.strptime( + data["backtest_end_date"], DATETIME_FORMAT) + ) + return BacktestReport( name=data["name"], strategy_identifiers=data["strategy_identifiers"], - backtest_start_date=data["backtest_start_date"], - backtest_end_date=data["backtest_end_date"], number_of_runs=data["number_of_runs"], + backtest_date_range=backtest_date_range, symbols=data["symbols"], market=data["market"], - number_of_days=data["number_of_days"], number_of_orders=data["number_of_orders"], number_of_positions=data["number_of_positions"], market_data_file=data["market_data_file"], @@ -461,3 +459,29 @@ def from_dict(data): average_trade_duration=data["average_trade_duration"], average_trade_size=float(data["average_trade_size"]), ) + + def get_trades(self, symbol=None): + """ + Function to get trades. If a symbol is provided, it will + return the trades for that symbol. If no symbol is provided, + it will return all the trades. + """ + if symbol is None: + return self.trades + + return [trade for trade in self.trades if trade.symbol == symbol] + + def get_profit(self) -> float: + return self._total_net_gain + + def get_profit_percentage(self) -> float: + return self._total_net_gain_percentage + + def get_growth(self) -> float: + return self._growth + + def get_growth_percentage(self) -> float: + return self._growth_rate + + def get_trading_symbol(self) -> str: + return self.trading_symbol diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py b/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py index 0635f735..5fa4afb1 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py @@ -1,40 +1,55 @@ -from datetime import datetime -from typing import List, Dict, Tuple +from typing import List, Dict +from investing_algorithm_framework.domain.exceptions import \ + OperationalException +from investing_algorithm_framework.domain.models.backtesting\ + .backtest_date_range import BacktestDateRange from .backtest_report import BacktestReport class BacktestReportsEvaluation: """ A class to evaluate backtest reports. + + This class is used to evaluate backtest reports and order them based on + different metrics. It also groups the reports by backtest date range. + + The class has methods to get the best algorithm based on profit and growth. """ - report_groupings: Dict[Tuple[datetime, datetime], List[BacktestReport]] + report_groupings: Dict[BacktestDateRange, List[BacktestReport]] def __init__(self, backtest_reports: List[BacktestReport]): + + if backtest_reports is None: + raise OperationalException("No backtest reports to evaluate") + self.backtest_reports = backtest_reports self.group_reports(self.backtest_reports) self.profit_order = {} - + self.profit_order_grouped_by_date = {} self.growth_order = {} + self.growth_order_grouped_by_date = {} self.percentage_positive_trades_order = {} + self.percentage_positive_trades_order_grouped_by_date = {} + # Calculate all metrics and group reports for key in self.report_groupings: - self.profit_order[key] = self.order_on_profit( + self.profit_order_grouped_by_date[key] = self.order_on_profit( self.report_groupings[key].copy() ) - self.growth_order[key] = self.order_on_growth( + self.growth_order_grouped_by_date[key] = self.order_on_growth( self.report_groupings[key].copy() ) - self.percentage_positive_trades_order[key] = \ + self.percentage_positive_trades_order_grouped_by_date[key] = \ self.order_on_positive_trades( self.report_groupings[key].copy() ) - self.profit_order_all = self.order_on_profit( - self.backtest_reports.copy() - ) - self.growth_order_all = self.order_on_growth( - self.backtest_reports.copy() - ) + + # Overall ordered reports + self.percentage_positive_trades_order = \ + self.order_on_positive_trades(self.backtest_reports) + self.growth_order = self.order_on_growth(self.backtest_reports) + self.profit_order = self.order_on_profit(self.backtest_reports) def order_on_profit(self, reports: List[BacktestReport]): return sorted(reports, key=lambda x: x.total_net_gain, reverse=True) @@ -54,7 +69,7 @@ def group_reports(self, reports: List[BacktestReport]): self.report_groupings = {} for report in reports: - key = (report.backtest_start_date, report.backtest_end_date) + key = report.backtest_date_range if key not in self.report_groupings: self.report_groupings[key] = [] self.report_groupings[key].append(report) @@ -64,3 +79,162 @@ def get_date_ranges(self): Get the date ranges of the backtest reports. """ return list(self.report_groupings.keys()) + + def get_profit_order( + self, backtest_date_range: BacktestDateRange = None + ) -> List[BacktestReport]: + """ + Function to get profit order of all the backtest reports + in an ordered list. + + :param backtest_date_range: Tuple with two datetime objects + :return: List of backtest reports + """ + + if backtest_date_range is None: + return self.profit_order + else: + + if backtest_date_range in self.profit_order_grouped_by_date: + return self.profit_order_grouped_by_date[backtest_date_range] + + raise OperationalException("No matches for given date range") + + def get_growth_order( + self, backtest_date_range: BacktestDateRange = None + ) -> List[BacktestReport]: + """ + Function to get growth order of all the backtest reports + in an ordered list. + + :param backtest_date_range: Tuple with two datetime objects + :return: List of backtest reports + """ + + if backtest_date_range is None: + return self.growth_order + else: + + if backtest_date_range in self.growth_order_grouped_by_date: + return self.growth_order_grouped_by_date[backtest_date_range] + + raise OperationalException("No matches for given date range") + + def get_percentage_positive_trades_order( + self, backtest_date_range: BacktestDateRange = None + ) -> List[BacktestReport]: + """ + Function to get growth order of all the backtest reports + in an ordered list. + + :param backtest_date_range: Tuple with two datetime objects + :return: List of backtest reports + """ + + if backtest_date_range is None: + return self.percentage_positive_trades_order + else: + + if backtest_date_range in \ + self.percentage_positive_trades_order_grouped_by_date: + return self.percentage_positive_trades_order_grouped_by_date[ + backtest_date_range + ] + + raise OperationalException("No matches for given date range") + + def rank( + self, + weight_profit=0.7, + weight_growth=0.3, + backtest_date_range: BacktestDateRange = None + ) -> str: + """ + Function to get the best overall algorithm based on the + weighted sum of profit and growth. + + :param weight_profit: Weight for profit + :param weight_growth: Weight for growth + :return: Name of the best algorithm + """ + + # Create a dictionary with the algorithm name as key and group + # the reports by name + ordered_reports = {} + + if backtest_date_range is not None: + reports = self.report_groupings[backtest_date_range] + else: + reports = self.backtest_reports + + for report in reports: + if report.name not in ordered_reports: + ordered_reports[report.name] = [] + ordered_reports[report.name].append(report) + + best_algorithm = None + best_score = 0 + profit_score = 0 + growth_score = 0 + + for algorithm in ordered_reports: + profit_score += sum( + [report.total_net_gain for report in ordered_reports[algorithm]] + ) + growth_score += sum( + [report.growth for report in + ordered_reports[algorithm]] + ) + score = weight_profit * profit_score + weight_growth * growth_score + + if score > best_score: + best_score = score + best_algorithm = algorithm + + profit_score = 0 + growth_score = 0 + + return best_algorithm + + def get_reports( + self, name: str = None, backtest_date_range: BacktestDateRange = None + ) -> List[BacktestReport]: + """ + Function to get all the reports for a given algorithm name. + + :param name: Name of the algorithm + :param backtest_date_range: Tuple with two datetime objects + :return: List of backtest reports + """ + + if name is not None and backtest_date_range is not None: + return [ + report for report in self.report_groupings[backtest_date_range] + if report.name == name + ] + + if name is not None: + return [ + report for report in self.backtest_reports if report.name == name + ] + + if backtest_date_range is not None: + return self.report_groupings[backtest_date_range] + + def get_report( + self, name: str, backtest_date_range: BacktestDateRange = None + ): + """ + Function to get the report for a given algorithm name and date range. + + :param name: Name of the algorithm + :param backtest_date_range: Tuple with two datetime objects + :return: Backtest report + """ + reports = self.get_reports(name, backtest_date_range) + + if len(reports) == 0: + raise OperationalException("No matches for given name and date range") + + return reports[0] + diff --git a/investing_algorithm_framework/domain/models/time_frame.py b/investing_algorithm_framework/domain/models/time_frame.py index eb26dc41..4bfac240 100644 --- a/investing_algorithm_framework/domain/models/time_frame.py +++ b/investing_algorithm_framework/domain/models/time_frame.py @@ -11,11 +11,11 @@ class TimeFrame(Enum): TEN_MINUTE = "10m" FIFTEEN_MINUTE = "15m" THIRTY_MINUTE = "30m" - ONE_HOUR = "1H" - TWO_HOUR = "2H" - FOUR_HOUR = "4H" - TWELVE_HOUR = "12H" - ONE_DAY = "1D" + ONE_HOUR = "1h" + TWO_HOUR = "2h" + FOUR_HOUR = "4h" + TWELVE_HOUR = "12h" + ONE_DAY = "1d" ONE_WEEK = "1W" ONE_MONTH = "1M" ONE_YEAR = "1Y" diff --git a/investing_algorithm_framework/domain/services/market_data_sources.py b/investing_algorithm_framework/domain/services/market_data_sources.py index f6d7ff59..605afc55 100644 --- a/investing_algorithm_framework/domain/services/market_data_sources.py +++ b/investing_algorithm_framework/domain/services/market_data_sources.py @@ -3,7 +3,6 @@ import os from abc import abstractmethod, ABC from datetime import datetime, timedelta -from typing import Callable import polars @@ -21,16 +20,12 @@ def __init__( identifier, market, symbol, - start_date=None, - end_date=None, backtest_data_start_date=None, backtest_data_index_date=None, ): self._identifier = identifier self._market = market self._symbol = symbol - self._start_date = start_date - self._end_date = end_date self._backtest_data_start_date = backtest_data_start_date self._backtest_data_index_date = backtest_data_index_date @@ -95,13 +90,17 @@ def prepare_data( pass @abstractmethod - def get_data( - self, - backtest_index_date, - from_time_stamp=None, - to_time_stamp=None, - **kwargs - ): + def get_data(self, **kwargs): + """ + Get data from the market data source. + :param kwargs: Additional arguments to get the data. Common arguments + - start_date: datetime + - end_date: datetime + - timeframe: str + - backtest_start_date: datetime + - backtest_end_date: datetime + - backtest_data_index_date: datetime + """ pass @property @@ -166,13 +165,7 @@ def __init__( self._market = market self._symbol = symbol self._market_credential_service = None - - def initialize(self, config): - pass - - @property - def identifier(self): - return self._identifier + self._config = None @property def config(self): @@ -182,6 +175,13 @@ def config(self): def config(self, value): self._config = value + def initialize(self, config): + pass + + @property + def identifier(self): + return self._identifier + def get_identifier(self): return self.identifier @@ -200,20 +200,15 @@ def get_symbol(self): return self.symbol @abstractmethod - def get_data( - self, - time_stamp=None, - from_time_stamp=None, - to_time_stamp=None, - **kwargs - ): + def get_data(self, **kwargs): """ Get data from the market data source. + :param kwargs: Additional arguments to get the data. Common arguments + - start_date: datetime + - end_date: datetime + - timeframe: str - :param time_stamp: The time stamp of the data to get. - :param from_time_stamp: The time stamp from which to get data. - :param to_time_stamp: The time stamp to which to get data. - :param kwargs: Additional arguments. + :return: Object with the data """ pass @@ -241,10 +236,6 @@ def __init__( symbol, timeframe, window_size=None, - start_date=None, - start_date_func=None, - end_date=None, - end_date_func=None, ): super().__init__( identifier=identifier, @@ -252,37 +243,9 @@ def __init__( symbol=symbol, ) self._window_size = window_size - self._timeframe = timeframe - self._start_date = start_date - self._start_date_func = start_date_func - self._end_date = end_date - self._end_date_func = end_date_func - self.initialize_window_size() - - def initialize_window_size(self): - """ - Method to determine the window size of ohlcv market data source - """ - if self._window_size is None: - start_date = self.start_date - end_date = self.end_date - - if not isinstance(start_date, datetime): - raise OperationalException( - "start_date or start_date_func must be a datetime object" - ) - - if not isinstance(end_date, datetime): - raise OperationalException( - "end_date or end_date_func must be a datetime object" - ) - - minutes_diff = \ - (self.end_date - self.start_date).total_seconds() / 60 - windows_size_minutes = TimeFrame.from_string(self.timeframe)\ - .amount_of_minutes - self._window_size = minutes_diff / windows_size_minutes + if timeframe is not None: + self._timeframe = TimeFrame.from_value(timeframe) @property def timeframe(self): @@ -291,81 +254,64 @@ def timeframe(self): def get_timeframe(self): return self.timeframe - @property - def start_date(self): - """ - Get the start date of the market data source. - - if window_size is not None and the start date is, - the start date will be calculated based on the end date - and the window size. - - If the start date is not None, the start date will be returned. - - If the start date function is not None, the start date function will - be called and the result will be returned. - """ - - if self.window_size is not None: + def create_start_date(self, end_date, timeframe, window_size): + minutes = TimeFrame.from_value(timeframe).amount_of_minutes + return end_date - timedelta(minutes=window_size * minutes) - if self._start_date is not None: - return self._start_date - - minutes = TimeFrame.from_string(self.timeframe).amount_of_minutes - return self.end_date - \ - timedelta(minutes=self.window_size * minutes) - - if self._start_date_func is not None: - return self._start_date_func() - else: - return self._start_date - - def get_start_date(self): - return self.start_date + def create_end_date(self, start_date, timeframe, window_size): + minutes = TimeFrame.from_value(timeframe).amount_of_minutes + return start_date + timedelta(minutes=window_size * minutes) @property - def start_date_func(self): - return self._start_date_func - - @property - def end_date(self): + def window_size(self): + return self._window_size - if self._end_date_func is not None: - return self._end_date_func() - elif self._end_date is not None: - return self._end_date - else: - return datetime.utcnow() + def get_date_ranges( + self, + start_date: datetime, + end_date: datetime, + window_size: int, + timeframe + ): + """ + Function to get the date ranges of the market data source based + on the window size and the timeframe. The date ranges + will be calculated based on the start date and the end date. + """ - def get_end_date(self): - return self.end_date + if start_date > end_date: + raise OperationalException( + "Start date must be before end date" + ) - @property - def end_date_func(self): - return self._end_date_func + timeframe = TimeFrame.from_value(timeframe) + new_end_date = start_date + timedelta( + minutes=window_size * timeframe.amount_of_minutes + ) + ranges = [(start_date, new_end_date)] + start_date = new_end_date - @end_date.setter - def end_date(self, value): - self._end_date = value + if new_end_date > end_date: + return [(start_date, end_date)] - @start_date.setter - def start_date(self, value): - self._start_date = value + while start_date < end_date: + new_end_date = start_date + timedelta( + minutes=self.window_size * timeframe.amount_of_minutes + ) - @end_date_func.setter - def end_date_func(self, func: Callable): - self._end_date_func = func + if new_end_date > end_date: + new_end_date = end_date - @start_date_func.setter - def start_date_func(self, func: Callable): - self._start_date_func = func + ranges.append((start_date, new_end_date)) + start_date = new_end_date - @property - def window_size(self): - return self._window_size + return ranges class TickerMarketDataSource(MarketDataSource, ABC): + """ + Abstract class for ticker market data sources. + """ def __init__( self, @@ -381,6 +327,9 @@ def __init__( class OrderBookMarketDataSource(MarketDataSource, ABC): + """ + Abstract class for order book market data sources. + """ def __init__( self, diff --git a/investing_algorithm_framework/domain/services/market_service.py b/investing_algorithm_framework/domain/services/market_service.py index 3695a658..ac7e8264 100644 --- a/investing_algorithm_framework/domain/services/market_service.py +++ b/investing_algorithm_framework/domain/services/market_service.py @@ -12,6 +12,15 @@ class MarketService(ABC): def __init__(self, market_credential_service): self._market_credential_service = market_credential_service + self._config = None + + @property + def config(self): + return self._config + + @config.setter + def config(self, value): + self._config = value @abstractmethod def pair_exists( diff --git a/investing_algorithm_framework/domain/utils/backtesting.py b/investing_algorithm_framework/domain/utils/backtesting.py index aaae32f7..1f89641a 100644 --- a/investing_algorithm_framework/domain/utils/backtesting.py +++ b/investing_algorithm_framework/domain/utils/backtesting.py @@ -5,12 +5,12 @@ from tabulate import tabulate -from investing_algorithm_framework.domain import DATETIME_FORMAT +from investing_algorithm_framework.domain import DATETIME_FORMAT, \ + BacktestDateRange from investing_algorithm_framework.domain.exceptions import \ OperationalException from investing_algorithm_framework.domain.models.backtesting import \ BacktestReportsEvaluation, BacktestReport -from .csv import load_csv_into_dict COLOR_RED = '\033[91m' COLOR_PURPLE = '\033[95m' @@ -19,30 +19,6 @@ COLOR_YELLOW = '\033[93m' -def print_tables_side_by_side(*tables, spacing: int = 3): - string_tables_split = [tabulate(t, headers="firstrow") - .splitlines() for t in tables] - spacing_str = " " * spacing - - num_lines = max(map(len, string_tables_split)) - paddings = [max(map(len, s_lines)) for s_lines in string_tables_split] - - for i in range(num_lines): - line_each_table = [] - for padding, table_lines in zip(paddings, string_tables_split): - if len(table_lines) <= i: - line_each_table.append(" " * (padding + spacing)) - else: - line_table_string = table_lines[i] - line_len = len(line_table_string) - line_each_table.append( - line_table_string + (" " * (padding - line_len)) + spacing_str - ) - - final_line_string = "".join(line_each_table) - print(final_line_string) - - def is_positive(number) -> bool: """ Check if a number is positive. @@ -54,99 +30,57 @@ def is_positive(number) -> bool: return number > 0 -def pretty_print_profit_evaluation( - evaluation: BacktestReportsEvaluation, - date_range, - precision=4, - number_of_reports=3 -): - profits = evaluation.profit_order[date_range] +def pretty_print_profit_evaluation(reports, precision=4): profit_table = {} profit_table["Algorithm name"] = [ - report.name for report in profits[:number_of_reports] + report.name for report in reports ] profit_table["Profit"] = [ f"{report.total_net_gain:.{precision}f} {report.trading_symbol}" - for report in profits[:number_of_reports] + for report in reports ] profit_table["Profit percentage"] = [ - f"{report.total_net_gain_percentage:.{precision}f}%" for report in profits[:number_of_reports] + f"{report.total_net_gain_percentage:.{precision}f}%" for report in reports ] - - print(f"{COLOR_YELLOW}Profit:{COLOR_RESET} {COLOR_GREEN}Top {number_of_reports}{COLOR_RESET}") - print(tabulate(profit_table, headers="keys", tablefmt="rounded_grid")) - - least_profits = profits[-number_of_reports:] - least_profit_table = {} - least_profit_table["Algorithm name"] = [ - report.name for report in least_profits - ] - least_profit_table["Profit"] = [ - f"{report.total_net_gain:.{precision}f} {report.trading_symbol}" for - report in least_profits + profit_table["Date range"] = [ + f"{report.backtest_date_range.name} {report.backtest_date_range.start_date} - {report.backtest_date_range.end_date}" + for report in reports ] - least_profit_table["Profit percentage"] = [ - f"{report.total_net_gain_percentage:.{precision}f}%" for report in - least_profits + profit_table["Total value"] = [ + f"{report.total_value:.{precision}f}" for report in reports ] - - print(f"{COLOR_RED}Least profit:{COLOR_RESET} {COLOR_GREEN}Top {number_of_reports}{COLOR_RESET}") - print(tabulate(least_profit_table, headers="keys", tablefmt="rounded_grid")) + print(tabulate(profit_table, headers="keys", tablefmt="rounded_grid")) -def pretty_print_growth_evaluation( - evaluation: BacktestReportsEvaluation, - date_range, - precision=4, - number_of_reports=3 -): - growths = evaluation.growth_order[date_range] - print(f"{COLOR_YELLOW}Growth:{COLOR_RESET} {COLOR_GREEN}Top {number_of_reports}{COLOR_RESET}") +def pretty_print_growth_evaluation(reports, precision=4): growth_table = {} growth_table["Algorithm name"] = [ - report.name for report in growths[:number_of_reports] + report.name for report in reports ] growth_table["Growth"] = [ - f"{report.growth:.{precision}f} {report.trading_symbol}" for report in growths[:number_of_reports] + f"{report.growth:.{precision}f} {report.trading_symbol}" for report in reports ] growth_table["Growth percentage"] = [ - f"{report.growth_rate:.{precision}f}%" for report in growths[:number_of_reports] - ] - print( - tabulate(growth_table, headers="keys", tablefmt="rounded_grid") - ) - - least_growths = growths[-number_of_reports:] - least_growth_table = {} - least_growth_table["Algorithm name"] = [ - report.name for report in least_growths + f"{report.growth_rate:.{precision}f}%" for report in reports ] - least_growth_table["Growth"] = [ - f"{report.growth:.{precision}f} {report.trading_symbol}" for - report in least_growths + growth_table["Date range"] = [ + f"{report.backtest_date_range.name} {report.backtest_date_range.start_date} - {report.backtest_date_range.end_date}" + for report in reports ] - least_growth_table["Growth percentage"] = [ - f"{report.growth_rate:.{precision}f}%" for report in - least_growths + growth_table["Total value"] = [ + f"{report.total_value:.{precision}f}" for report in reports ] - - print( - f"{COLOR_RED}Least growth:{COLOR_RESET} {COLOR_GREEN}" - f"Top {number_of_reports}{COLOR_RESET}" - ) print( - tabulate( - least_growth_table, headers="keys", tablefmt="rounded_grid" - ) + tabulate(growth_table, headers="keys", tablefmt="rounded_grid") ) def pretty_print_percentage_positive_trades_evaluation( evaluation: BacktestReportsEvaluation, - date_range, + backtest_date_range: BacktestDateRange, precision=0, number_of_reports=3 ): - order = evaluation.percentage_positive_trades_order[date_range] + order = evaluation.get_percentage_positive_trades_order(backtest_date_range=backtest_date_range) print(f"{COLOR_YELLOW}Trades:{COLOR_RESET} {COLOR_GREEN}Top {number_of_reports}{COLOR_RESET}") profit_table = {} profit_table["Algorithm name"] = [ @@ -188,7 +122,7 @@ def pretty_print_percentage_positive_trades_evaluation( ) -def pretty_print_date_ranges(date_ranges: List[Tuple[datetime]]) -> None: +def pretty_print_date_ranges(date_ranges: List[BacktestDateRange]) -> None: """ Pretty print the date ranges to the console. @@ -196,8 +130,8 @@ def pretty_print_date_ranges(date_ranges: List[Tuple[datetime]]) -> None: """ print(f"{COLOR_YELLOW}Date ranges of backtests:{COLOR_RESET}") for date_range in date_ranges: - start_date = date_range[0] - end_date = date_range[1] + start_date = date_range.start_date + end_date = date_range.end_date if isinstance(start_date, datetime): start_date = start_date.strftime(DATETIME_FORMAT) @@ -205,126 +139,104 @@ def pretty_print_date_ranges(date_ranges: List[Tuple[datetime]]) -> None: if isinstance(end_date, datetime): end_date = end_date.strftime(DATETIME_FORMAT) - print(f"{COLOR_GREEN}{start_date} - {end_date}{COLOR_RESET}") + if date_range.name is not None: + print(f"{COLOR_GREEN}{date_range.name}: {start_date} - {end_date}{COLOR_RESET}") + else: + print(f"{COLOR_GREEN}{start_date} - {end_date}{COLOR_RESET}") def pretty_print_most_profitable( evaluation: BacktestReportsEvaluation, - date_range, + backtest_date_range: BacktestDateRange, precision=4, ): - profits = evaluation.profit_order[date_range] + profits = evaluation.get_profit_order(backtest_date_range=backtest_date_range) profit = profits[0] print(f"{COLOR_YELLOW}Most profitable:{COLOR_RESET} {COLOR_GREEN}Algorithm {profit.name} {profit.total_net_gain:.{precision}f} {profit.trading_symbol} {profit.total_net_gain_percentage:.{precision}f}%{COLOR_RESET}") def pretty_print_most_growth( evaluation: BacktestReportsEvaluation, - date_range, + backtest_date_range: BacktestDateRange, precision=4, ): - profits = evaluation.growth_order[date_range] + profits = evaluation.get_growth_order(backtest_date_range=backtest_date_range) profit = profits[0] print(f"{COLOR_YELLOW}Most growth:{COLOR_RESET} {COLOR_GREEN}Algorithm {profit.name} {profit.growth:.{precision}f} {profit.trading_symbol} {profit.growth_rate:.{precision}f}%{COLOR_RESET}") def pretty_print_percentage_positive_trades( evaluation: BacktestReportsEvaluation, - date_range, + backtest_date_range: BacktestDateRange, precision=0 ): - percentages = evaluation.percentage_positive_trades_order[date_range] + percentages = evaluation.get_percentage_positive_trades_order(backtest_date_range=backtest_date_range) percentages = percentages[0] print(f"{COLOR_YELLOW}Most positive trades:{COLOR_RESET} {COLOR_GREEN}Algorithm {percentages.name} {percentages.percentage_positive_trades:.{precision}f}%{COLOR_RESET}") def pretty_print_backtest_reports_evaluation( backtest_reports_evaluation: BacktestReportsEvaluation, - precision=4 + precision=4, + backtest_date_range: BacktestDateRange = None ) -> None: """ Pretty print the backtest reports evaluation to the console. """ - number_of_backtest_reports = len(backtest_reports_evaluation.backtest_reports) - most_profitable = backtest_reports_evaluation.profit_order_all[0] - most_growth = backtest_reports_evaluation.growth_order_all[0] + if backtest_date_range is not None: + reports = backtest_reports_evaluation.get_reports(backtest_date_range=backtest_date_range) + + if len(reports) == 0: + print(f"No reports available for date range {backtest_date_range}") + return + else: + reports = backtest_reports_evaluation.backtest_reports + + number_of_backtest_reports = len(reports) + most_profitable = backtest_reports_evaluation.get_profit_order(backtest_date_range)[0] + most_growth = backtest_reports_evaluation.get_growth_order(backtest_date_range)[0] + ascii_art = f""" - {COLOR_PURPLE}/{COLOR_RESET}&{COLOR_PURPLE}#{COLOR_RESET} {COLOR_PURPLE}#{COLOR_RESET}&{COLOR_PURPLE}({COLOR_RESET} {COLOR_GREEN}Backtest reports evaluation{COLOR_RESET} - &&&&&&&&&&&# &&&&&&&&&&&& {COLOR_GREEN}---------------------------{COLOR_RESET} - &&&&&&&&&&&&&&&& (&&&&&&&&&&&&&&& {COLOR_YELLOW}Number of reports:{COLOR_RESET} {COLOR_GREEN}{number_of_backtest_reports} backtest reports{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Total number of date ranges:{COLOR_RESET}{COLOR_GREEN}{len(backtest_reports_evaluation.get_date_ranges())}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Largest overall profit:{COLOR_RESET}{COLOR_GREEN}{COLOR_RESET}{COLOR_GREEN} (Algorithm {most_profitable.name}) {most_profitable.total_net_gain:.{precision}f} {most_profitable.trading_symbol} {most_profitable.total_net_gain_percentage:.{precision}f}% ({most_profitable.backtest_start_date} - {most_profitable.backtest_end_date}){COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Largest overall growth:{COLOR_RESET}{COLOR_GREEN} (Algorithm {most_profitable.name}) {most_growth.growth:.{precision}f} {most_growth.trading_symbol} {most_growth.growth_rate:.{precision}f}% ({most_growth.backtest_start_date} - {most_growth.backtest_end_date}){COLOR_RESET} - .&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}.{COLOR_RESET} - &&&&&&&# {COLOR_PURPLE}/((({COLOR_RESET} &&&&&&&&&&&&{COLOR_PURPLE}*((({COLOR_RESET} .&&&&&&&{COLOR_PURPLE}.{COLOR_RESET} - &&&&&&&&&&&&&&&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&&&&&&&&&&&&&&& - {COLOR_PURPLE}((({COLOR_RESET}&&&&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&&&&&{COLOR_PURPLE}(({COLOR_RESET} - {COLOR_PURPLE}/(((((((((({COLOR_RESET}&&&&&&&&&& {COLOR_PURPLE}(((,{COLOR_RESET} &&&&&& {COLOR_PURPLE}(((**{COLOR_RESET}&&&&&&&&&{COLOR_PURPLE}((((((((((({COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE},{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&{COLOR_PURPLE}#{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} #&&&&&&&&&&{COLOR_PURPLE}###{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&{COLOR_PURPLE}###.{COLOR_RESET} - {COLOR_PURPLE}.((((({COLOR_RESET} &&&&&&&&&&&&&&{COLOR_PURPLE}###({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&{COLOR_PURPLE}#(((/{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&@{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}((((,{COLOR_RESET} - {COLOR_PURPLE}.((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}#(((({COLOR_RESET} - {COLOR_PURPLE}(((((((((((((((((((#########{COLOR_RESET}&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}((((({COLOR_RESET} - {COLOR_PURPLE}(((((((((((((((((((((######{COLOR_RESET}&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} + :%%%#+- .=*#%%% {COLOR_GREEN}Backtest reports evaluation{COLOR_RESET} + *%%%%%%%+------=*%%%%%%%- {COLOR_GREEN}---------------------------{COLOR_RESET} + *%%%%%%%%%%%%%%%%%%%%%%%- {COLOR_YELLOW}Number of reports:{COLOR_RESET} {COLOR_GREEN}{number_of_backtest_reports} backtest reports{COLOR_RESET} + .%%%%%%%%%%%%%%%%%%%%%%# {COLOR_YELLOW}Largest overall profit:{COLOR_RESET}{COLOR_GREEN}{COLOR_RESET}{COLOR_GREEN} (Algorithm {most_profitable.name}) {most_profitable.total_net_gain:.{precision}f} {most_profitable.trading_symbol} {most_profitable.total_net_gain_percentage:.{precision}f}% ({most_profitable.backtest_date_range.name} {most_profitable.backtest_date_range.start_date} - {most_profitable.backtest_date_range.end_date}){COLOR_RESET} + #%%%####%%%%%%%%**#%%%+ {COLOR_YELLOW}Largest overall growth:{COLOR_RESET}{COLOR_GREEN} (Algorithm {most_profitable.name}) {most_growth.growth:.{precision}f} {most_growth.trading_symbol} {most_growth.growth_rate:.{precision}f}% ({most_growth.backtest_date_range.name} {most_growth.backtest_date_range.start_date} - {most_growth.backtest_date_range.end_date}){COLOR_RESET} + .:-+*%%%%- {COLOR_PURPLE}-+..#{COLOR_RESET}%%%+.{COLOR_PURPLE}+- +{COLOR_RESET}%%%#*=-: + .:-=*%%%%. {COLOR_PURPLE}+={COLOR_RESET} .%%# {COLOR_PURPLE}-+.-{COLOR_RESET}%%%%=-:.. + .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: + +%%%%%%%%%%%%%%%%%%%= + :++ .=#%%%%%%%%%%%%%*- + :++: :+%%%%%%#-. + :++: .%%%%%#= + :++: .#%%%%%#*= + :++- :%%%%%%%%%+= + .++- -%%%%%%%%%%%+= + .++- .%%%%%%%%%%%%%+= + .++- *%%%%%%%%%%%%%*+: + .++- %%%%%%%%%%%%%%#+= + =++........:::%%%%%%%%%%%%%%*+- + .=++++++++++**#%%%%%%%%%%%%%++. """ + if len(backtest_reports_evaluation.backtest_reports) == 0: print("No backtest reports available in your evaluation") return print(ascii_art) - pretty_print_date_ranges(backtest_reports_evaluation.get_date_ranges()) - print("") - date_ranges = backtest_reports_evaluation.get_date_ranges() - - for date_range in date_ranges: - start_date = date_range[0] - end_date = date_range[1] - - if isinstance(start_date, datetime): - start_date = start_date.strftime(DATETIME_FORMAT) - - if isinstance(end_date, datetime): - end_date = end_date.strftime(DATETIME_FORMAT) - - print( - f"{COLOR_YELLOW}Evaluation of date range:{COLOR_RESET} {COLOR_GREEN}{start_date} - {end_date}{COLOR_RESET}") - print( - f"{COLOR_GREEN}-------------------------------------------------------------------{COLOR_RESET}") - pretty_print_most_profitable( - backtest_reports_evaluation, date_range, precision - ) - pretty_print_most_growth( - backtest_reports_evaluation, date_range, precision - ) - pretty_print_percentage_positive_trades( - backtest_reports_evaluation, date_range - ) + if backtest_date_range is None: + pretty_print_date_ranges(backtest_reports_evaluation.get_date_ranges()) print("") - pretty_print_profit_evaluation( - backtest_reports_evaluation, date_range, precision - ) - pretty_print_growth_evaluation( - backtest_reports_evaluation, date_range, precision - ) - pretty_print_percentage_positive_trades_evaluation( - backtest_reports_evaluation, date_range, precision=0 - ) + + print(f"{COLOR_YELLOW}All profits ordered{COLOR_RESET}") + pretty_print_profit_evaluation( + backtest_reports_evaluation.get_profit_order(backtest_date_range), precision + ) + print(f"{COLOR_YELLOW}All growths ordered{COLOR_RESET}") + pretty_print_growth_evaluation( + backtest_reports_evaluation.get_growth_order(backtest_date_range), precision + ) def print_number_of_runs(report): @@ -349,38 +261,26 @@ def pretty_print_backtest( """ ascii_art = f""" - {COLOR_PURPLE}/{COLOR_RESET}&{COLOR_PURPLE}#{COLOR_RESET} {COLOR_PURPLE}#{COLOR_RESET}&{COLOR_PURPLE}({COLOR_RESET} {COLOR_GREEN}Backtest report{COLOR_RESET} - &&&&&&&&&&&# &&&&&&&&&&&& {COLOR_GREEN}---------------------------{COLOR_RESET} - &&&&&&&&&&&&&&&& (&&&&&&&&&&&&&&& {COLOR_YELLOW}Start date:{COLOR_RESET}{COLOR_GREEN} {backtest_report.backtest_start_date}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}End date:{COLOR_RESET}{COLOR_GREEN} {backtest_report.backtest_end_date}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Number of days:{COLOR_RESET}{COLOR_GREEN}{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_days}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Number of runs:{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_runs}{COLOR_RESET} - .&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Number of orders:{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_orders}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}.{COLOR_RESET} {COLOR_YELLOW}Initial balance:{COLOR_RESET}{COLOR_GREEN} {backtest_report.initial_unallocated}{COLOR_RESET} - &&&&&&&# {COLOR_PURPLE}/((({COLOR_RESET} &&&&&&&&&&&&{COLOR_PURPLE}*((({COLOR_RESET} .&&&&&&&{COLOR_PURPLE}.{COLOR_RESET} {COLOR_YELLOW}Final balance:{COLOR_RESET}{COLOR_GREEN} {backtest_report.total_value:.{precision}f}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Total net gain:{COLOR_RESET}{COLOR_GREEN} {backtest_report.total_net_gain:.{precision}f} {backtest_report.total_net_gain_percentage:.{precision}}%{COLOR_RESET} - {COLOR_PURPLE}((({COLOR_RESET}&&&&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&& {COLOR_PURPLE}(((({COLOR_RESET} &&&&&&&&&{COLOR_PURPLE}(({COLOR_RESET} {COLOR_YELLOW}Growth:{COLOR_RESET}{COLOR_GREEN} {backtest_report.growth:.{precision}f} {backtest_report.growth_rate:.{precision}}%{COLOR_RESET} - {COLOR_PURPLE}/(((((((((({COLOR_RESET}&&&&&&&&&& {COLOR_PURPLE}(((,{COLOR_RESET} &&&&&& {COLOR_PURPLE}(((**{COLOR_RESET}&&&&&&&&&{COLOR_PURPLE}((((((((((({COLOR_RESET} {COLOR_YELLOW}Number of trades closed:{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_trades_closed}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Number of trades open(end of backtest):{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_trades_open}{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Percentage positive trades:{COLOR_RESET}{COLOR_GREEN} {backtest_report.percentage_positive_trades}%{COLOR_RESET} - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& {COLOR_YELLOW}Percentage negative trades:{COLOR_RESET}{COLOR_GREEN} {backtest_report.percentage_negative_trades}%{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}({COLOR_RESET} {COLOR_YELLOW}Average trade size:{COLOR_RESET}{COLOR_GREEN} {backtest_report.average_trade_size:.{precision}f} {backtest_report.trading_symbol}{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE},{COLOR_RESET} {COLOR_YELLOW}Average trade duration:{COLOR_RESET}{COLOR_GREEN} {backtest_report.average_trade_duration} hours{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&{COLOR_PURPLE}#{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} #&&&&&&&&&&{COLOR_PURPLE}###{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&{COLOR_PURPLE}###.{COLOR_RESET} - {COLOR_PURPLE}.((((({COLOR_RESET} &&&&&&&&&&&&&&{COLOR_PURPLE}###({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&{COLOR_PURPLE}#(((/{COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&@{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}((((,{COLOR_RESET} - {COLOR_PURPLE}.((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} - {COLOR_PURPLE}((((({COLOR_RESET} &&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}#(((({COLOR_RESET} - {COLOR_PURPLE}(((((((((((((((((((#########{COLOR_RESET}&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}((((({COLOR_RESET} - {COLOR_PURPLE}(((((((((((((((((((((######{COLOR_RESET}&&&&&&&&&&&&&&&&&&&&&&&&&&&&{COLOR_PURPLE}(((({COLOR_RESET} + :%%%#+- .=*#%%% {COLOR_GREEN}Backtest report{COLOR_RESET} + *%%%%%%%+------=*%%%%%%%- {COLOR_GREEN}---------------------------{COLOR_RESET} + *%%%%%%%%%%%%%%%%%%%%%%%- {COLOR_YELLOW}Start date:{COLOR_RESET}{COLOR_GREEN} {backtest_report.backtest_start_date}{COLOR_RESET} + .%%%%%%%%%%%%%%%%%%%%%%# {COLOR_YELLOW}End date:{COLOR_RESET}{COLOR_GREEN} {backtest_report.backtest_end_date}{COLOR_RESET} + #%%%####%%%%%%%%**#%%%+ {COLOR_YELLOW}Number of days:{COLOR_RESET}{COLOR_GREEN}{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_days}{COLOR_RESET} + .:-+*%%%%- {COLOR_PURPLE}-+..#{COLOR_RESET}%%%+.{COLOR_PURPLE}+- +{COLOR_RESET}%%%#*=-: {COLOR_YELLOW}Number of runs:{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_runs}{COLOR_RESET} + .:-=*%%%%. {COLOR_PURPLE}+={COLOR_RESET} .%%# {COLOR_PURPLE}-+.-{COLOR_RESET}%%%%=-:.. {COLOR_YELLOW}Number of orders:{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_orders}{COLOR_RESET} + .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: {COLOR_YELLOW}Initial balance:{COLOR_RESET}{COLOR_GREEN} {backtest_report.initial_unallocated}{COLOR_RESET} + +%%%%%%%%%%%%%%%%%%%= {COLOR_YELLOW}Final balance:{COLOR_RESET}{COLOR_GREEN} {backtest_report.total_value:.{precision}f}{COLOR_RESET} + :++ .=#%%%%%%%%%%%%%*- {COLOR_YELLOW}Total net gain:{COLOR_RESET}{COLOR_GREEN} {backtest_report.total_net_gain:.{precision}f} {backtest_report.total_net_gain_percentage:.{precision}}%{COLOR_RESET} + :++: :+%%%%%%#-. {COLOR_YELLOW}Growth:{COLOR_RESET}{COLOR_GREEN} {backtest_report.growth:.{precision}f} {backtest_report.growth_rate:.{precision}}%{COLOR_RESET} + :++: .%%%%%#= {COLOR_YELLOW}Number of trades closed:{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_trades_closed}{COLOR_RESET} + :++: .#%%%%%#*= {COLOR_YELLOW}Number of trades open(end of backtest):{COLOR_RESET}{COLOR_GREEN} {backtest_report.number_of_trades_open}{COLOR_RESET} + :++- :%%%%%%%%%+= {COLOR_YELLOW}Percentage positive trades:{COLOR_RESET}{COLOR_GREEN} {backtest_report.percentage_positive_trades}%{COLOR_RESET} + .++- -%%%%%%%%%%%+= {COLOR_YELLOW}Percentage negative trades:{COLOR_RESET}{COLOR_GREEN} {backtest_report.percentage_negative_trades}%{COLOR_RESET} + .++- .%%%%%%%%%%%%%+= {COLOR_YELLOW}Average trade size:{COLOR_RESET}{COLOR_GREEN} {backtest_report.average_trade_size:.{precision}f} {backtest_report.trading_symbol}{COLOR_RESET} + .++- *%%%%%%%%%%%%%*+: {COLOR_YELLOW}Average trade duration:{COLOR_RESET}{COLOR_GREEN} {backtest_report.average_trade_duration} hours{COLOR_RESET} + .++- %%%%%%%%%%%%%%#+= + =++........:::%%%%%%%%%%%%%%*+- + .=++++++++++**#%%%%%%%%%%%%%++. """ print(ascii_art) diff --git a/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py b/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py index 0fe3571d..8d004a83 100644 --- a/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +++ b/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py @@ -1,7 +1,8 @@ +import datetime import logging import os from datetime import timedelta - +from dateutil.parser import parse import polars from dateutil import parser @@ -45,23 +46,18 @@ def __init__( market, symbol, timeframe, - start_date=None, window_size=None, - start_date_func=None, - end_date_func=None, - end_date=None, ): super().__init__( identifier=identifier, market=market, symbol=symbol, timeframe=timeframe, - start_date=start_date, - start_date_func=start_date_func, - end_date=end_date, - end_date_func=end_date_func, window_size=window_size, ) + self.data = None + self._start_date_data_source = None + self._end_date_data_source = None def prepare_data( self, @@ -81,21 +77,11 @@ def prepare_data( When downloading the data it will use the ccxt library. """ # Calculating the backtest data start date - difference = self.end_date - self.start_date - total_minutes = 0 - - if difference.days > 0: - total_minutes += difference.days * 24 * 60 - - if difference.seconds > 0: - total_minutes += difference.seconds / 60 - - self.total_minutes_timeframe = total_minutes backtest_data_start_date = \ backtest_start_date - timedelta( minutes=( - self.window_size * - TimeFrame.from_string(self.timeframe).amount_of_minutes + (self.window_size + 1) * + TimeFrame.from_value(self.timeframe).amount_of_minutes ) ) self.backtest_data_start_date = backtest_data_start_date\ @@ -133,20 +119,30 @@ def prepare_data( market_service.config = config ohlcv = market_service.get_ohlcv( symbol=self.symbol, - time_frame=self.timeframe, + time_frame=self.timeframe.value, from_timestamp=backtest_data_start_date, to_timestamp=backtest_end_date, market=self.market ) self.write_data_to_file_path(file_path, ohlcv) + self.load_data() + + def load_data(self): + file_path = self._create_file_path() + self.data = polars.read_csv(file_path) + first_row = self.data.head(1) + last_row = self.data.tail(1) + self._start_date_data_source = parse(first_row["Datetime"][0]) + self._end_date_data_source = parse(last_row["Datetime"][0]) + def _create_file_path(self): """ Function to create a filename in the following format: OHLCV_{symbol}_{market}_{timeframe}_{start_date}_{end_date}.csv """ symbol_string = self.symbol.replace("/", "-") - time_frame_string = self.timeframe.replace("_", "") + time_frame_string = self.timeframe.value.replace("_", "") backtest_data_start_date = \ self.backtest_data_start_date.strftime(DATETIME_FORMAT_BACKTESTING) backtest_data_end_date = \ @@ -163,44 +159,57 @@ def _create_file_path(self): ) ) - def get_data(self, backtest_index_date, **kwargs): + def get_data(self, **kwargs): """ Get data implementation of ccxt based ohlcv backtest market data source. This implementation will use polars to load and filter the data. """ - file_path = self._create_file_path() - to_timestamp = backtest_index_date - from_timestamp = backtest_index_date - timedelta( - minutes=self.total_minutes_timeframe - ) - datetime_format = self._config["DATETIME_FORMAT"] - self.backtest_data_index_date = backtest_index_date\ - .replace(microsecond=0) - from_timestamp = from_timestamp.replace(microsecond=0) + start_date = kwargs.get("start_date") + end_date = kwargs.get("end_date") + backtest_index_date = kwargs.get("backtest_index_date") + + if self.data is None: + self.load_data() + + if start_date is None \ + and end_date is None \ + and backtest_index_date is None: + return self.data + + if backtest_index_date is not None: + end_date = backtest_index_date + start_date = self.create_start_date( + end_date, self.timeframe, self.window_size + ) + else: + if start_date is None: + start_date = self.create_start_date( + end_date, self.timeframe, self.window_size + ) - if from_timestamp < self.backtest_data_start_date: + if end_date is None: + end_date = self.create_end_date( + start_date, self.timeframe, self.window_size + ) + + if start_date < self._start_date_data_source: raise OperationalException( - f"Cannot get data from {from_timestamp} as the " - f"backtest data starts at {self.start_date}" + f"Start date {start_date} is before the start date " + f"of the data source {self._start_date_data_source}" ) - if to_timestamp > self.backtest_data_end_date: + if end_date > self._end_date_data_source: raise OperationalException( - f"Cannot get data to {to_timestamp} as the " - f"backtest data ends at {self.end_date}" + f"End date {end_date} is after the end date " + f"of the data source {self._end_date_data_source}" ) - # Load the csv file and filter out the dates that are not in the - # backtest index date range - df = polars.read_csv( - file_path, columns=self.column_names, separator="," - ) - df = df.filter( - (df['Datetime'] >= from_timestamp.strftime(datetime_format)) - & (df['Datetime'] <= to_timestamp.strftime(datetime_format)) + selection = self.data.filter( + (self.data['Datetime'] >= start_date.strftime(DATETIME_FORMAT)) + & (self.data['Datetime'] <= end_date.strftime(DATETIME_FORMAT)) ) - return df + return selection def to_backtest_market_data_source(self) -> BacktestMarketDataSource: # Ignore this method for now @@ -407,23 +416,62 @@ def write_data_to_file_path(self, data_file, data: polars.DataFrame): class CCXTOHLCVMarketDataSource(OHLCVMarketDataSource): + """ + CCXTOHLCVMarketDataSource implementation of OHLCVMarketDataSource using + ccxt to download all ohlcv data sources. + """ def get_data(self, **kwargs): + """ + Implementation of get_data for CCXTOHLCVMarketDataSource. + This implementation uses the CCXTMarketService to get the OHLCV data. + + In the kwargs, the start_date should be set as a datetime object. + + returns a polars.DataFrame with the OHLCV data + """ market_service = CCXTMarketService( market_credential_service=self.market_credential_service, ) - market_service.config = self.config - if self.start_date is None: + + # Add config if present + if self.config is not None: + market_service.config = self.config + + if "start_date" in kwargs: + start_date = kwargs["start_date"] + + if not isinstance(start_date, datetime.datetime): + raise OperationalException( + "start_date should be a datetime object" + ) + else: + raise OperationalException( + "start_date should be set for CCXTOHLCVMarketDataSource" + ) + + if "end_date" not in kwargs: + end_date = self.create_end_date( + start_date, self.timeframe, self.window_size + ) + else: + end_date = kwargs["end_date"] + + if not isinstance(end_date, datetime.datetime): + raise OperationalException( + "end_date should be a datetime object" + ) + + if not isinstance(start_date, datetime.datetime): raise OperationalException( - "Either start_date or start_date_func should be set " - "for OHLCVMarketDataSource" + "start_date should be a datetime object" ) return market_service.get_ohlcv( symbol=self.symbol, time_frame=self.timeframe, - from_timestamp=self.start_date, - to_timestamp=self.end_date, + from_timestamp=start_date, + to_timestamp=end_date, market=self.market ) @@ -432,11 +480,8 @@ def to_backtest_market_data_source(self) -> BacktestMarketDataSource: identifier=self.identifier, market=self.market, symbol=self.symbol, - start_date=self.start_date, - start_date_func=self.start_date_func, - end_date=self.end_date, - end_date_func=self.end_date_func, timeframe=self.timeframe, + window_size=self.window_size ) diff --git a/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py b/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py index f32bb12a..71d13004 100644 --- a/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +++ b/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py @@ -1,23 +1,24 @@ import logging -from datetime import datetime +from datetime import datetime, timedelta import polars from dateutil.parser import parse from investing_algorithm_framework.domain import OHLCVMarketDataSource, \ BacktestMarketDataSource, OperationalException, TickerMarketDataSource, \ - DATETIME_FORMAT + DATETIME_FORMAT, TimeFrame logger = logging.getLogger(__name__) class CSVOHLCVMarketDataSource(OHLCVMarketDataSource): + """ + Implementation of a OHLCV data source that reads OHLCV data from a csv file. + Market data source that reads OHLCV data from a csv file. + """ - def empty(self): - data = self.get_data( - from_time_stamp=self.start_date, - to_time_stamp=self.end_date - ) + def empty(self, start_date, end_date): + data = self.get_data(start_date=start_date, end_date=end_date) return len(data) == 0 def __init__( @@ -27,10 +28,6 @@ def __init__( market=None, symbol=None, timeframe=None, - start_date=None, - start_date_func=None, - end_date=None, - end_date_func=None, window_size=None, ): super().__init__( @@ -38,10 +35,6 @@ def __init__( market=market, symbol=symbol, timeframe=timeframe, - start_date=start_date, - start_date_func=start_date_func, - end_date=end_date, - end_date_func=end_date_func, window_size=window_size, ) self._csv_file_path = csv_file_path @@ -63,32 +56,65 @@ def __init__( first_row = df.head(1) last_row = df.tail(1) - self._start_date = parse(first_row["Datetime"][0]) - self._end_date = parse(last_row["Datetime"][0]) + self._start_date_data_source = parse(first_row["Datetime"][0]) + self._end_date_data_source = parse(last_row["Datetime"][0]) @property def csv_file_path(self): return self._csv_file_path - def get_data( - self, - from_timestamp=None, - to_timestamp=None, - **kwargs - ): + def get_data(self, **kwargs): + """ + Get the data from the csv file. The data can be filtered by + the start_date and end_date in the kwargs. backtest_index_date + can also be provided to filter the data, where this will be used + as start_date. + """ + start_date = kwargs.get("start_date") + end_date = kwargs.get("end_date") + backtest_index_date = kwargs.get("backtest_index_date") + + if start_date is None \ + and end_date is None \ + and backtest_index_date is None: + return polars.read_csv( + self.csv_file_path, columns=self._columns, separator="," + ) - if from_timestamp is None: - from_timestamp = self.start_date + if backtest_index_date is not None: + end_date = backtest_index_date + start_date = self.create_start_date( + end_date, self.timeframe, self.window_size + ) + else: + if start_date is None: + start_date = self.create_start_date( + end_date, self.timeframe, self.window_size + ) + + if end_date is None: + end_date = self.create_end_date( + start_date, self.timeframe, self.window_size + ) + + if start_date > self._start_date_data_source: + raise OperationalException( + f"Start date {start_date} is before the start date " + f"of the data source {self._start_date_data_source}" + ) - if to_timestamp is None: - to_timestamp = self.end_date + if end_date < self._end_date_data_source: + raise OperationalException( + f"End date {end_date} is after the end date " + f"of the data source {self._end_date_data_source}" + ) df = polars.read_csv( self.csv_file_path, columns=self._columns, separator="," ) df = df.filter( - (df['Datetime'] >= from_timestamp.strftime(DATETIME_FORMAT)) - & (df['Datetime'] <= to_timestamp.strftime(DATETIME_FORMAT)) + (df['Datetime'] >= start_date.strftime(DATETIME_FORMAT)) + & (df['Datetime'] <= end_date.strftime(DATETIME_FORMAT)) ) return df diff --git a/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py b/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py index feb78b7b..64168488 100644 --- a/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +++ b/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py @@ -8,7 +8,7 @@ from dateutil import parser from investing_algorithm_framework.domain import OperationalException, Order, \ - MarketService + MarketService, DATETIME_FORMAT, TimeFrame logger = logging.getLogger(__name__) @@ -142,7 +142,6 @@ def get_order_books(self, symbols, market): def get_order(self, order, market): market_credential = self.get_market_credential(market) exchange = self.initialize_exchange(market, market_credential) - symbol = f"{order.target_symbol.upper()}/" \ f"{order.trading_symbol.upper()}" @@ -242,12 +241,12 @@ def create_limit_buy_order( raise OperationalException("Could not create limit buy order") def create_limit_sell_order( - self, - target_symbol: str, - trading_symbol: str, - amount: float, - price: float, - market + self, + target_symbol: str, + trading_symbol: str, + amount: float, + price: float, + market ): market_credential = self.get_market_credential(market) exchange = self.initialize_exchange(market, market_credential) @@ -357,7 +356,12 @@ def get_closed_orders( def get_ohlcv( self, symbol, time_frame, from_timestamp, market, to_timestamp=None ) -> pl.DataFrame: - datetime_format = self.config["DATETIME_FORMAT"] + time_frame = TimeFrame.from_value(time_frame).value + + if self.config is not None: + datetime_format = self.config["DATETIME_FORMAT"] + else: + datetime_format = DATETIME_FORMAT market_credential = self.get_market_credential(market) exchange = self.initialize_exchange(market, market_credential) @@ -422,6 +426,7 @@ def get_ohlcvs( to_timestamp=None ) -> Dict[str, pl.DataFrame]: ohlcvs = {} + time_frame = TimeFrame.from_value(time_frame).value for symbol in symbols: diff --git a/investing_algorithm_framework/services/__init__.py b/investing_algorithm_framework/services/__init__.py index 01c4e0ff..16cb0120 100644 --- a/investing_algorithm_framework/services/__init__.py +++ b/investing_algorithm_framework/services/__init__.py @@ -1,4 +1,5 @@ -from .backtesting import BacktestService, BacktestReportWriterService +from .backtesting import BacktestService, BacktestReportWriterService, \ + create_trade_exit_markers_chart, create_trade_entry_markers_chart from .configuration_service import ConfigurationService from .market_credential_service import MarketCredentialService from .market_data_source_service import MarketDataSourceService, \ @@ -31,5 +32,7 @@ "MarketCredentialService", "BacktestMarketDataSourceService", "BacktestPortfolioService", - "TradeService" + "TradeService", + "create_trade_entry_markers_chart", + "create_trade_exit_markers_chart" ] diff --git a/investing_algorithm_framework/services/backtesting/__init__.py b/investing_algorithm_framework/services/backtesting/__init__.py index f0c34538..7971f65f 100644 --- a/investing_algorithm_framework/services/backtesting/__init__.py +++ b/investing_algorithm_framework/services/backtesting/__init__.py @@ -1,8 +1,12 @@ from .backtest_report_writer_service import BacktestReportWriterService from .backtest_service import BacktestService +from .graphs import create_trade_entry_markers_chart, \ + create_trade_exit_markers_chart __all__ = [ "BacktestReportWriterService", - "BacktestService" + "BacktestService", + "create_trade_entry_markers_chart", + "create_trade_exit_markers_chart" ] diff --git a/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py b/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py index 5bdeeae2..8702dfb1 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py @@ -11,38 +11,17 @@ class BacktestReportWriterService: Service to write backtest reports to a file. Service supports writing backtest reports to the following formats: - - CSV + - JSON """ - def write_report_to_csv( - self, report: BacktestReport, output_directory: str - ) -> str: - """ - Write a backtest report to a CSV file. - """ - - if not os.path.exists(output_directory): - os.makedirs(output_directory) - - csv_file_path = self.create_report_name( - report, output_directory, extension=".csv" - ) - report_dict = report.to_dict() - - with open(csv_file_path, 'w', newline='') as csv_file: - writer = csv.DictWriter(csv_file, fieldnames=report_dict.keys()) - writer.writeheader() - writer.writerow(report_dict) - - return csv_file_path def write_report_to_json( self, report: BacktestReport, output_directory: str ): if not os.path.exists(output_directory): os.makedirs(output_directory) - backtest_start_date = report.backtest_start_date\ + backtest_start_date = report.backtest_date_range.start_date\ .strftime(DATETIME_FORMAT_BACKTESTING) - backtest_end_date = report.backtest_end_date\ + backtest_end_date = report.backtest_date_range.end_date\ .strftime(DATETIME_FORMAT_BACKTESTING) created_at = report.created_at.strftime(DATETIME_FORMAT_BACKTESTING) json_file_path = os.path.join( diff --git a/investing_algorithm_framework/services/backtesting/backtest_service.py b/investing_algorithm_framework/services/backtesting/backtest_service.py index 5bf8142b..54f16214 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_service.py @@ -7,7 +7,7 @@ from investing_algorithm_framework.domain import BacktestReport, \ BACKTESTING_INDEX_DATETIME, TimeUnit, BacktestPosition, \ TradingDataType, OrderStatus, OperationalException, MarketDataSource, \ - OrderSide + OrderSide, SYMBOLS, BacktestDateRange from investing_algorithm_framework.services.market_data_source_service import \ MarketDataSourceService @@ -16,14 +16,15 @@ class BacktestService: """ Service that facilitates backtests for algorithm objects. """ + def __init__( - self, - market_data_source_service: MarketDataSourceService, - order_service, - portfolio_repository, - position_repository, - performance_service, - configuration_service + self, + market_data_source_service: MarketDataSourceService, + order_service, + portfolio_repository, + position_repository, + performance_service, + configuration_service ): self._resource_directory = None self._order_service = order_service @@ -48,7 +49,7 @@ def resource_directory(self, resource_directory): self._resource_directory = resource_directory def run_backtest( - self, algorithm, start_date, end_date=None + self, algorithm, backtest_date_range: BacktestDateRange ) -> BacktestReport: """ Run a backtest for the given algorithm. This function will run @@ -61,8 +62,7 @@ def run_backtest( the backtest is run for each date in the schedule. :param algorithm: The algorithm to run the backtest for - :param start_date: The start date of the backtest - :param end_date: The end date of the backtest + :param backtest_date_range: The backtest date range :return: The backtest report instance of BacktestReport """ @@ -76,18 +76,13 @@ def run_backtest( for strategy in algorithm.strategies: strategy_profiles.append(strategy.strategy_profile) - if end_date is None: - end_date = datetime.utcnow() - - if start_date > end_date: - raise OperationalException( - "Start date cannot be greater than end date for backtest" - ) + # Check if required market data sources are registered + self._check_if_required_market_data_sources_are_registered() schedule = self.generate_schedule( strategies=algorithm.strategies, - start_date=start_date, - end_date=end_date + start_date=backtest_date_range.start_date, + end_date=backtest_date_range.end_date ) for index, row in tqdm( @@ -106,18 +101,19 @@ def run_backtest( index_date=index_date, ) return self.create_backtest_report( - algorithm, len(schedule), start_date, end_date, initial_unallocated + algorithm, len(schedule), backtest_date_range, initial_unallocated ) - def run_backtests(self, algorithms, start_date, end_date=None): + def run_backtests( + self, algorithms, backtest_date_range: BacktestDateRange + ): """ Run backtests for the given algorithms. This function will run backtests for the given algorithms and return a list of backtest reports. :param algorithms: The algorithms to run the backtests for - :param start_date: The start date of the backtests - :param end_date: The end date of the backtests + :param backtest_date_range: The backtest date range of the backtests :return: A list of backtest reports """ backtest_reports = [] @@ -126,8 +122,7 @@ def run_backtests(self, algorithms, start_date, end_date=None): backtest_reports.append( self.run_backtest( algorithm=algorithm, - start_date=start_date, - end_date=end_date + backtest_date_range=backtest_date_range ) ) @@ -150,14 +145,13 @@ def run_backtest_for_profile(self, algorithm, strategy, index_date): market_data[data_id] = \ self._market_data_source_service.get_data(data_id) - # self._order_service.check_pending_orders() strategy.run_strategy(algorithm=algorithm, market_data=market_data) def generate_schedule( - self, - strategies, - start_date, - end_date + self, + strategies, + start_date, + end_date ): data = [] @@ -209,8 +203,7 @@ def create_backtest_report( self, algorithm, number_of_runs, - start_date, - end_date, + backtest_date_range: BacktestDateRange, initial_unallocated=0 ) -> BacktestReport: """ @@ -222,11 +215,11 @@ def create_backtest_report( :param algorithm: The algorithm to create the backtest report for :param number_of_runs: The number of runs - :param start_date: The start date of the backtest - :param end_date: The end date of the backtest + :param backtest_date_range: The backtest date range of the backtest :param initial_unallocated: The initial unallocated amount :return: The backtest report instance of BacktestReport """ + for portfolio in self._portfolio_repository.get_all(): ids = [strategy.strategy_id for strategy in algorithm.strategies] @@ -238,14 +231,12 @@ def create_backtest_report( backtest_profile = BacktestReport( name=algorithm.name, strategy_identifiers=ids, - backtest_start_date=start_date, - backtest_end_date=end_date, + backtest_date_range=backtest_date_range, initial_unallocated=initial_unallocated, trading_symbol=portfolio.trading_symbol, created_at=datetime.utcnow(), ) backtest_profile.number_of_runs = number_of_runs - backtest_profile.number_of_days = (end_date - start_date).days backtest_profile.number_of_orders = self._order_service.count({ "portfolio": portfolio.id }) @@ -255,22 +246,22 @@ def create_backtest_report( "amount_gt": 0 }) backtest_profile.percentage_negative_trades = \ - self._performance_service\ + self._performance_service \ .get_percentage_negative_trades(portfolio.id) backtest_profile.percentage_positive_trades = \ - self._performance_service\ + self._performance_service \ .get_percentage_positive_trades(portfolio.id) backtest_profile.number_of_trades_closed = \ - self._performance_service\ + self._performance_service \ .get_number_of_trades_closed(portfolio.id) backtest_profile.number_of_trades_open = \ - self._performance_service\ + self._performance_service \ .get_number_of_trades_open(portfolio.id) backtest_profile.total_cost = portfolio.total_cost backtest_profile.total_net_gain = portfolio.total_net_gain backtest_profile.total_net_gain_percentage = \ - self._performance_service\ - .get_total_net_gain_percentage_of_backtest( + self._performance_service \ + .get_total_net_gain_percentage_of_backtest( portfolio.id, backtest_profile ) positions = self._position_repository.get_all({ @@ -286,6 +277,20 @@ def create_backtest_report( if position.symbol != portfolio.trading_symbol: ticker_symbol = \ f"{position.symbol}/{portfolio.trading_symbol}" + + if not self._market_data_source_service \ + .has_ticker_market_data_source( + symbol=ticker_symbol, market=portfolio.market + ): + raise OperationalException( + f"Ticker market data source for " + f"symbol {ticker_symbol} " + f"and market {portfolio.market} not found, please " + f"make sure you register a ticker market " + f"data source for this symbol and market " + f"in backtest mode. Otherwise, the backtest report" + " cannot be generated." + ) tickers[ticker_symbol] = \ self._market_data_source_service.get_ticker( f"{position.symbol}/{portfolio.trading_symbol}", @@ -294,16 +299,16 @@ def create_backtest_report( backtest_profile.growth_rate = self._performance_service \ .get_growth_rate_of_backtest( - portfolio.id, tickers, backtest_profile - ) + portfolio.id, tickers, backtest_profile + ) backtest_profile.growth = self._performance_service \ .get_growth_of_backtest( - portfolio.id, tickers, backtest_profile - ) + portfolio.id, tickers, backtest_profile + ) backtest_profile.total_value = self._performance_service \ .get_total_value(portfolio.id, tickers, backtest_profile) backtest_profile.average_trade_duration = \ - self._performance_service\ + self._performance_service \ .get_average_trade_duration(portfolio.id) backtest_profile.average_trade_size = \ self._performance_service.get_average_trade_size(portfolio.id) @@ -354,15 +359,16 @@ def create_backtest_report( # Probably not needed ticker = self._market_data_source_service \ .get_ticker( - symbol=f"{position.symbol}" - f"/{portfolio.trading_symbol}", - market=portfolio.market - ) + symbol=f"{position.symbol}" + f"/{portfolio.trading_symbol}", + market=portfolio.market + ) backtest_position.price = ticker["bid"] backtest_positions.append(backtest_position) backtest_profile.positions = backtest_positions backtest_profile.trades = algorithm.get_trades() backtest_profile.orders = orders + backtest_profile.context = algorithm.context return backtest_profile def set_backtest_market_data_sources(self, market_data_sources): @@ -381,3 +387,28 @@ def get_backtest_market_data_source(self, symbol, market): f"Market data source for " f"symbol {symbol} and market {market} not found" ) + + def _check_if_required_market_data_sources_are_registered(self): + """ + Check if the required market data sources are registered. + + It will iterate over all registered symbols and markets and check + if a ticker market data source is registered for the symbol and market. + """ + symbols = self._configuration_service.config[SYMBOLS] + + if symbols is not None: + + for symbol in symbols: + if not self._market_data_source_service\ + .has_ticker_market_data_source( + symbol=symbol + ): + raise OperationalException( + f"Ticker market data source for " + f"symbol {symbol} not found, please " + f"make sure you register a ticker market " + f"data source for this symbol " + f"in backtest mode. Otherwise, the backtest report" + " cannot be generated." + ) diff --git a/investing_algorithm_framework/services/backtesting/graphs.py b/investing_algorithm_framework/services/backtesting/graphs.py new file mode 100644 index 00000000..6cfe8828 --- /dev/null +++ b/investing_algorithm_framework/services/backtesting/graphs.py @@ -0,0 +1,62 @@ +from typing import List + +import pandas as pd +from plotly import graph_objects as go + +from investing_algorithm_framework.domain import Trade + + +def create_prices_chart(df, column="Close"): + """ + Function to create a prices chart. + """ + return go.Scatter( + x=df.index, + y=df[column], + mode='lines', + line=dict(color="blue", width=1), + name="Close" + ) + + +def create_trade_entry_markers_chart(df, trades: List[Trade]): + df['entry_prices'] = None + + for trade in trades: + opened_index = df.index.get_indexer( + [pd.to_datetime(trade.opened_at)], method='nearest' + ) + df.at[df.index[opened_index[0]], 'entry_prices'] = df.at[ + df.index[opened_index[0]], 'Close'] + + return go.Scatter( + x=df.index, + y=df["entry_prices"], + marker_symbol="arrow-up", + marker=dict(color='green'), + mode='markers', + name='Buy' + ) + + +def create_trade_exit_markers_chart(df, trades: List[Trade]): + df['exit_prices'] = None + + for trade in trades: + + if trade.closed_at is not None: + closed_index = df.index.get_indexer( + [pd.to_datetime(trade.closed_at)], method='nearest' + ) + df.at[df.index[closed_index[0]], 'exit_prices'] = df.at[ + df.index[closed_index[0]], 'Close'] + + return go.Scatter( + x=df.index, + y=df["exit_prices"], + marker_symbol="arrow-down", + marker=dict(color='red'), + mode='markers', + name='Sell' + ) + diff --git a/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py b/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py index 90f5f1b5..7b7b3d8b 100644 --- a/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +++ b/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py @@ -2,7 +2,7 @@ from investing_algorithm_framework.domain import MarketService, \ MarketDataSource, OHLCVMarketDataSource, TickerMarketDataSource, \ - OrderBookMarketDataSource + OrderBookMarketDataSource, TimeFrame from investing_algorithm_framework.services.market_credential_service \ import MarketCredentialService @@ -113,6 +113,9 @@ def get_ohlcv_market_data_source( self, symbol, time_frame=None, market=None ): + if time_frame is not None: + time_frame = TimeFrame.from_value(time_frame) + if self.market_data_sources is not None: for market_data_source in self._market_data_sources: @@ -169,7 +172,18 @@ def market_data_sources(self, market_data_sources): self._market_data_sources = market_data_sources def add(self, market_data_source): + + # Check if there is already a market data source with the same + # identifier + for existing_market_data_source in self._market_data_sources: + if existing_market_data_source.get_identifier() == \ + market_data_source.get_identifier(): + return + self._market_data_sources.append(market_data_source) def get_market_data_sources(self): return self._market_data_sources + + def has_ticker_market_data_source(self, symbol, market=None): + return self.get_ticker_market_data_source(symbol, market) is not None From 22c0ce1c15e7c7637a32317c7973c2b3985de9f3 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:12:09 +0200 Subject: [PATCH 06/31] Rename directory --- examples/{backtest => backtest_example}/__init__.py | 0 examples/{backtest => backtest_example}/algorithm/__init__.py | 0 examples/{backtest => backtest_example}/algorithm/algorithm.py | 0 examples/{backtest => backtest_example}/algorithm/data_sources.py | 0 examples/{backtest => backtest_example}/algorithm/strategy.py | 0 examples/{backtest => backtest_example}/app.py | 0 examples/{backtest => backtest_example}/run_backtest.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename examples/{backtest => backtest_example}/__init__.py (100%) rename examples/{backtest => backtest_example}/algorithm/__init__.py (100%) rename examples/{backtest => backtest_example}/algorithm/algorithm.py (100%) rename examples/{backtest => backtest_example}/algorithm/data_sources.py (100%) rename examples/{backtest => backtest_example}/algorithm/strategy.py (100%) rename examples/{backtest => backtest_example}/app.py (100%) rename examples/{backtest => backtest_example}/run_backtest.py (100%) diff --git a/examples/backtest/__init__.py b/examples/backtest_example/__init__.py similarity index 100% rename from examples/backtest/__init__.py rename to examples/backtest_example/__init__.py diff --git a/examples/backtest/algorithm/__init__.py b/examples/backtest_example/algorithm/__init__.py similarity index 100% rename from examples/backtest/algorithm/__init__.py rename to examples/backtest_example/algorithm/__init__.py diff --git a/examples/backtest/algorithm/algorithm.py b/examples/backtest_example/algorithm/algorithm.py similarity index 100% rename from examples/backtest/algorithm/algorithm.py rename to examples/backtest_example/algorithm/algorithm.py diff --git a/examples/backtest/algorithm/data_sources.py b/examples/backtest_example/algorithm/data_sources.py similarity index 100% rename from examples/backtest/algorithm/data_sources.py rename to examples/backtest_example/algorithm/data_sources.py diff --git a/examples/backtest/algorithm/strategy.py b/examples/backtest_example/algorithm/strategy.py similarity index 100% rename from examples/backtest/algorithm/strategy.py rename to examples/backtest_example/algorithm/strategy.py diff --git a/examples/backtest/app.py b/examples/backtest_example/app.py similarity index 100% rename from examples/backtest/app.py rename to examples/backtest_example/app.py diff --git a/examples/backtest/run_backtest.py b/examples/backtest_example/run_backtest.py similarity index 100% rename from examples/backtest/run_backtest.py rename to examples/backtest_example/run_backtest.py From 26bc8de962e00d83de21200089dcbf6be5cf0ef6 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:12:25 +0200 Subject: [PATCH 07/31] Rename directory --- .../__init__.py | 0 .../backtests_example/algorithms/__init__.py | 5 + .../algorithms/challenger.py | 148 + .../backtests_example/algorithms/primary.py | 122 + examples/backtests_example/experiment.ipynb | 27713 ++++++++++++++++ 5 files changed, 27988 insertions(+) rename examples/{backtest_experiment => backtests_example}/__init__.py (100%) create mode 100644 examples/backtests_example/algorithms/__init__.py create mode 100644 examples/backtests_example/algorithms/challenger.py create mode 100644 examples/backtests_example/algorithms/primary.py create mode 100644 examples/backtests_example/experiment.ipynb diff --git a/examples/backtest_experiment/__init__.py b/examples/backtests_example/__init__.py similarity index 100% rename from examples/backtest_experiment/__init__.py rename to examples/backtests_example/__init__.py diff --git a/examples/backtests_example/algorithms/__init__.py b/examples/backtests_example/algorithms/__init__.py new file mode 100644 index 00000000..d6a1b27d --- /dev/null +++ b/examples/backtests_example/algorithms/__init__.py @@ -0,0 +1,5 @@ +from .challenger import create_algorithm as create_challenger_algorithm +from .primary import create_algorithm as create_primary_algorithm + + +__all__ = ["create_challenger_algorithm", "create_primary_algorithm"] diff --git a/examples/backtests_example/algorithms/challenger.py b/examples/backtests_example/algorithms/challenger.py new file mode 100644 index 00000000..6b299763 --- /dev/null +++ b/examples/backtests_example/algorithms/challenger.py @@ -0,0 +1,148 @@ +import tulipy as tp +import numpy as np + +from investing_algorithm_framework import Algorithm, TradingStrategy, \ + TimeUnit, OrderSide, CCXTOHLCVMarketDataSource, CCXTTickerMarketDataSource + + +btc_eur_ohlcv_2h_data = CCXTOHLCVMarketDataSource( + identifier="BTC/EUR_ohlcv_2h", + symbol="BTC/EUR", + market="BITVAVO", + timeframe="2h", + window_size=200, +) + +btc_eur_ticker_data = CCXTTickerMarketDataSource( + identifier="BTC/EUR_ticker", + symbol="BTC/EUR", + market="BITVAVO", + backtest_timeframe="2h" +) + + +def is_below_trend(fast_series, slow_series): + return fast_series[-1] < slow_series[-1] + + +def is_above_trend(fast_series, slow_series): + return fast_series[-1] > slow_series[-1] + + +class Strategy(TradingStrategy): + time_unit = TimeUnit.HOUR + interval = 2 + market_data_sources = [ + btc_eur_ohlcv_2h_data, + btc_eur_ticker_data + ] + symbols = ["BTC/EUR"] + + def __init__( + self, + short_period, + long_period, + rsi_period, + rsi_buy_threshold, + rsi_sell_threshold + ): + self.fast = short_period + self.slow = long_period + self.rsi_period = rsi_period + self.rsi_buy_threshold = rsi_buy_threshold + self.rsi_sell_threshold = rsi_sell_threshold + super().__init__() + + def apply_strategy(self, algorithm: Algorithm, market_data): + + for symbol in self.symbols: + target_symbol = symbol.split('/')[0] + + if algorithm.has_open_orders(target_symbol): + continue + + df = market_data[f"{symbol}_ohlcv_2h"].to_pandas() + df = self.add_ema(df, "Close", self.fast) + df = self.add_ema(df, "Close", self.slow) + df = self.add_rsi(df, self.rsi_period) + ticker_data = market_data[f"{symbol}_ticker"] + price = ticker_data['bid'] + + if not algorithm.has_position(target_symbol) \ + and self.is_crossover( + df, f"EMA_Close_{self.fast}", f"EMA_Close_{self.slow}" + ) and df["RSI"].iloc[-1] <= self.rsi_buy_threshold: + algorithm.create_limit_order( + target_symbol=target_symbol, + order_side=OrderSide.BUY, + price=price, + percentage_of_portfolio=25, + precision=4, + ) + + if algorithm.has_position(target_symbol) \ + and self.is_below_trend( + df, f"EMA_Close_{self.fast}", f"EMA_Close_{self.slow}" + ) and df["RSI"].iloc[-1] > self.rsi_sell_threshold: + open_trades = algorithm.get_open_trades( + target_symbol=target_symbol + ) + for trade in open_trades: + algorithm.close_trade(trade) + + def is_below_trend(self, data, fast_key, slow_key): + """ + Expect df to have columns: Date, ma_, ma_. + With the given date time it will check if the ma_ is a + crossover with the ma_ + """ + return data[fast_key].iloc[-1] < data[slow_key].iloc[-1] + + def is_crossover(self, data, fast_key, slow_key): + """ + Expect df to have columns: Date, ma_, ma_. + With the given date time it will check if the ma_ is a + crossover with the ma_ + """ + return data[fast_key].iloc[-2] <= data[slow_key].iloc[-2] \ + and data[fast_key].iloc[-1] > data[slow_key].iloc[-1] + + def add_ema(self, data, key, period): + data[f"EMA_{key}_{period}"] = tp.ema(data[key].to_numpy(), period) + return data + + def add_rsi(self, data, rsi_period): + # Calculate RSI + rsi_values = tp.rsi(data['Close'].to_numpy(), period=rsi_period) + + # Pad NaN values for initial rows with a default value, e.g., 0 + rsi_values = np.concatenate((np.full(rsi_period, 0), rsi_values)) + + # Assign RSI values to the DataFrame + data["RSI"] = rsi_values + return data + + +def create_algorithm( + name, + description, + short_period, + long_period, + rsi_period, + rsi_buy_threshold, + rsi_sell_threshold +) -> Algorithm: + algorithm = Algorithm( + name=name, + description=description + ) + algorithm.add_strategy( + Strategy( + short_period, + long_period, + rsi_period, + rsi_buy_threshold=rsi_buy_threshold, + rsi_sell_threshold=rsi_sell_threshold + ) + ) + return algorithm diff --git a/examples/backtests_example/algorithms/primary.py b/examples/backtests_example/algorithms/primary.py new file mode 100644 index 00000000..d819b746 --- /dev/null +++ b/examples/backtests_example/algorithms/primary.py @@ -0,0 +1,122 @@ +import tulipy as tp +import numpy as np + +from investing_algorithm_framework import Algorithm, TradingStrategy, \ + TimeUnit, OrderSide, CCXTOHLCVMarketDataSource, CCXTTickerMarketDataSource + +btc_eur_ohlcv_2h_data = CCXTOHLCVMarketDataSource( + identifier="BTC/EUR_ohlcv_2h", + symbol="BTC/EUR", + market="BITVAVO", + timeframe="2h", + window_size=200, +) + +btc_eur_ticker_data = CCXTTickerMarketDataSource( + identifier="BTC/EUR_ticker", + symbol="BTC/EUR", + market="BITVAVO", + backtest_timeframe="2h" +) + +def is_below_trend(fast_series, slow_series): + return fast_series[-1] < slow_series[-1] + + +def is_above_trend(fast_series, slow_series): + return fast_series[-1] > slow_series[-1] + + +class Strategy(TradingStrategy): + time_unit = TimeUnit.HOUR + interval = 2 + market_data_sources = [ + btc_eur_ohlcv_2h_data, + btc_eur_ticker_data + ] + symbols = ["BTC/EUR"] + + def __init__( + self, + short_period, + long_period + ): + self.fast = short_period + self.slow = long_period + super().__init__() + + def apply_strategy(self, algorithm: Algorithm, market_data): + + for symbol in self.symbols: + target_symbol = symbol.split('/')[0] + + if algorithm.has_open_orders(target_symbol): + continue + + df = market_data[f"{symbol}_ohlcv_2h"].to_pandas() + df = self.add_ema(df, "Close", self.fast) + df = self.add_ema(df, "Close", self.slow) + ticker_data = market_data[f"{symbol}_ticker"] + price = ticker_data['bid'] + + if not algorithm.has_position(target_symbol) \ + and self.is_crossover( + df, f"EMA_Close_{self.fast}", f"EMA_Close_{self.slow}" + ): + algorithm.create_limit_order( + target_symbol=target_symbol, + order_side=OrderSide.BUY, + price=price, + percentage_of_portfolio=25, + precision=4, + ) + + if algorithm.has_position(target_symbol) \ + and self.is_below_trend( + df, f"EMA_Close_{self.fast}", f"EMA_Close_{self.slow}" + ): + open_trades = algorithm.get_open_trades( + target_symbol=target_symbol + ) + for trade in open_trades: + algorithm.close_trade(trade) + + def is_below_trend(self, data, fast_key, slow_key): + """ + Expect df to have columns: Date, ma_, ma_. + With the given date time it will check if the ma_ is a + crossover with the ma_ + """ + return data[fast_key].iloc[-1] < data[slow_key].iloc[-1] + + def is_crossover(self, data, fast_key, slow_key): + """ + Expect df to have columns: Date, ma_, ma_. + With the given date time it will check if the ma_ is a + crossover with the ma_ + """ + return data[fast_key].iloc[-2] <= data[slow_key].iloc[-2] \ + and data[fast_key].iloc[-1] > data[slow_key].iloc[-1] + + def add_ema(self, data, key, period): + data[f"EMA_{key}_{period}"] = tp.ema(data[key].to_numpy(), period) + return data + + +def create_algorithm( + name, + description, + short_period, + long_period +) -> Algorithm: + algorithm = Algorithm( + name=name, + description=description + ) + algorithm.add_strategy( + Strategy( + short_period, + long_period, + ) + ) + return algorithm diff --git a/examples/backtests_example/experiment.ipynb b/examples/backtests_example/experiment.ipynb new file mode 100644 index 00000000..ba0adbc6 --- /dev/null +++ b/examples/backtests_example/experiment.ipynb @@ -0,0 +1,27713 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Experiment functionality tutorial with the Investing Algorithm Framework\n", + "\n", + "Welcome to the tutorial about the Experiment functionality within the Investing Algorithm Framework. In this guide, we'll demonstrate how to leverage this feature to conduct A/B Testing effectively. With Experiment, you can effortlessly compare the performance of multiple models, such as challenger versus champion, and experiment with diverse backtest date ranges and parameter configurations.\n", + "\n", + "The Experiment functionality proves invaluable for fine-tuning strategy parameters and comparing different strategies, whether it's testing a new challenger model against the existing production model (champion), or exploring variations in configuration. This process of comparing the challenger model to the production model, or champion, falls under the umbrella of model validation or model evaluation. It entails meticulously assessing the challenger model's performance in relation to the established production model." + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 1: Importing the primary and challenger algorithms" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Import the factory methods for creation of the champion and challenger strategies\n", + "from algorithms import create_primary_algorithm, create_challenger_algorithm" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## Step 2: Setting up the backtest" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 7, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "data": [ + { + "line": { + "color": "red", + "width": 1 + }, + "mode": "lines", + "name": "Close down turn", + "x": [ + "2021-12-21 02:00:00", + "2021-12-21 04:00:00", + "2021-12-21 06:00:00", + "2021-12-21 08:00:00", + "2021-12-21 10:00:00", + "2021-12-21 12:00:00", + "2021-12-21 14:00:00", + "2021-12-21 16:00:00", + "2021-12-21 18:00:00", + "2021-12-21 20:00:00", + "2021-12-21 22:00:00", + "2021-12-22 00:00:00", + "2021-12-22 02:00:00", + "2021-12-22 04:00:00", + "2021-12-22 06:00:00", + "2021-12-22 08:00:00", + "2021-12-22 10:00:00", + "2021-12-22 12:00:00", + "2021-12-22 14:00:00", + "2021-12-22 16:00:00", + "2021-12-22 18:00:00", + "2021-12-22 20:00:00", + "2021-12-22 22:00:00", + "2021-12-23 00:00:00", + "2021-12-23 02:00:00", + "2021-12-23 04:00:00", + "2021-12-23 06:00:00", + "2021-12-23 08:00:00", + "2021-12-23 10:00:00", + "2021-12-23 12:00:00", + "2021-12-23 14:00:00", + "2021-12-23 16:00:00", + "2021-12-23 18:00:00", + "2021-12-23 20:00:00", + "2021-12-23 22:00:00", + "2021-12-24 00:00:00", + "2021-12-24 02:00:00", + "2021-12-24 04:00:00", + "2021-12-24 06:00:00", + "2021-12-24 08:00:00", + "2021-12-24 10:00:00", + "2021-12-24 12:00:00", + "2021-12-24 14:00:00", + "2021-12-24 16:00:00", + "2021-12-24 18:00:00", + "2021-12-24 20:00:00", + "2021-12-24 22:00:00", + "2021-12-25 00:00:00", + "2021-12-25 02:00:00", + "2021-12-25 04:00:00", + "2021-12-25 06:00:00", + "2021-12-25 08:00:00", + "2021-12-25 10:00:00", + "2021-12-25 12:00:00", + "2021-12-25 14:00:00", + "2021-12-25 16:00:00", + "2021-12-25 18:00:00", + "2021-12-25 20:00:00", + "2021-12-25 22:00:00", + "2021-12-26 00:00:00", + "2021-12-26 02:00:00", + "2021-12-26 04:00:00", + "2021-12-26 06:00:00", + "2021-12-26 08:00:00", + "2021-12-26 10:00:00", + "2021-12-26 12:00:00", + "2021-12-26 14:00:00", + "2021-12-26 16:00:00", + "2021-12-26 18:00:00", + "2021-12-26 20:00:00", + "2021-12-26 22:00:00", + "2021-12-27 00:00:00", + "2021-12-27 02:00:00", + "2021-12-27 04:00:00", + "2021-12-27 06:00:00", + "2021-12-27 08:00:00", + "2021-12-27 10:00:00", + "2021-12-27 12:00:00", + "2021-12-27 14:00:00", + "2021-12-27 16:00:00", + "2021-12-27 18:00:00", + "2021-12-27 20:00:00", + "2021-12-27 22:00:00", + "2021-12-28 00:00:00", + "2021-12-28 02:00:00", + "2021-12-28 04:00:00", + "2021-12-28 06:00:00", + "2021-12-28 08:00:00", + "2021-12-28 10:00:00", + "2021-12-28 12:00:00", + "2021-12-28 14:00:00", + "2021-12-28 16:00:00", + "2021-12-28 18:00:00", + "2021-12-28 20:00:00", + "2021-12-28 22:00:00", + "2021-12-29 00:00:00", + "2021-12-29 02:00:00", + "2021-12-29 04:00:00", + "2021-12-29 06:00:00", + "2021-12-29 08:00:00", + "2021-12-29 10:00:00", + "2021-12-29 12:00:00", + "2021-12-29 14:00:00", + "2021-12-29 16:00:00", + "2021-12-29 18:00:00", + "2021-12-29 20:00:00", + "2021-12-29 22:00:00", + "2021-12-30 00:00:00", + "2021-12-30 02:00:00", + "2021-12-30 04:00:00", + "2021-12-30 06:00:00", + "2021-12-30 08:00:00", + "2021-12-30 10:00:00", + "2021-12-30 12:00:00", + "2021-12-30 14:00:00", + "2021-12-30 16:00:00", + "2021-12-30 18:00:00", + "2021-12-30 20:00:00", + "2021-12-30 22:00:00", + "2021-12-31 00:00:00", + "2021-12-31 02:00:00", + "2021-12-31 04:00:00", + "2021-12-31 06:00:00", + "2021-12-31 08:00:00", + "2021-12-31 10:00:00", + "2021-12-31 12:00:00", + "2021-12-31 14:00:00", + "2021-12-31 16:00:00", + "2021-12-31 18:00:00", + "2021-12-31 20:00:00", + "2021-12-31 22:00:00", + "2022-01-01 00:00:00", + "2022-01-01 02:00:00", + "2022-01-01 04:00:00", + "2022-01-01 06:00:00", + "2022-01-01 08:00:00", + "2022-01-01 10:00:00", + "2022-01-01 12:00:00", + "2022-01-01 14:00:00", + "2022-01-01 16:00:00", + "2022-01-01 18:00:00", + "2022-01-01 20:00:00", + "2022-01-01 22:00:00", + "2022-01-02 00:00:00", + "2022-01-02 02:00:00", + "2022-01-02 04:00:00", + "2022-01-02 06:00:00", + "2022-01-02 08:00:00", + "2022-01-02 10:00:00", + "2022-01-02 12:00:00", + "2022-01-02 14:00:00", + "2022-01-02 16:00:00", + "2022-01-02 18:00:00", + "2022-01-02 20:00:00", + "2022-01-02 22:00:00", + "2022-01-03 00:00:00", + "2022-01-03 02:00:00", + "2022-01-03 04:00:00", + "2022-01-03 06:00:00", + "2022-01-03 08:00:00", + "2022-01-03 10:00:00", + "2022-01-03 12:00:00", + "2022-01-03 14:00:00", + "2022-01-03 16:00:00", + "2022-01-03 18:00:00", + "2022-01-03 20:00:00", + "2022-01-03 22:00:00", + "2022-01-04 00:00:00", + "2022-01-04 02:00:00", + "2022-01-04 04:00:00", + "2022-01-04 06:00:00", + "2022-01-04 08:00:00", + "2022-01-04 10:00:00", + "2022-01-04 12:00:00", + "2022-01-04 14:00:00", + "2022-01-04 16:00:00", + "2022-01-04 18:00:00", + "2022-01-04 20:00:00", + "2022-01-04 22:00:00", + "2022-01-05 00:00:00", + "2022-01-05 02:00:00", + "2022-01-05 04:00:00", + "2022-01-05 06:00:00", + "2022-01-05 08:00:00", + "2022-01-05 10:00:00", + "2022-01-05 12:00:00", + "2022-01-05 14:00:00", + "2022-01-05 16:00:00", + "2022-01-05 18:00:00", + "2022-01-05 20:00:00", + "2022-01-05 22:00:00", + "2022-01-06 00:00:00", + "2022-01-06 02:00:00", + "2022-01-06 04:00:00", + "2022-01-06 06:00:00", + "2022-01-06 08:00:00", + "2022-01-06 10:00:00", + "2022-01-06 12:00:00", + "2022-01-06 14:00:00", + "2022-01-06 16:00:00", + "2022-01-06 18:00:00", + "2022-01-06 20:00:00", + "2022-01-06 22:00:00", + "2022-01-07 00:00:00", + "2022-01-07 02:00:00", + "2022-01-07 04:00:00", + "2022-01-07 06:00:00", + "2022-01-07 08:00:00", + "2022-01-07 10:00:00", + "2022-01-07 12:00:00", + "2022-01-07 14:00:00", + "2022-01-07 16:00:00", + "2022-01-07 18:00:00", + "2022-01-07 20:00:00", + "2022-01-07 22:00:00", + "2022-01-08 00:00:00", + "2022-01-08 02:00:00", + "2022-01-08 04:00:00", + "2022-01-08 06:00:00", + "2022-01-08 08:00:00", + "2022-01-08 10:00:00", + "2022-01-08 12:00:00", + "2022-01-08 14:00:00", + "2022-01-08 16:00:00", + "2022-01-08 18:00:00", + "2022-01-08 20:00:00", + "2022-01-08 22:00:00", + "2022-01-09 00:00:00", + "2022-01-09 02:00:00", + "2022-01-09 04:00:00", + "2022-01-09 06:00:00", + "2022-01-09 08:00:00", + "2022-01-09 10:00:00", + "2022-01-09 12:00:00", + "2022-01-09 14:00:00", + "2022-01-09 16:00:00", + "2022-01-09 18:00:00", + "2022-01-09 20:00:00", + "2022-01-09 22:00:00", + "2022-01-10 00:00:00", + "2022-01-10 02:00:00", + "2022-01-10 04:00:00", + "2022-01-10 06:00:00", + "2022-01-10 08:00:00", + "2022-01-10 10:00:00", + "2022-01-10 12:00:00", + "2022-01-10 14:00:00", + "2022-01-10 16:00:00", + "2022-01-10 18:00:00", + "2022-01-10 20:00:00", + "2022-01-10 22:00:00", + "2022-01-11 00:00:00", + "2022-01-11 02:00:00", + "2022-01-11 04:00:00", + "2022-01-11 06:00:00", + "2022-01-11 08:00:00", + "2022-01-11 10:00:00", + "2022-01-11 12:00:00", + "2022-01-11 14:00:00", + "2022-01-11 16:00:00", + "2022-01-11 18:00:00", + "2022-01-11 20:00:00", + "2022-01-11 22:00:00", + "2022-01-12 00:00:00", + "2022-01-12 02:00:00", + "2022-01-12 04:00:00", + "2022-01-12 06:00:00", + "2022-01-12 08:00:00", + "2022-01-12 10:00:00", + "2022-01-12 12:00:00", + "2022-01-12 14:00:00", + "2022-01-12 16:00:00", + "2022-01-12 18:00:00", + "2022-01-12 20:00:00", + "2022-01-12 22:00:00", + "2022-01-13 00:00:00", + "2022-01-13 02:00:00", + "2022-01-13 04:00:00", + "2022-01-13 06:00:00", + "2022-01-13 08:00:00", + "2022-01-13 10:00:00", + "2022-01-13 12:00:00", + "2022-01-13 14:00:00", + "2022-01-13 16:00:00", + "2022-01-13 18:00:00", + "2022-01-13 20:00:00", + "2022-01-13 22:00:00", + "2022-01-14 00:00:00", + "2022-01-14 02:00:00", + "2022-01-14 04:00:00", + "2022-01-14 06:00:00", + "2022-01-14 08:00:00", + "2022-01-14 10:00:00", + "2022-01-14 12:00:00", + "2022-01-14 14:00:00", + "2022-01-14 16:00:00", + "2022-01-14 18:00:00", + "2022-01-14 20:00:00", + "2022-01-14 22:00:00", + "2022-01-15 00:00:00", + "2022-01-15 02:00:00", + "2022-01-15 04:00:00", + "2022-01-15 06:00:00", + "2022-01-15 08:00:00", + "2022-01-15 10:00:00", + "2022-01-15 12:00:00", + "2022-01-15 14:00:00", + "2022-01-15 16:00:00", + "2022-01-15 18:00:00", + "2022-01-15 20:00:00", + "2022-01-15 22:00:00", + "2022-01-16 00:00:00", + "2022-01-16 02:00:00", + "2022-01-16 04:00:00", + "2022-01-16 06:00:00", + "2022-01-16 08:00:00", + "2022-01-16 10:00:00", + "2022-01-16 12:00:00", + "2022-01-16 14:00:00", + "2022-01-16 16:00:00", + "2022-01-16 18:00:00", + "2022-01-16 20:00:00", + "2022-01-16 22:00:00", + "2022-01-17 00:00:00", + "2022-01-17 02:00:00", + "2022-01-17 04:00:00", + "2022-01-17 06:00:00", + "2022-01-17 08:00:00", + "2022-01-17 10:00:00", + "2022-01-17 12:00:00", + "2022-01-17 14:00:00", + "2022-01-17 16:00:00", + "2022-01-17 18:00:00", + "2022-01-17 20:00:00", + "2022-01-17 22:00:00", + "2022-01-18 00:00:00", + "2022-01-18 02:00:00", + "2022-01-18 04:00:00", + "2022-01-18 06:00:00", + "2022-01-18 08:00:00", + "2022-01-18 10:00:00", + "2022-01-18 12:00:00", + "2022-01-18 14:00:00", + "2022-01-18 16:00:00", + "2022-01-18 18:00:00", + "2022-01-18 20:00:00", + "2022-01-18 22:00:00", + "2022-01-19 00:00:00", + "2022-01-19 02:00:00", + "2022-01-19 04:00:00", + "2022-01-19 06:00:00", + "2022-01-19 08:00:00", + "2022-01-19 10:00:00", + "2022-01-19 12:00:00", + "2022-01-19 14:00:00", + "2022-01-19 16:00:00", + "2022-01-19 18:00:00", + "2022-01-19 20:00:00", + "2022-01-19 22:00:00", + "2022-01-20 00:00:00", + "2022-01-20 02:00:00", + "2022-01-20 04:00:00", + "2022-01-20 06:00:00", + "2022-01-20 08:00:00", + "2022-01-20 10:00:00", + "2022-01-20 12:00:00", + "2022-01-20 14:00:00", + "2022-01-20 16:00:00", + "2022-01-20 18:00:00", + "2022-01-20 20:00:00", + "2022-01-20 22:00:00", + "2022-01-21 00:00:00", + "2022-01-21 02:00:00", + "2022-01-21 04:00:00", + "2022-01-21 06:00:00", + "2022-01-21 08:00:00", + "2022-01-21 10:00:00", + "2022-01-21 12:00:00", + "2022-01-21 14:00:00", + "2022-01-21 16:00:00", + "2022-01-21 18:00:00", + "2022-01-21 20:00:00", + "2022-01-21 22:00:00", + "2022-01-22 00:00:00", + "2022-01-22 02:00:00", + "2022-01-22 04:00:00", + "2022-01-22 06:00:00", + "2022-01-22 08:00:00", + "2022-01-22 10:00:00", + "2022-01-22 12:00:00", + "2022-01-22 14:00:00", + "2022-01-22 16:00:00", + "2022-01-22 18:00:00", + "2022-01-22 20:00:00", + "2022-01-22 22:00:00", + "2022-01-23 00:00:00", + "2022-01-23 02:00:00", + "2022-01-23 04:00:00", + "2022-01-23 06:00:00", + "2022-01-23 08:00:00", + "2022-01-23 10:00:00", + "2022-01-23 12:00:00", + "2022-01-23 14:00:00", + "2022-01-23 16:00:00", + "2022-01-23 18:00:00", + "2022-01-23 20:00:00", + "2022-01-23 22:00:00", + "2022-01-24 00:00:00", + "2022-01-24 02:00:00", + "2022-01-24 04:00:00", + "2022-01-24 06:00:00", + "2022-01-24 08:00:00", + "2022-01-24 10:00:00", + "2022-01-24 12:00:00", + "2022-01-24 14:00:00", + "2022-01-24 16:00:00", + "2022-01-24 18:00:00", + "2022-01-24 20:00:00", + "2022-01-24 22:00:00", + "2022-01-25 00:00:00", + "2022-01-25 02:00:00", + "2022-01-25 04:00:00", + "2022-01-25 06:00:00", + "2022-01-25 08:00:00", + "2022-01-25 10:00:00", + "2022-01-25 12:00:00", + "2022-01-25 14:00:00", + "2022-01-25 16:00:00", + "2022-01-25 18:00:00", + "2022-01-25 20:00:00", + "2022-01-25 22:00:00", + "2022-01-26 00:00:00", + "2022-01-26 02:00:00", + "2022-01-26 04:00:00", + "2022-01-26 06:00:00", + "2022-01-26 08:00:00", + "2022-01-26 10:00:00", + "2022-01-26 12:00:00", + "2022-01-26 14:00:00", + "2022-01-26 16:00:00", + "2022-01-26 18:00:00", + "2022-01-26 20:00:00", + "2022-01-26 22:00:00", + "2022-01-27 00:00:00", + "2022-01-27 02:00:00", + "2022-01-27 04:00:00", + "2022-01-27 06:00:00", + "2022-01-27 08:00:00", + "2022-01-27 10:00:00", + "2022-01-27 12:00:00", + "2022-01-27 14:00:00", + "2022-01-27 16:00:00", + "2022-01-27 18:00:00", + "2022-01-27 20:00:00", + "2022-01-27 22:00:00", + "2022-01-28 00:00:00", + "2022-01-28 02:00:00", + "2022-01-28 04:00:00", + "2022-01-28 06:00:00", + "2022-01-28 08:00:00", + "2022-01-28 10:00:00", + "2022-01-28 12:00:00", + "2022-01-28 14:00:00", + "2022-01-28 16:00:00", + "2022-01-28 18:00:00", + "2022-01-28 20:00:00", + "2022-01-28 22:00:00", + "2022-01-29 00:00:00", + "2022-01-29 02:00:00", + "2022-01-29 04:00:00", + "2022-01-29 06:00:00", + "2022-01-29 08:00:00", + "2022-01-29 10:00:00", + "2022-01-29 12:00:00", + "2022-01-29 14:00:00", + "2022-01-29 16:00:00", + "2022-01-29 18:00:00", + "2022-01-29 20:00:00", + "2022-01-29 22:00:00", + "2022-01-30 00:00:00", + "2022-01-30 02:00:00", + "2022-01-30 04:00:00", + "2022-01-30 06:00:00", + "2022-01-30 08:00:00", + "2022-01-30 10:00:00", + "2022-01-30 12:00:00", + "2022-01-30 14:00:00", + "2022-01-30 16:00:00", + "2022-01-30 18:00:00", + "2022-01-30 20:00:00", + "2022-01-30 22:00:00", + "2022-01-31 00:00:00", + "2022-01-31 02:00:00", + "2022-01-31 04:00:00", + "2022-01-31 06:00:00", + "2022-01-31 08:00:00", + "2022-01-31 10:00:00", + "2022-01-31 12:00:00", + "2022-01-31 14:00:00", + "2022-01-31 16:00:00", + "2022-01-31 18:00:00", + "2022-01-31 20:00:00", + "2022-01-31 22:00:00", + "2022-02-01 00:00:00", + "2022-02-01 02:00:00", + "2022-02-01 04:00:00", + "2022-02-01 06:00:00", + "2022-02-01 08:00:00", + "2022-02-01 10:00:00", + "2022-02-01 12:00:00", + "2022-02-01 14:00:00", + "2022-02-01 16:00:00", + "2022-02-01 18:00:00", + "2022-02-01 20:00:00", + "2022-02-01 22:00:00", + "2022-02-02 00:00:00", + "2022-02-02 02:00:00", + "2022-02-02 04:00:00", + "2022-02-02 06:00:00", + "2022-02-02 08:00:00", + "2022-02-02 10:00:00", + "2022-02-02 12:00:00", + "2022-02-02 14:00:00", + "2022-02-02 16:00:00", + "2022-02-02 18:00:00", + "2022-02-02 20:00:00", + "2022-02-02 22:00:00", + "2022-02-03 00:00:00", + "2022-02-03 02:00:00", + "2022-02-03 04:00:00", + "2022-02-03 06:00:00", + "2022-02-03 08:00:00", + "2022-02-03 10:00:00", + "2022-02-03 12:00:00", + "2022-02-03 14:00:00", + "2022-02-03 16:00:00", + "2022-02-03 18:00:00", + "2022-02-03 20:00:00", + "2022-02-03 22:00:00", + "2022-02-04 00:00:00", + "2022-02-04 02:00:00", + "2022-02-04 04:00:00", + "2022-02-04 06:00:00", + "2022-02-04 08:00:00", + "2022-02-04 10:00:00", + "2022-02-04 12:00:00", + "2022-02-04 14:00:00", + "2022-02-04 16:00:00", + "2022-02-04 18:00:00", + "2022-02-04 20:00:00", + "2022-02-04 22:00:00", + "2022-02-05 00:00:00", + "2022-02-05 02:00:00", + "2022-02-05 04:00:00", + "2022-02-05 06:00:00", + "2022-02-05 08:00:00", + "2022-02-05 10:00:00", + "2022-02-05 12:00:00", + "2022-02-05 14:00:00", + "2022-02-05 16:00:00", + "2022-02-05 18:00:00", + "2022-02-05 20:00:00", + "2022-02-05 22:00:00", + "2022-02-06 00:00:00", + "2022-02-06 02:00:00", + "2022-02-06 04:00:00", + "2022-02-06 06:00:00", + "2022-02-06 08:00:00", + "2022-02-06 10:00:00", + "2022-02-06 12:00:00", + "2022-02-06 14:00:00", + "2022-02-06 16:00:00", + "2022-02-06 18:00:00", + "2022-02-06 20:00:00", + "2022-02-06 22:00:00", + "2022-02-07 00:00:00", + "2022-02-07 02:00:00", + "2022-02-07 04:00:00", + "2022-02-07 06:00:00", + "2022-02-07 08:00:00", + "2022-02-07 10:00:00", + "2022-02-07 12:00:00", + "2022-02-07 14:00:00", + "2022-02-07 16:00:00", + "2022-02-07 18:00:00", + "2022-02-07 20:00:00", + "2022-02-07 22:00:00", + "2022-02-08 00:00:00", + "2022-02-08 02:00:00", + "2022-02-08 04:00:00", + "2022-02-08 06:00:00", + "2022-02-08 08:00:00", + "2022-02-08 10:00:00", + "2022-02-08 12:00:00", + "2022-02-08 14:00:00", + "2022-02-08 16:00:00", + "2022-02-08 18:00:00", + "2022-02-08 20:00:00", + "2022-02-08 22:00:00", + "2022-02-09 00:00:00", + "2022-02-09 02:00:00", + "2022-02-09 04:00:00", + "2022-02-09 06:00:00", + "2022-02-09 08:00:00", + "2022-02-09 10:00:00", + "2022-02-09 12:00:00", + "2022-02-09 14:00:00", + "2022-02-09 16:00:00", + "2022-02-09 18:00:00", + "2022-02-09 20:00:00", + "2022-02-09 22:00:00", + "2022-02-10 00:00:00", + "2022-02-10 02:00:00", + "2022-02-10 04:00:00", + "2022-02-10 06:00:00", + "2022-02-10 08:00:00", + "2022-02-10 10:00:00", + "2022-02-10 12:00:00", + "2022-02-10 14:00:00", + "2022-02-10 16:00:00", + "2022-02-10 18:00:00", + "2022-02-10 20:00:00", + "2022-02-10 22:00:00", + "2022-02-11 00:00:00", + "2022-02-11 02:00:00", + "2022-02-11 04:00:00", + "2022-02-11 06:00:00", + "2022-02-11 08:00:00", + "2022-02-11 10:00:00", + "2022-02-11 12:00:00", + "2022-02-11 14:00:00", + "2022-02-11 16:00:00", + "2022-02-11 18:00:00", + "2022-02-11 20:00:00", + "2022-02-11 22:00:00", + "2022-02-12 00:00:00", + "2022-02-12 02:00:00", + "2022-02-12 04:00:00", + "2022-02-12 06:00:00", + "2022-02-12 08:00:00", + "2022-02-12 10:00:00", + "2022-02-12 12:00:00", + "2022-02-12 14:00:00", + "2022-02-12 16:00:00", + "2022-02-12 18:00:00", + "2022-02-12 20:00:00", + "2022-02-12 22:00:00", + "2022-02-13 00:00:00", + "2022-02-13 02:00:00", + "2022-02-13 04:00:00", + "2022-02-13 06:00:00", + "2022-02-13 08:00:00", + "2022-02-13 10:00:00", + "2022-02-13 12:00:00", + "2022-02-13 14:00:00", + "2022-02-13 16:00:00", + "2022-02-13 18:00:00", + "2022-02-13 20:00:00", + "2022-02-13 22:00:00", + "2022-02-14 00:00:00", + "2022-02-14 02:00:00", + "2022-02-14 04:00:00", + "2022-02-14 06:00:00", + "2022-02-14 08:00:00", + "2022-02-14 10:00:00", + "2022-02-14 12:00:00", + "2022-02-14 14:00:00", + "2022-02-14 16:00:00", + "2022-02-14 18:00:00", + "2022-02-14 20:00:00", + "2022-02-14 22:00:00", + "2022-02-15 00:00:00", + "2022-02-15 02:00:00", + "2022-02-15 04:00:00", + "2022-02-15 06:00:00", + "2022-02-15 08:00:00", + "2022-02-15 10:00:00", + "2022-02-15 12:00:00", + "2022-02-15 14:00:00", + "2022-02-15 16:00:00", + "2022-02-15 18:00:00", + "2022-02-15 20:00:00", + "2022-02-15 22:00:00", + "2022-02-16 00:00:00", + "2022-02-16 02:00:00", + "2022-02-16 04:00:00", + "2022-02-16 06:00:00", + "2022-02-16 08:00:00", + "2022-02-16 10:00:00", + "2022-02-16 12:00:00", + "2022-02-16 14:00:00", + "2022-02-16 16:00:00", + "2022-02-16 18:00:00", + "2022-02-16 20:00:00", + "2022-02-16 22:00:00", + "2022-02-17 00:00:00", + "2022-02-17 02:00:00", + "2022-02-17 04:00:00", + "2022-02-17 06:00:00", + "2022-02-17 08:00:00", + "2022-02-17 10:00:00", + "2022-02-17 12:00:00", + "2022-02-17 14:00:00", + "2022-02-17 16:00:00", + "2022-02-17 18:00:00", + "2022-02-17 20:00:00", + "2022-02-17 22:00:00", + "2022-02-18 00:00:00", + "2022-02-18 02:00:00", + "2022-02-18 04:00:00", + "2022-02-18 06:00:00", + "2022-02-18 08:00:00", + "2022-02-18 10:00:00", + "2022-02-18 12:00:00", + "2022-02-18 14:00:00", + "2022-02-18 16:00:00", + "2022-02-18 18:00:00", + "2022-02-18 20:00:00", + "2022-02-18 22:00:00", + "2022-02-19 00:00:00", + "2022-02-19 02:00:00", + "2022-02-19 04:00:00", + "2022-02-19 06:00:00", + "2022-02-19 08:00:00", + "2022-02-19 10:00:00", + "2022-02-19 12:00:00", + "2022-02-19 14:00:00", + "2022-02-19 16:00:00", + "2022-02-19 18:00:00", + "2022-02-19 20:00:00", + "2022-02-19 22:00:00", + "2022-02-20 00:00:00", + "2022-02-20 02:00:00", + "2022-02-20 04:00:00", + "2022-02-20 06:00:00", + "2022-02-20 08:00:00", + "2022-02-20 10:00:00", + "2022-02-20 12:00:00", + "2022-02-20 14:00:00", + "2022-02-20 16:00:00", + "2022-02-20 18:00:00", + "2022-02-20 20:00:00", + "2022-02-20 22:00:00", + "2022-02-21 00:00:00", + "2022-02-21 02:00:00", + "2022-02-21 04:00:00", + "2022-02-21 06:00:00", + "2022-02-21 08:00:00", + "2022-02-21 10:00:00", + "2022-02-21 12:00:00", + "2022-02-21 14:00:00", + "2022-02-21 16:00:00", + "2022-02-21 18:00:00", + "2022-02-21 20:00:00", + "2022-02-21 22:00:00", + "2022-02-22 00:00:00", + "2022-02-22 02:00:00", + "2022-02-22 04:00:00", + "2022-02-22 06:00:00", + "2022-02-22 08:00:00", + "2022-02-22 10:00:00", + "2022-02-22 12:00:00", + "2022-02-22 14:00:00", + "2022-02-22 16:00:00", + "2022-02-22 18:00:00", + "2022-02-22 20:00:00", + "2022-02-22 22:00:00", + "2022-02-23 00:00:00", + "2022-02-23 02:00:00", + "2022-02-23 04:00:00", + "2022-02-23 06:00:00", + "2022-02-23 08:00:00", + "2022-02-23 10:00:00", + "2022-02-23 12:00:00", + "2022-02-23 14:00:00", + "2022-02-23 16:00:00", + "2022-02-23 18:00:00", + "2022-02-23 20:00:00", + "2022-02-23 22:00:00", + "2022-02-24 00:00:00", + "2022-02-24 02:00:00", + "2022-02-24 04:00:00", + "2022-02-24 06:00:00", + "2022-02-24 08:00:00", + "2022-02-24 10:00:00", + "2022-02-24 12:00:00", + "2022-02-24 14:00:00", + "2022-02-24 16:00:00", + "2022-02-24 18:00:00", + "2022-02-24 20:00:00", + "2022-02-24 22:00:00", + "2022-02-25 00:00:00", + "2022-02-25 02:00:00", + "2022-02-25 04:00:00", + "2022-02-25 06:00:00", + "2022-02-25 08:00:00", + "2022-02-25 10:00:00", + "2022-02-25 12:00:00", + "2022-02-25 14:00:00", + "2022-02-25 16:00:00", + "2022-02-25 18:00:00", + "2022-02-25 20:00:00", + "2022-02-25 22:00:00", + "2022-02-26 00:00:00", + "2022-02-26 02:00:00", + "2022-02-26 04:00:00", + "2022-02-26 06:00:00", + "2022-02-26 08:00:00", + "2022-02-26 10:00:00", + "2022-02-26 12:00:00", + "2022-02-26 14:00:00", + "2022-02-26 16:00:00", + "2022-02-26 18:00:00", + "2022-02-26 20:00:00", + "2022-02-26 22:00:00", + "2022-02-27 00:00:00", + "2022-02-27 02:00:00", + "2022-02-27 04:00:00", + "2022-02-27 06:00:00", + "2022-02-27 08:00:00", + "2022-02-27 10:00:00", + "2022-02-27 12:00:00", + "2022-02-27 14:00:00", + "2022-02-27 16:00:00", + "2022-02-27 18:00:00", + "2022-02-27 20:00:00", + "2022-02-27 22:00:00", + "2022-02-28 00:00:00", + "2022-02-28 02:00:00", + "2022-02-28 04:00:00", + "2022-02-28 06:00:00", + "2022-02-28 08:00:00", + "2022-02-28 10:00:00", + "2022-02-28 12:00:00", + "2022-02-28 14:00:00", + "2022-02-28 16:00:00", + "2022-02-28 18:00:00", + "2022-02-28 20:00:00", + "2022-02-28 22:00:00", + "2022-03-01 00:00:00", + "2022-03-01 02:00:00", + "2022-03-01 04:00:00", + "2022-03-01 06:00:00", + "2022-03-01 08:00:00", + "2022-03-01 10:00:00", + "2022-03-01 12:00:00", + "2022-03-01 14:00:00", + "2022-03-01 16:00:00", + "2022-03-01 18:00:00", + "2022-03-01 20:00:00", + "2022-03-01 22:00:00", + "2022-03-02 00:00:00", + "2022-03-02 02:00:00", + "2022-03-02 04:00:00", + "2022-03-02 06:00:00", + "2022-03-02 08:00:00", + "2022-03-02 10:00:00", + "2022-03-02 12:00:00", + "2022-03-02 14:00:00", + "2022-03-02 16:00:00", + "2022-03-02 18:00:00", + "2022-03-02 20:00:00", + "2022-03-02 22:00:00", + "2022-03-03 00:00:00", + "2022-03-03 02:00:00", + "2022-03-03 04:00:00", + "2022-03-03 06:00:00", + "2022-03-03 08:00:00", + "2022-03-03 10:00:00", + "2022-03-03 12:00:00", + "2022-03-03 14:00:00", + "2022-03-03 16:00:00", + "2022-03-03 18:00:00", + "2022-03-03 20:00:00", + "2022-03-03 22:00:00", + "2022-03-04 00:00:00", + "2022-03-04 02:00:00", + "2022-03-04 04:00:00", + "2022-03-04 06:00:00", + "2022-03-04 08:00:00", + "2022-03-04 10:00:00", + "2022-03-04 12:00:00", + "2022-03-04 14:00:00", + "2022-03-04 16:00:00", + "2022-03-04 18:00:00", + "2022-03-04 20:00:00", + "2022-03-04 22:00:00", + "2022-03-05 00:00:00", + "2022-03-05 02:00:00", + "2022-03-05 04:00:00", + "2022-03-05 06:00:00", + "2022-03-05 08:00:00", + "2022-03-05 10:00:00", + "2022-03-05 12:00:00", + "2022-03-05 14:00:00", + "2022-03-05 16:00:00", + "2022-03-05 18:00:00", + "2022-03-05 20:00:00", + "2022-03-05 22:00:00", + "2022-03-06 00:00:00", + "2022-03-06 02:00:00", + "2022-03-06 04:00:00", + "2022-03-06 06:00:00", + "2022-03-06 08:00:00", + "2022-03-06 10:00:00", + "2022-03-06 12:00:00", + "2022-03-06 14:00:00", + "2022-03-06 16:00:00", + "2022-03-06 18:00:00", + "2022-03-06 20:00:00", + "2022-03-06 22:00:00", + "2022-03-07 00:00:00", + "2022-03-07 02:00:00", + "2022-03-07 04:00:00", + "2022-03-07 06:00:00", + "2022-03-07 08:00:00", + "2022-03-07 10:00:00", + "2022-03-07 12:00:00", + "2022-03-07 14:00:00", + "2022-03-07 16:00:00", + "2022-03-07 18:00:00", + "2022-03-07 20:00:00", + "2022-03-07 22:00:00", + "2022-03-08 00:00:00", + "2022-03-08 02:00:00", + "2022-03-08 04:00:00", + "2022-03-08 06:00:00", + "2022-03-08 08:00:00", + "2022-03-08 10:00:00", + "2022-03-08 12:00:00", + "2022-03-08 14:00:00", + "2022-03-08 16:00:00", + "2022-03-08 18:00:00", + "2022-03-08 20:00:00", + "2022-03-08 22:00:00", + "2022-03-09 00:00:00", + "2022-03-09 02:00:00", + "2022-03-09 04:00:00", + "2022-03-09 06:00:00", + "2022-03-09 08:00:00", + "2022-03-09 10:00:00", + "2022-03-09 12:00:00", + "2022-03-09 14:00:00", + "2022-03-09 16:00:00", + "2022-03-09 18:00:00", + "2022-03-09 20:00:00", + "2022-03-09 22:00:00", + "2022-03-10 00:00:00", + "2022-03-10 02:00:00", + "2022-03-10 04:00:00", + "2022-03-10 06:00:00", + "2022-03-10 08:00:00", + "2022-03-10 10:00:00", + "2022-03-10 12:00:00", + "2022-03-10 14:00:00", + "2022-03-10 16:00:00", + "2022-03-10 18:00:00", + "2022-03-10 20:00:00", + "2022-03-10 22:00:00", + "2022-03-11 00:00:00", + "2022-03-11 02:00:00", + "2022-03-11 04:00:00", + "2022-03-11 06:00:00", + "2022-03-11 08:00:00", + "2022-03-11 10:00:00", + "2022-03-11 12:00:00", + "2022-03-11 14:00:00", + "2022-03-11 16:00:00", + "2022-03-11 18:00:00", + "2022-03-11 20:00:00", + "2022-03-11 22:00:00", + "2022-03-12 00:00:00", + "2022-03-12 02:00:00", + "2022-03-12 04:00:00", + "2022-03-12 06:00:00", + "2022-03-12 08:00:00", + "2022-03-12 10:00:00", + "2022-03-12 12:00:00", + "2022-03-12 14:00:00", + "2022-03-12 16:00:00", + "2022-03-12 18:00:00", + "2022-03-12 20:00:00", + "2022-03-12 22:00:00", + "2022-03-13 00:00:00", + "2022-03-13 02:00:00", + "2022-03-13 04:00:00", + "2022-03-13 06:00:00", + "2022-03-13 08:00:00", + "2022-03-13 10:00:00", + "2022-03-13 12:00:00", + "2022-03-13 14:00:00", + "2022-03-13 16:00:00", + "2022-03-13 18:00:00", + "2022-03-13 20:00:00", + "2022-03-13 22:00:00", + "2022-03-14 00:00:00", + "2022-03-14 02:00:00", + "2022-03-14 04:00:00", + "2022-03-14 06:00:00", + "2022-03-14 08:00:00", + "2022-03-14 10:00:00", + "2022-03-14 12:00:00", + "2022-03-14 14:00:00", + "2022-03-14 16:00:00", + "2022-03-14 18:00:00", + "2022-03-14 20:00:00", + "2022-03-14 22:00:00", + "2022-03-15 00:00:00", + "2022-03-15 02:00:00", + "2022-03-15 04:00:00", + "2022-03-15 06:00:00", + "2022-03-15 08:00:00", + "2022-03-15 10:00:00", + "2022-03-15 12:00:00", + "2022-03-15 14:00:00", + "2022-03-15 16:00:00", + "2022-03-15 18:00:00", + "2022-03-15 20:00:00", + "2022-03-15 22:00:00", + "2022-03-16 00:00:00", + "2022-03-16 02:00:00", + "2022-03-16 04:00:00", + "2022-03-16 06:00:00", + "2022-03-16 08:00:00", + "2022-03-16 10:00:00", + "2022-03-16 12:00:00", + "2022-03-16 14:00:00", + "2022-03-16 16:00:00", + "2022-03-16 18:00:00", + "2022-03-16 20:00:00", + "2022-03-16 22:00:00", + "2022-03-17 00:00:00", + "2022-03-17 02:00:00", + "2022-03-17 04:00:00", + "2022-03-17 06:00:00", + "2022-03-17 08:00:00", + "2022-03-17 10:00:00", + "2022-03-17 12:00:00", + "2022-03-17 14:00:00", + "2022-03-17 16:00:00", + "2022-03-17 18:00:00", + "2022-03-17 20:00:00", + "2022-03-17 22:00:00", + "2022-03-18 00:00:00", + "2022-03-18 02:00:00", + "2022-03-18 04:00:00", + "2022-03-18 06:00:00", + "2022-03-18 08:00:00", + "2022-03-18 10:00:00", + "2022-03-18 12:00:00", + "2022-03-18 14:00:00", + "2022-03-18 16:00:00", + "2022-03-18 18:00:00", + "2022-03-18 20:00:00", + "2022-03-18 22:00:00", + "2022-03-19 00:00:00", + "2022-03-19 02:00:00", + "2022-03-19 04:00:00", + "2022-03-19 06:00:00", + "2022-03-19 08:00:00", + "2022-03-19 10:00:00", + "2022-03-19 12:00:00", + "2022-03-19 14:00:00", + "2022-03-19 16:00:00", + "2022-03-19 18:00:00", + "2022-03-19 20:00:00", + "2022-03-19 22:00:00", + "2022-03-20 00:00:00", + "2022-03-20 02:00:00", + "2022-03-20 04:00:00", + "2022-03-20 06:00:00", + "2022-03-20 08:00:00", + "2022-03-20 10:00:00", + "2022-03-20 12:00:00", + "2022-03-20 14:00:00", + "2022-03-20 16:00:00", + "2022-03-20 18:00:00", + "2022-03-20 20:00:00", + "2022-03-20 22:00:00", + "2022-03-21 00:00:00", + "2022-03-21 02:00:00", + "2022-03-21 04:00:00", + "2022-03-21 06:00:00", + "2022-03-21 08:00:00", + "2022-03-21 10:00:00", + "2022-03-21 12:00:00", + "2022-03-21 14:00:00", + "2022-03-21 16:00:00", + "2022-03-21 18:00:00", + "2022-03-21 20:00:00", + "2022-03-21 22:00:00", + "2022-03-22 00:00:00", + "2022-03-22 02:00:00", + "2022-03-22 04:00:00", + "2022-03-22 06:00:00", + "2022-03-22 08:00:00", + "2022-03-22 10:00:00", + "2022-03-22 12:00:00", + "2022-03-22 14:00:00", + "2022-03-22 16:00:00", + "2022-03-22 18:00:00", + "2022-03-22 20:00:00", + "2022-03-22 22:00:00", + "2022-03-23 00:00:00", + "2022-03-23 02:00:00", + "2022-03-23 04:00:00", + "2022-03-23 06:00:00", + "2022-03-23 08:00:00", + "2022-03-23 10:00:00", + "2022-03-23 12:00:00", + "2022-03-23 14:00:00", + "2022-03-23 16:00:00", + "2022-03-23 18:00:00", + "2022-03-23 20:00:00", + "2022-03-23 22:00:00", + "2022-03-24 00:00:00", + "2022-03-24 02:00:00", + "2022-03-24 04:00:00", + "2022-03-24 06:00:00", + "2022-03-24 08:00:00", + "2022-03-24 10:00:00", + "2022-03-24 12:00:00", + "2022-03-24 14:00:00", + "2022-03-24 16:00:00", + "2022-03-24 18:00:00", + "2022-03-24 20:00:00", + "2022-03-24 22:00:00", + "2022-03-25 00:00:00", + "2022-03-25 02:00:00", + "2022-03-25 04:00:00", + "2022-03-25 06:00:00", + "2022-03-25 08:00:00", + "2022-03-25 10:00:00", + "2022-03-25 12:00:00", + "2022-03-25 14:00:00", + "2022-03-25 16:00:00", + "2022-03-25 18:00:00", + "2022-03-25 20:00:00", + "2022-03-25 22:00:00", + "2022-03-26 00:00:00", + "2022-03-26 02:00:00", + "2022-03-26 04:00:00", + "2022-03-26 06:00:00", + "2022-03-26 08:00:00", + "2022-03-26 10:00:00", + "2022-03-26 12:00:00", + "2022-03-26 14:00:00", + "2022-03-26 16:00:00", + "2022-03-26 18:00:00", + "2022-03-26 20:00:00", + "2022-03-26 22:00:00", + "2022-03-27 00:00:00", + "2022-03-27 02:00:00", + "2022-03-27 04:00:00", + "2022-03-27 06:00:00", + "2022-03-27 08:00:00", + "2022-03-27 10:00:00", + "2022-03-27 12:00:00", + "2022-03-27 14:00:00", + "2022-03-27 16:00:00", + "2022-03-27 18:00:00", + "2022-03-27 20:00:00", + "2022-03-27 22:00:00", + "2022-03-28 00:00:00", + "2022-03-28 02:00:00", + "2022-03-28 04:00:00", + "2022-03-28 06:00:00", + "2022-03-28 08:00:00", + "2022-03-28 10:00:00", + "2022-03-28 12:00:00", + "2022-03-28 14:00:00", + "2022-03-28 16:00:00", + "2022-03-28 18:00:00", + "2022-03-28 20:00:00", + "2022-03-28 22:00:00", + "2022-03-29 00:00:00", + "2022-03-29 02:00:00", + "2022-03-29 04:00:00", + "2022-03-29 06:00:00", + "2022-03-29 08:00:00", + "2022-03-29 10:00:00", + "2022-03-29 12:00:00", + "2022-03-29 14:00:00", + "2022-03-29 16:00:00", + "2022-03-29 18:00:00", + "2022-03-29 20:00:00", + "2022-03-29 22:00:00", + "2022-03-30 00:00:00", + "2022-03-30 02:00:00", + "2022-03-30 04:00:00", + "2022-03-30 06:00:00", + "2022-03-30 08:00:00", + "2022-03-30 10:00:00", + "2022-03-30 12:00:00", + "2022-03-30 14:00:00", + "2022-03-30 16:00:00", + "2022-03-30 18:00:00", + "2022-03-30 20:00:00", + "2022-03-30 22:00:00", + "2022-03-31 00:00:00", + "2022-03-31 02:00:00", + "2022-03-31 04:00:00", + "2022-03-31 06:00:00", + "2022-03-31 08:00:00", + "2022-03-31 10:00:00", + "2022-03-31 12:00:00", + "2022-03-31 14:00:00", + "2022-03-31 16:00:00", + "2022-03-31 18:00:00", + "2022-03-31 20:00:00", + "2022-03-31 22:00:00", + "2022-04-01 00:00:00", + "2022-04-01 02:00:00", + "2022-04-01 04:00:00", + "2022-04-01 06:00:00", + "2022-04-01 08:00:00", + "2022-04-01 10:00:00", + "2022-04-01 12:00:00", + "2022-04-01 14:00:00", + "2022-04-01 16:00:00", + "2022-04-01 18:00:00", + "2022-04-01 20:00:00", + "2022-04-01 22:00:00", + "2022-04-02 00:00:00", + "2022-04-02 02:00:00", + "2022-04-02 04:00:00", + "2022-04-02 06:00:00", + "2022-04-02 08:00:00", + "2022-04-02 10:00:00", + "2022-04-02 12:00:00", + "2022-04-02 14:00:00", + "2022-04-02 16:00:00", + "2022-04-02 18:00:00", + "2022-04-02 20:00:00", + "2022-04-02 22:00:00", + "2022-04-03 00:00:00", + "2022-04-03 02:00:00", + "2022-04-03 04:00:00", + "2022-04-03 06:00:00", + "2022-04-03 08:00:00", + "2022-04-03 10:00:00", + "2022-04-03 12:00:00", + "2022-04-03 14:00:00", + "2022-04-03 16:00:00", + "2022-04-03 18:00:00", + "2022-04-03 20:00:00", + "2022-04-03 22:00:00", + "2022-04-04 00:00:00", + "2022-04-04 02:00:00", + "2022-04-04 04:00:00", + "2022-04-04 06:00:00", + "2022-04-04 08:00:00", + "2022-04-04 10:00:00", + "2022-04-04 12:00:00", + "2022-04-04 14:00:00", + "2022-04-04 16:00:00", + "2022-04-04 18:00:00", + "2022-04-04 20:00:00", + "2022-04-04 22:00:00", + "2022-04-05 00:00:00", + "2022-04-05 02:00:00", + "2022-04-05 04:00:00", + "2022-04-05 06:00:00", + "2022-04-05 08:00:00", + "2022-04-05 10:00:00", + "2022-04-05 12:00:00", + "2022-04-05 14:00:00", + "2022-04-05 16:00:00", + "2022-04-05 18:00:00", + "2022-04-05 20:00:00", + "2022-04-05 22:00:00", + "2022-04-06 00:00:00", + "2022-04-06 02:00:00", + "2022-04-06 04:00:00", + "2022-04-06 06:00:00", + "2022-04-06 08:00:00", + "2022-04-06 10:00:00", + "2022-04-06 12:00:00", + "2022-04-06 14:00:00", + "2022-04-06 16:00:00", + "2022-04-06 18:00:00", + "2022-04-06 20:00:00", + "2022-04-06 22:00:00", + "2022-04-07 00:00:00", + "2022-04-07 02:00:00", + "2022-04-07 04:00:00", + "2022-04-07 06:00:00", + "2022-04-07 08:00:00", + "2022-04-07 10:00:00", + "2022-04-07 12:00:00", + "2022-04-07 14:00:00", + "2022-04-07 16:00:00", + "2022-04-07 18:00:00", + "2022-04-07 20:00:00", + "2022-04-07 22:00:00", + "2022-04-08 00:00:00", + "2022-04-08 02:00:00", + "2022-04-08 04:00:00", + "2022-04-08 06:00:00", + "2022-04-08 08:00:00", + "2022-04-08 10:00:00", + "2022-04-08 12:00:00", + "2022-04-08 14:00:00", + "2022-04-08 16:00:00", + "2022-04-08 18:00:00", + "2022-04-08 20:00:00", + "2022-04-08 22:00:00", + "2022-04-09 00:00:00", + "2022-04-09 02:00:00", + "2022-04-09 04:00:00", + "2022-04-09 06:00:00", + "2022-04-09 08:00:00", + "2022-04-09 10:00:00", + "2022-04-09 12:00:00", + "2022-04-09 14:00:00", + "2022-04-09 16:00:00", + "2022-04-09 18:00:00", + "2022-04-09 20:00:00", + "2022-04-09 22:00:00", + "2022-04-10 00:00:00", + "2022-04-10 02:00:00", + "2022-04-10 04:00:00", + "2022-04-10 06:00:00", + "2022-04-10 08:00:00", + "2022-04-10 10:00:00", + "2022-04-10 12:00:00", + "2022-04-10 14:00:00", + "2022-04-10 16:00:00", + "2022-04-10 18:00:00", + "2022-04-10 20:00:00", + "2022-04-10 22:00:00", + "2022-04-11 00:00:00", + "2022-04-11 02:00:00", + "2022-04-11 04:00:00", + "2022-04-11 06:00:00", + "2022-04-11 08:00:00", + "2022-04-11 10:00:00", + "2022-04-11 12:00:00", + "2022-04-11 14:00:00", + "2022-04-11 16:00:00", + "2022-04-11 18:00:00", + "2022-04-11 20:00:00", + "2022-04-11 22:00:00", + "2022-04-12 00:00:00", + "2022-04-12 02:00:00", + "2022-04-12 04:00:00", + "2022-04-12 06:00:00", + "2022-04-12 08:00:00", + "2022-04-12 10:00:00", + "2022-04-12 12:00:00", + "2022-04-12 14:00:00", + "2022-04-12 16:00:00", + "2022-04-12 18:00:00", + "2022-04-12 20:00:00", + "2022-04-12 22:00:00", + "2022-04-13 00:00:00", + "2022-04-13 02:00:00", + "2022-04-13 04:00:00", + "2022-04-13 06:00:00", + "2022-04-13 08:00:00", + "2022-04-13 10:00:00", + "2022-04-13 12:00:00", + "2022-04-13 14:00:00", + "2022-04-13 16:00:00", + "2022-04-13 18:00:00", + "2022-04-13 20:00:00", + "2022-04-13 22:00:00", + "2022-04-14 00:00:00", + "2022-04-14 02:00:00", + "2022-04-14 04:00:00", + "2022-04-14 06:00:00", + "2022-04-14 08:00:00", + "2022-04-14 10:00:00", + "2022-04-14 12:00:00", + "2022-04-14 14:00:00", + "2022-04-14 16:00:00", + "2022-04-14 18:00:00", + "2022-04-14 20:00:00", + "2022-04-14 22:00:00", + "2022-04-15 00:00:00", + "2022-04-15 02:00:00", + "2022-04-15 04:00:00", + "2022-04-15 06:00:00", + "2022-04-15 08:00:00", + "2022-04-15 10:00:00", + "2022-04-15 12:00:00", + "2022-04-15 14:00:00", + "2022-04-15 16:00:00", + "2022-04-15 18:00:00", + "2022-04-15 20:00:00", + "2022-04-15 22:00:00", + "2022-04-16 00:00:00", + "2022-04-16 02:00:00", + "2022-04-16 04:00:00", + "2022-04-16 06:00:00", + "2022-04-16 08:00:00", + "2022-04-16 10:00:00", + "2022-04-16 12:00:00", + "2022-04-16 14:00:00", + "2022-04-16 16:00:00", + "2022-04-16 18:00:00", + "2022-04-16 20:00:00", + "2022-04-16 22:00:00", + "2022-04-17 00:00:00", + "2022-04-17 02:00:00", + "2022-04-17 04:00:00", + "2022-04-17 06:00:00", + "2022-04-17 08:00:00", + "2022-04-17 10:00:00", + "2022-04-17 12:00:00", + "2022-04-17 14:00:00", + "2022-04-17 16:00:00", + "2022-04-17 18:00:00", + "2022-04-17 20:00:00", + "2022-04-17 22:00:00", + "2022-04-18 00:00:00", + "2022-04-18 02:00:00", + "2022-04-18 04:00:00", + "2022-04-18 06:00:00", + "2022-04-18 08:00:00", + "2022-04-18 10:00:00", + "2022-04-18 12:00:00", + "2022-04-18 14:00:00", + "2022-04-18 16:00:00", + "2022-04-18 18:00:00", + "2022-04-18 20:00:00", + "2022-04-18 22:00:00", + "2022-04-19 00:00:00", + "2022-04-19 02:00:00", + "2022-04-19 04:00:00", + "2022-04-19 06:00:00", + "2022-04-19 08:00:00", + "2022-04-19 10:00:00", + "2022-04-19 12:00:00", + "2022-04-19 14:00:00", + "2022-04-19 16:00:00", + "2022-04-19 18:00:00", + "2022-04-19 20:00:00", + "2022-04-19 22:00:00", + "2022-04-20 00:00:00", + "2022-04-20 04:00:00", + "2022-04-20 06:00:00", + "2022-04-20 08:00:00", + "2022-04-20 10:00:00", + "2022-04-20 12:00:00", + "2022-04-20 14:00:00", + "2022-04-20 16:00:00", + "2022-04-20 18:00:00", + "2022-04-20 20:00:00", + "2022-04-20 22:00:00", + "2022-04-21 00:00:00", + "2022-04-21 02:00:00", + "2022-04-21 04:00:00", + "2022-04-21 06:00:00", + "2022-04-21 08:00:00", + "2022-04-21 10:00:00", + "2022-04-21 12:00:00", + "2022-04-21 14:00:00", + "2022-04-21 16:00:00", + "2022-04-21 18:00:00", + "2022-04-21 20:00:00", + "2022-04-21 22:00:00", + "2022-04-22 00:00:00", + "2022-04-22 02:00:00", + "2022-04-22 04:00:00", + "2022-04-22 06:00:00", + "2022-04-22 08:00:00", + "2022-04-22 10:00:00", + "2022-04-22 12:00:00", + "2022-04-22 14:00:00", + "2022-04-22 16:00:00", + "2022-04-22 18:00:00", + "2022-04-22 20:00:00", + "2022-04-22 22:00:00", + "2022-04-23 00:00:00", + "2022-04-23 02:00:00", + "2022-04-23 04:00:00", + "2022-04-23 06:00:00", + "2022-04-23 08:00:00", + "2022-04-23 10:00:00", + "2022-04-23 12:00:00", + "2022-04-23 14:00:00", + "2022-04-23 16:00:00", + "2022-04-23 18:00:00", + "2022-04-23 20:00:00", + "2022-04-23 22:00:00", + "2022-04-24 00:00:00", + "2022-04-24 02:00:00", + "2022-04-24 04:00:00", + "2022-04-24 06:00:00", + "2022-04-24 08:00:00", + "2022-04-24 10:00:00", + "2022-04-24 12:00:00", + "2022-04-24 14:00:00", + "2022-04-24 16:00:00", + "2022-04-24 18:00:00", + "2022-04-24 20:00:00", + "2022-04-24 22:00:00", + "2022-04-25 00:00:00", + "2022-04-25 02:00:00", + "2022-04-25 04:00:00", + "2022-04-25 06:00:00", + "2022-04-25 08:00:00", + "2022-04-25 10:00:00", + "2022-04-25 12:00:00", + "2022-04-25 14:00:00", + "2022-04-25 16:00:00", + "2022-04-25 18:00:00", + "2022-04-25 20:00:00", + "2022-04-25 22:00:00", + "2022-04-26 00:00:00", + "2022-04-26 02:00:00", + "2022-04-26 04:00:00", + "2022-04-26 06:00:00", + "2022-04-26 08:00:00", + "2022-04-26 10:00:00", + "2022-04-26 12:00:00", + "2022-04-26 14:00:00", + "2022-04-26 16:00:00", + "2022-04-26 18:00:00", + "2022-04-26 20:00:00", + "2022-04-26 22:00:00", + "2022-04-27 00:00:00", + "2022-04-27 02:00:00", + "2022-04-27 04:00:00", + "2022-04-27 06:00:00", + "2022-04-27 08:00:00", + "2022-04-27 10:00:00", + "2022-04-27 12:00:00", + "2022-04-27 14:00:00", + "2022-04-27 16:00:00", + "2022-04-27 18:00:00", + "2022-04-27 20:00:00", + "2022-04-27 22:00:00", + "2022-04-28 00:00:00", + "2022-04-28 02:00:00", + "2022-04-28 04:00:00", + "2022-04-28 06:00:00", + "2022-04-28 08:00:00", + "2022-04-28 10:00:00", + "2022-04-28 12:00:00", + "2022-04-28 14:00:00", + "2022-04-28 16:00:00", + "2022-04-28 18:00:00", + "2022-04-28 20:00:00", + "2022-04-28 22:00:00", + "2022-04-29 00:00:00", + "2022-04-29 02:00:00", + "2022-04-29 04:00:00", + "2022-04-29 06:00:00", + "2022-04-29 08:00:00", + "2022-04-29 10:00:00", + "2022-04-29 12:00:00", + "2022-04-29 14:00:00", + "2022-04-29 16:00:00", + "2022-04-29 18:00:00", + "2022-04-29 20:00:00", + "2022-04-29 22:00:00", + "2022-04-30 00:00:00", + "2022-04-30 02:00:00", + "2022-04-30 04:00:00", + "2022-04-30 06:00:00", + "2022-04-30 08:00:00", + "2022-04-30 10:00:00", + "2022-04-30 12:00:00", + "2022-04-30 14:00:00", + "2022-04-30 16:00:00", + "2022-04-30 18:00:00", + "2022-04-30 20:00:00", + "2022-04-30 22:00:00", + "2022-05-01 00:00:00", + "2022-05-01 02:00:00", + "2022-05-01 04:00:00", + "2022-05-01 06:00:00", + "2022-05-01 08:00:00", + "2022-05-01 10:00:00", + "2022-05-01 12:00:00", + "2022-05-01 14:00:00", + "2022-05-01 16:00:00", + "2022-05-01 18:00:00", + "2022-05-01 20:00:00", + "2022-05-01 22:00:00", + "2022-05-02 00:00:00", + "2022-05-02 02:00:00", + "2022-05-02 04:00:00", + "2022-05-02 06:00:00", + "2022-05-02 08:00:00", + "2022-05-02 10:00:00", + "2022-05-02 12:00:00", + "2022-05-02 14:00:00", + "2022-05-02 16:00:00", + "2022-05-02 18:00:00", + "2022-05-02 20:00:00", + "2022-05-02 22:00:00", + "2022-05-03 00:00:00", + "2022-05-03 02:00:00", + "2022-05-03 04:00:00", + "2022-05-03 06:00:00", + "2022-05-03 08:00:00", + "2022-05-03 10:00:00", + "2022-05-03 12:00:00", + "2022-05-03 14:00:00", + "2022-05-03 16:00:00", + "2022-05-03 18:00:00", + "2022-05-03 20:00:00", + "2022-05-03 22:00:00", + "2022-05-04 00:00:00", + "2022-05-04 02:00:00", + "2022-05-04 04:00:00", + "2022-05-04 06:00:00", + "2022-05-04 08:00:00", + "2022-05-04 10:00:00", + "2022-05-04 12:00:00", + "2022-05-04 14:00:00", + "2022-05-04 16:00:00", + "2022-05-04 18:00:00", + "2022-05-04 20:00:00", + "2022-05-04 22:00:00", + "2022-05-05 00:00:00", + "2022-05-05 02:00:00", + "2022-05-05 04:00:00", + "2022-05-05 06:00:00", + "2022-05-05 08:00:00", + "2022-05-05 10:00:00", + "2022-05-05 12:00:00", + "2022-05-05 14:00:00", + "2022-05-05 16:00:00", + "2022-05-05 18:00:00", + "2022-05-05 20:00:00", + "2022-05-05 22:00:00", + "2022-05-06 00:00:00", + "2022-05-06 02:00:00", + "2022-05-06 04:00:00", + "2022-05-06 06:00:00", + "2022-05-06 08:00:00", + "2022-05-06 10:00:00", + "2022-05-06 12:00:00", + "2022-05-06 14:00:00", + "2022-05-06 16:00:00", + "2022-05-06 18:00:00", + "2022-05-06 20:00:00", + "2022-05-06 22:00:00", + "2022-05-07 00:00:00", + "2022-05-07 02:00:00", + "2022-05-07 04:00:00", + "2022-05-07 06:00:00", + "2022-05-07 08:00:00", + "2022-05-07 10:00:00", + "2022-05-07 12:00:00", + "2022-05-07 14:00:00", + "2022-05-07 16:00:00", + "2022-05-07 18:00:00", + "2022-05-07 20:00:00", + "2022-05-07 22:00:00", + "2022-05-08 00:00:00", + "2022-05-08 02:00:00", + "2022-05-08 04:00:00", + "2022-05-08 06:00:00", + "2022-05-08 08:00:00", + "2022-05-08 10:00:00", + "2022-05-08 12:00:00", + "2022-05-08 14:00:00", + "2022-05-08 16:00:00", + "2022-05-08 18:00:00", + "2022-05-08 20:00:00", + "2022-05-08 22:00:00", + "2022-05-09 00:00:00", + "2022-05-09 02:00:00", + "2022-05-09 04:00:00", + "2022-05-09 06:00:00", + "2022-05-09 08:00:00", + "2022-05-09 10:00:00", + "2022-05-09 12:00:00", + "2022-05-09 14:00:00", + "2022-05-09 16:00:00", + "2022-05-09 18:00:00", + "2022-05-09 20:00:00", + "2022-05-09 22:00:00", + "2022-05-10 00:00:00", + "2022-05-10 02:00:00", + "2022-05-10 04:00:00", + "2022-05-10 06:00:00", + "2022-05-10 08:00:00", + "2022-05-10 10:00:00", + "2022-05-10 12:00:00", + "2022-05-10 14:00:00", + "2022-05-10 16:00:00", + "2022-05-10 18:00:00", + "2022-05-10 20:00:00", + "2022-05-10 22:00:00", + "2022-05-11 00:00:00", + "2022-05-11 02:00:00", + "2022-05-11 04:00:00", + "2022-05-11 06:00:00", + "2022-05-11 08:00:00", + "2022-05-11 10:00:00", + "2022-05-11 12:00:00", + "2022-05-11 14:00:00", + "2022-05-11 16:00:00", + "2022-05-11 18:00:00", + "2022-05-11 20:00:00", + "2022-05-11 22:00:00", + "2022-05-12 00:00:00", + "2022-05-12 02:00:00", + "2022-05-12 04:00:00", + "2022-05-12 06:00:00", + "2022-05-12 08:00:00", + "2022-05-12 10:00:00", + "2022-05-12 12:00:00", + "2022-05-12 14:00:00", + "2022-05-12 16:00:00", + "2022-05-12 18:00:00", + "2022-05-12 20:00:00", + "2022-05-12 22:00:00", + "2022-05-13 00:00:00", + "2022-05-13 02:00:00", + "2022-05-13 04:00:00", + "2022-05-13 06:00:00", + "2022-05-13 08:00:00", + "2022-05-13 10:00:00", + "2022-05-13 12:00:00", + "2022-05-13 14:00:00", + "2022-05-13 16:00:00", + "2022-05-13 18:00:00", + "2022-05-13 20:00:00", + "2022-05-13 22:00:00", + "2022-05-14 00:00:00", + "2022-05-14 02:00:00", + "2022-05-14 04:00:00", + "2022-05-14 06:00:00", + "2022-05-14 08:00:00", + "2022-05-14 10:00:00", + "2022-05-14 12:00:00", + "2022-05-14 14:00:00", + "2022-05-14 16:00:00", + "2022-05-14 18:00:00", + "2022-05-14 20:00:00", + "2022-05-14 22:00:00", + "2022-05-15 00:00:00", + "2022-05-15 02:00:00", + "2022-05-15 04:00:00", + "2022-05-15 06:00:00", + "2022-05-15 08:00:00", + "2022-05-15 10:00:00", + "2022-05-15 12:00:00", + "2022-05-15 14:00:00", + "2022-05-15 16:00:00", + "2022-05-15 18:00:00", + "2022-05-15 20:00:00", + "2022-05-15 22:00:00", + "2022-05-16 00:00:00", + "2022-05-16 02:00:00", + "2022-05-16 04:00:00", + "2022-05-16 06:00:00", + "2022-05-16 08:00:00", + "2022-05-16 10:00:00", + "2022-05-16 12:00:00", + "2022-05-16 14:00:00", + "2022-05-16 16:00:00", + "2022-05-16 18:00:00", + "2022-05-16 20:00:00", + "2022-05-16 22:00:00", + "2022-05-17 00:00:00", + "2022-05-17 02:00:00", + "2022-05-17 04:00:00", + "2022-05-17 06:00:00", + "2022-05-17 08:00:00", + "2022-05-17 10:00:00", + "2022-05-17 12:00:00", + "2022-05-17 14:00:00", + "2022-05-17 16:00:00", + "2022-05-17 18:00:00", + "2022-05-17 20:00:00", + "2022-05-17 22:00:00", + "2022-05-18 00:00:00", + "2022-05-18 02:00:00", + "2022-05-18 04:00:00", + "2022-05-18 06:00:00", + "2022-05-18 08:00:00", + "2022-05-18 10:00:00", + "2022-05-18 12:00:00", + "2022-05-18 14:00:00", + "2022-05-18 16:00:00", + "2022-05-18 18:00:00", + "2022-05-18 20:00:00", + "2022-05-18 22:00:00", + "2022-05-19 00:00:00", + "2022-05-19 02:00:00", + "2022-05-19 04:00:00", + "2022-05-19 06:00:00", + "2022-05-19 08:00:00", + "2022-05-19 10:00:00", + "2022-05-19 12:00:00", + "2022-05-19 14:00:00", + "2022-05-19 16:00:00", + "2022-05-19 18:00:00", + "2022-05-19 20:00:00", + "2022-05-19 22:00:00", + "2022-05-20 00:00:00", + "2022-05-20 02:00:00", + "2022-05-20 04:00:00", + "2022-05-20 06:00:00", + "2022-05-20 08:00:00", + "2022-05-20 10:00:00", + "2022-05-20 12:00:00", + "2022-05-20 14:00:00", + "2022-05-20 16:00:00", + "2022-05-20 18:00:00", + "2022-05-20 20:00:00", + "2022-05-20 22:00:00", + "2022-05-21 00:00:00", + "2022-05-21 02:00:00", + "2022-05-21 04:00:00", + "2022-05-21 06:00:00", + "2022-05-21 08:00:00", + "2022-05-21 10:00:00", + "2022-05-21 12:00:00", + "2022-05-21 14:00:00", + "2022-05-21 16:00:00", + "2022-05-21 18:00:00", + "2022-05-21 20:00:00", + "2022-05-21 22:00:00", + "2022-05-22 00:00:00", + "2022-05-22 02:00:00", + "2022-05-22 04:00:00", + "2022-05-22 06:00:00", + "2022-05-22 08:00:00", + "2022-05-22 10:00:00", + "2022-05-22 12:00:00", + "2022-05-22 14:00:00", + "2022-05-22 16:00:00", + "2022-05-22 18:00:00", + "2022-05-22 20:00:00", + "2022-05-22 22:00:00", + "2022-05-23 00:00:00", + "2022-05-23 02:00:00", + "2022-05-23 04:00:00", + "2022-05-23 06:00:00", + "2022-05-23 08:00:00", + "2022-05-23 10:00:00", + "2022-05-23 12:00:00", + "2022-05-23 14:00:00", + "2022-05-23 16:00:00", + "2022-05-23 18:00:00", + "2022-05-23 20:00:00", + "2022-05-23 22:00:00", + "2022-05-24 00:00:00", + "2022-05-24 02:00:00", + "2022-05-24 04:00:00", + "2022-05-24 06:00:00", + "2022-05-24 08:00:00", + "2022-05-24 10:00:00", + "2022-05-24 12:00:00", + "2022-05-24 14:00:00", + "2022-05-24 16:00:00", + "2022-05-24 18:00:00", + "2022-05-24 20:00:00", + "2022-05-24 22:00:00", + "2022-05-25 00:00:00", + "2022-05-25 02:00:00", + "2022-05-25 04:00:00", + "2022-05-25 06:00:00", + "2022-05-25 08:00:00", + "2022-05-25 10:00:00", + "2022-05-25 12:00:00", + "2022-05-25 14:00:00", + "2022-05-25 16:00:00", + "2022-05-25 18:00:00", + "2022-05-25 20:00:00", + "2022-05-25 22:00:00", + "2022-05-26 00:00:00", + "2022-05-26 02:00:00", + "2022-05-26 04:00:00", + "2022-05-26 06:00:00", + "2022-05-26 08:00:00", + "2022-05-26 10:00:00", + "2022-05-26 12:00:00", + "2022-05-26 14:00:00", + "2022-05-26 16:00:00", + "2022-05-26 18:00:00", + "2022-05-26 20:00:00", + "2022-05-26 22:00:00", + "2022-05-27 00:00:00", + "2022-05-27 02:00:00", + "2022-05-27 04:00:00", + "2022-05-27 06:00:00", + "2022-05-27 08:00:00", + "2022-05-27 10:00:00", + "2022-05-27 12:00:00", + "2022-05-27 14:00:00", + "2022-05-27 16:00:00", + "2022-05-27 18:00:00", + "2022-05-27 20:00:00", + "2022-05-27 22:00:00", + "2022-05-28 00:00:00", + "2022-05-28 02:00:00", + "2022-05-28 04:00:00", + "2022-05-28 06:00:00", + "2022-05-28 08:00:00", + "2022-05-28 10:00:00", + "2022-05-28 12:00:00", + "2022-05-28 14:00:00", + "2022-05-28 16:00:00", + "2022-05-28 18:00:00", + "2022-05-28 20:00:00", + "2022-05-28 22:00:00", + "2022-05-29 00:00:00", + "2022-05-29 02:00:00", + "2022-05-29 04:00:00", + "2022-05-29 06:00:00", + "2022-05-29 08:00:00", + "2022-05-29 10:00:00", + "2022-05-29 12:00:00", + "2022-05-29 14:00:00", + "2022-05-29 16:00:00", + "2022-05-29 18:00:00", + "2022-05-29 20:00:00", + "2022-05-29 22:00:00", + "2022-05-30 00:00:00", + "2022-05-30 02:00:00", + "2022-05-30 04:00:00", + "2022-05-30 06:00:00", + "2022-05-30 08:00:00", + "2022-05-30 10:00:00", + "2022-05-30 12:00:00", + "2022-05-30 14:00:00", + "2022-05-30 16:00:00", + "2022-05-30 18:00:00", + "2022-05-30 20:00:00", + "2022-05-30 22:00:00", + "2022-05-31 00:00:00", + "2022-05-31 02:00:00", + "2022-05-31 04:00:00", + "2022-05-31 06:00:00", + "2022-05-31 08:00:00", + "2022-05-31 10:00:00", + "2022-05-31 12:00:00", + "2022-05-31 14:00:00", + "2022-05-31 16:00:00", + "2022-05-31 18:00:00", + "2022-05-31 20:00:00", + "2022-05-31 22:00:00", + "2022-06-01 00:00:00", + "2022-06-01 02:00:00", + "2022-06-01 04:00:00", + "2022-06-01 06:00:00", + "2022-06-01 08:00:00", + "2022-06-01 10:00:00", + "2022-06-01 12:00:00", + "2022-06-01 14:00:00", + "2022-06-01 16:00:00", + "2022-06-01 18:00:00", + "2022-06-01 20:00:00", + "2022-06-01 22:00:00", + "2022-06-02 00:00:00", + "2022-06-02 02:00:00", + "2022-06-02 04:00:00", + "2022-06-02 06:00:00", + "2022-06-02 08:00:00", + "2022-06-02 10:00:00", + "2022-06-02 12:00:00", + "2022-06-02 14:00:00", + "2022-06-02 16:00:00", + "2022-06-02 18:00:00", + "2022-06-02 20:00:00", + "2022-06-02 22:00:00", + "2022-06-03 00:00:00", + "2022-06-03 02:00:00", + "2022-06-03 04:00:00", + "2022-06-03 06:00:00", + "2022-06-03 08:00:00", + "2022-06-03 10:00:00", + "2022-06-03 12:00:00", + "2022-06-03 14:00:00", + "2022-06-03 16:00:00", + "2022-06-03 18:00:00", + "2022-06-03 20:00:00", + "2022-06-03 22:00:00", + "2022-06-04 00:00:00", + "2022-06-04 02:00:00", + "2022-06-04 04:00:00", + "2022-06-04 06:00:00", + "2022-06-04 08:00:00", + "2022-06-04 10:00:00", + "2022-06-04 12:00:00", + "2022-06-04 14:00:00", + "2022-06-04 16:00:00", + "2022-06-04 18:00:00", + "2022-06-04 20:00:00", + "2022-06-04 22:00:00", + "2022-06-05 00:00:00", + "2022-06-05 02:00:00", + "2022-06-05 04:00:00", + "2022-06-05 06:00:00", + "2022-06-05 08:00:00", + "2022-06-05 10:00:00", + "2022-06-05 12:00:00", + "2022-06-05 14:00:00", + "2022-06-05 16:00:00", + "2022-06-05 18:00:00", + "2022-06-05 20:00:00", + "2022-06-05 22:00:00", + "2022-06-06 00:00:00", + "2022-06-06 02:00:00", + "2022-06-06 04:00:00", + "2022-06-06 06:00:00", + "2022-06-06 08:00:00", + "2022-06-06 10:00:00", + "2022-06-06 12:00:00", + "2022-06-06 14:00:00", + "2022-06-06 16:00:00", + "2022-06-06 18:00:00", + "2022-06-06 20:00:00", + "2022-06-06 22:00:00", + "2022-06-07 00:00:00", + "2022-06-07 02:00:00", + "2022-06-07 04:00:00", + "2022-06-07 06:00:00", + "2022-06-07 08:00:00", + "2022-06-07 10:00:00", + "2022-06-07 12:00:00", + "2022-06-07 14:00:00", + "2022-06-07 16:00:00", + "2022-06-07 18:00:00", + "2022-06-07 20:00:00", + "2022-06-07 22:00:00", + "2022-06-08 00:00:00", + "2022-06-08 02:00:00", + "2022-06-08 04:00:00", + "2022-06-08 06:00:00", + "2022-06-08 08:00:00", + "2022-06-08 10:00:00", + "2022-06-08 12:00:00", + "2022-06-08 14:00:00", + "2022-06-08 16:00:00", + "2022-06-08 18:00:00", + "2022-06-08 20:00:00", + "2022-06-08 22:00:00", + "2022-06-09 00:00:00", + "2022-06-09 02:00:00", + "2022-06-09 04:00:00", + "2022-06-09 06:00:00", + "2022-06-09 08:00:00", + "2022-06-09 10:00:00", + "2022-06-09 12:00:00", + "2022-06-09 14:00:00", + "2022-06-09 16:00:00", + "2022-06-09 18:00:00", + "2022-06-09 20:00:00", + "2022-06-09 22:00:00", + "2022-06-10 00:00:00", + "2022-06-10 02:00:00", + "2022-06-10 04:00:00", + "2022-06-10 06:00:00", + "2022-06-10 08:00:00", + "2022-06-10 10:00:00", + "2022-06-10 12:00:00", + "2022-06-10 14:00:00", + "2022-06-10 16:00:00", + "2022-06-10 18:00:00", + "2022-06-10 20:00:00", + "2022-06-10 22:00:00", + "2022-06-11 00:00:00", + "2022-06-11 02:00:00", + "2022-06-11 04:00:00", + "2022-06-11 06:00:00", + "2022-06-11 08:00:00", + "2022-06-11 10:00:00", + "2022-06-11 12:00:00", + "2022-06-11 14:00:00", + "2022-06-11 16:00:00", + "2022-06-11 18:00:00", + "2022-06-11 20:00:00", + "2022-06-11 22:00:00", + "2022-06-12 00:00:00", + "2022-06-12 02:00:00", + "2022-06-12 04:00:00", + "2022-06-12 06:00:00", + "2022-06-12 08:00:00", + "2022-06-12 10:00:00", + "2022-06-12 12:00:00", + "2022-06-12 14:00:00", + "2022-06-12 16:00:00", + "2022-06-12 18:00:00", + "2022-06-12 20:00:00", + "2022-06-12 22:00:00", + "2022-06-13 00:00:00", + "2022-06-13 02:00:00", + "2022-06-13 04:00:00", + "2022-06-13 06:00:00", + "2022-06-13 08:00:00", + "2022-06-13 10:00:00", + "2022-06-13 12:00:00", + "2022-06-13 14:00:00", + "2022-06-13 16:00:00", + "2022-06-13 18:00:00", + "2022-06-13 20:00:00", + "2022-06-13 22:00:00", + "2022-06-14 00:00:00", + "2022-06-14 02:00:00", + "2022-06-14 04:00:00", + "2022-06-14 06:00:00", + "2022-06-14 08:00:00", + "2022-06-14 10:00:00", + "2022-06-14 12:00:00", + "2022-06-14 14:00:00", + "2022-06-14 16:00:00", + "2022-06-14 18:00:00", + "2022-06-14 20:00:00", + "2022-06-14 22:00:00", + "2022-06-15 00:00:00", + "2022-06-15 02:00:00", + "2022-06-15 04:00:00", + "2022-06-15 06:00:00", + "2022-06-15 08:00:00", + "2022-06-15 10:00:00", + "2022-06-15 12:00:00", + "2022-06-15 14:00:00", + "2022-06-15 16:00:00", + "2022-06-15 18:00:00", + "2022-06-15 20:00:00", + "2022-06-15 22:00:00", + "2022-06-16 00:00:00", + "2022-06-16 02:00:00", + "2022-06-16 04:00:00", + "2022-06-16 06:00:00", + "2022-06-16 08:00:00", + "2022-06-16 10:00:00", + "2022-06-16 12:00:00", + "2022-06-16 14:00:00", + "2022-06-16 16:00:00", + "2022-06-16 18:00:00", + "2022-06-16 20:00:00", + "2022-06-16 22:00:00", + "2022-06-17 00:00:00", + "2022-06-17 02:00:00", + "2022-06-17 04:00:00", + "2022-06-17 06:00:00", + "2022-06-17 08:00:00", + "2022-06-17 10:00:00", + "2022-06-17 12:00:00", + "2022-06-17 14:00:00", + "2022-06-17 16:00:00", + "2022-06-17 18:00:00", + "2022-06-17 20:00:00", + "2022-06-17 22:00:00", + "2022-06-18 00:00:00", + "2022-06-18 02:00:00", + "2022-06-18 04:00:00", + "2022-06-18 06:00:00", + "2022-06-18 08:00:00", + "2022-06-18 10:00:00", + "2022-06-18 12:00:00", + "2022-06-18 14:00:00", + "2022-06-18 16:00:00", + "2022-06-18 18:00:00", + "2022-06-18 20:00:00", + "2022-06-18 22:00:00", + "2022-06-19 00:00:00", + "2022-06-19 02:00:00", + "2022-06-19 04:00:00", + "2022-06-19 06:00:00", + "2022-06-19 08:00:00", + "2022-06-19 10:00:00", + "2022-06-19 12:00:00", + "2022-06-19 14:00:00", + "2022-06-19 16:00:00", + "2022-06-19 18:00:00", + "2022-06-19 20:00:00", + "2022-06-19 22:00:00", + "2022-06-20 00:00:00" + ], + "y": [ + 42439.0, + 43107.0, + 43012.0, + 43059.0, + 43312.0, + 43373.0, + 42955.0, + 43201.0, + 43123.0, + 43483.0, + 43344.0, + 43259.0, + 43616.0, + 43455.0, + 43705.0, + 43398.0, + 43366.0, + 42972.0, + 43196.0, + 42987.0, + 43180.0, + 43341.0, + 42905.0, + 42770.0, + 42822.0, + 42687.0, + 42521.0, + 42773.0, + 42765.0, + 43061.0, + 43170.0, + 44209.0, + 45099.0, + 44902.0, + 44856.0, + 45334.0, + 45095.0, + 45071.0, + 45072.0, + 45257.0, + 45048.0, + 45129.0, + 45098.0, + 45237.0, + 45234.0, + 45012.0, + 44934.0, + 45099.0, + 44965.0, + 45009.0, + 45029.0, + 44971.0, + 44879.0, + 45025.0, + 44862.0, + 44886.0, + 45049.0, + 45080.0, + 44640.0, + 44749.0, + 44006.0, + 44170.0, + 44227.0, + 44252.0, + 44063.0, + 44087.0, + 44308.0, + 44497.0, + 44537.0, + 44880.0, + 44903.0, + 44935.0, + 45038.0, + 44999.0, + 44761.0, + 44940.0, + 44910.0, + 45403.0, + 45494.0, + 45830.0, + 45275.0, + 44985.0, + 44771.0, + 44078.0, + 44030.0, + 43501.0, + 43534.0, + 43306.0, + 43481.0, + 43300.0, + 43374.0, + 42502.0, + 42240.0, + 42098.0, + 42055.0, + 42254.0, + 42455.0, + 42377.0, + 42125.0, + 42516.0, + 42270.0, + 41889.0, + 42291.0, + 41938.0, + 41540.0, + 41650.0, + 40936.0, + 41079.0, + 41060.0, + 41316.0, + 41544.0, + 41380.0, + 42000.0, + 41850.0, + 41627.0, + 42164.0, + 42030.0, + 41775.0, + 41633.0, + 41666.0, + 41762.0, + 41802.0, + 41729.0, + 42660.0, + 42403.0, + 42279.0, + 42214.0, + 41347.0, + 40189.0, + 40776.0, + 40687.0, + 41214.0, + 41213.0, + 41549.0, + 41546.0, + 41466.0, + 41220.0, + 41456.0, + 41557.0, + 42062.0, + 41694.0, + 41651.0, + 42034.0, + 41735.0, + 41688.0, + 41476.0, + 41575.0, + 41600.0, + 41624.0, + 41528.0, + 41715.0, + 41741.0, + 41302.0, + 41412.0, + 41645.0, + 41515.0, + 41287.0, + 41582.0, + 41516.0, + 41409.0, + 41758.0, + 41562.0, + 41369.0, + 41305.0, + 41057.0, + 40776.0, + 41113.0, + 40757.0, + 40990.0, + 40824.0, + 41257.0, + 41034.0, + 41410.0, + 41604.0, + 41450.0, + 41233.0, + 40804.0, + 40971.0, + 40642.0, + 40888.0, + 41112.0, + 41009.0, + 41052.0, + 41501.0, + 40921.0, + 40999.0, + 41151.0, + 40601.0, + 39532.0, + 38601.0, + 38448.0, + 38520.0, + 37866.0, + 38077.0, + 38331.0, + 37700.0, + 37935.0, + 38164.0, + 38052.0, + 38123.0, + 38533.0, + 38208.0, + 38165.0, + 38086.0, + 37041.0, + 37042.0, + 36891.0, + 37493.0, + 37417.0, + 36724.0, + 36464.0, + 37003.0, + 36781.0, + 36899.0, + 36588.0, + 36844.0, + 36808.0, + 36969.0, + 36979.0, + 37218.0, + 37023.0, + 36999.0, + 36708.0, + 35971.0, + 35979.0, + 36829.0, + 36734.0, + 36859.0, + 36859.0, + 36772.0, + 36878.0, + 36600.0, + 36916.0, + 36593.0, + 36687.0, + 37144.0, + 37722.0, + 37284.0, + 36914.0, + 36830.0, + 37080.0, + 37138.0, + 37172.0, + 36980.0, + 36700.0, + 36129.0, + 36217.0, + 36350.0, + 36453.0, + 36868.0, + 36908.0, + 37011.0, + 37253.0, + 37122.0, + 37254.0, + 37074.0, + 36947.0, + 36855.0, + 36839.0, + 37539.0, + 37881.0, + 37579.0, + 37608.0, + 37514.0, + 37510.0, + 37598.0, + 37527.0, + 37670.0, + 37846.0, + 38580.0, + 38183.0, + 38401.0, + 38276.0, + 38327.0, + 38424.0, + 38098.0, + 38056.0, + 38240.0, + 38177.0, + 38299.0, + 38068.0, + 38313.0, + 37761.0, + 37390.0, + 37268.0, + 37428.0, + 37178.0, + 37167.0, + 37228.0, + 37417.0, + 37187.0, + 37180.0, + 36735.0, + 36899.0, + 37706.0, + 37649.0, + 37804.0, + 37937.0, + 37750.0, + 37682.0, + 37706.0, + 37792.0, + 37855.0, + 37858.0, + 37805.0, + 37695.0, + 38112.0, + 38092.0, + 38207.0, + 37968.0, + 37760.0, + 37782.0, + 37803.0, + 37743.0, + 37914.0, + 37827.0, + 37712.0, + 37889.0, + 37930.0, + 37746.0, + 37585.0, + 37669.0, + 37765.0, + 37618.0, + 37401.0, + 37403.0, + 37387.0, + 37533.0, + 37407.0, + 37409.0, + 37288.0, + 36958.0, + 37093.0, + 36617.0, + 37022.0, + 37041.0, + 36934.0, + 36991.0, + 36905.0, + 36814.0, + 36790.0, + 36633.0, + 36709.0, + 36631.0, + 36848.0, + 37447.0, + 37417.0, + 37526.0, + 36852.0, + 36881.0, + 36424.0, + 36713.0, + 37046.0, + 37240.0, + 37065.0, + 37172.0, + 36952.0, + 36813.0, + 36759.0, + 36793.0, + 36971.0, + 36955.0, + 37050.0, + 37088.0, + 37150.0, + 37342.0, + 38146.0, + 37993.0, + 37984.0, + 36523.0, + 36020.0, + 35168.0, + 34031.0, + 34414.0, + 34589.0, + 34389.0, + 34343.0, + 33891.0, + 34272.0, + 33861.0, + 33518.0, + 32405.0, + 32183.0, + 32248.0, + 32099.0, + 31533.0, + 31228.0, + 30676.0, + 31297.0, + 31469.0, + 30774.0, + 30579.0, + 30473.0, + 31225.0, + 30981.0, + 31171.0, + 30988.0, + 31343.0, + 31450.0, + 31721.0, + 31586.0, + 31850.0, + 31192.0, + 31244.0, + 30696.0, + 31163.0, + 32015.0, + 31485.0, + 31235.0, + 31088.0, + 30811.0, + 30496.0, + 29799.0, + 29543.0, + 30289.0, + 31238.0, + 31866.0, + 32555.0, + 32403.0, + 31918.0, + 32241.0, + 31904.0, + 31933.0, + 32276.0, + 32367.0, + 32417.0, + 32470.0, + 33059.0, + 32845.0, + 32382.0, + 32703.0, + 32607.0, + 33144.0, + 33324.0, + 33140.0, + 33399.0, + 33842.0, + 33914.0, + 33708.0, + 33751.0, + 33448.0, + 32343.0, + 32778.0, + 31920.0, + 31898.0, + 32132.0, + 32353.0, + 32676.0, + 32920.0, + 33047.0, + 32909.0, + 32616.0, + 32536.0, + 32468.0, + 33389.0, + 33123.0, + 33537.0, + 33388.0, + 33054.0, + 32805.0, + 32741.0, + 33089.0, + 33355.0, + 33054.0, + 33423.0, + 33887.0, + 33883.0, + 33694.0, + 33926.0, + 33856.0, + 34047.0, + 33927.0, + 33933.0, + 34271.0, + 33758.0, + 33840.0, + 34026.0, + 34476.0, + 34293.0, + 34106.0, + 34088.0, + 34281.0, + 34395.0, + 34077.0, + 34275.0, + 34131.0, + 34151.0, + 34146.0, + 33693.0, + 33903.0, + 34048.0, + 33030.0, + 33220.0, + 33192.0, + 33283.0, + 33320.0, + 33443.0, + 33349.0, + 33682.0, + 34347.0, + 34204.0, + 34237.0, + 34296.0, + 34101.0, + 34370.0, + 34262.0, + 34143.0, + 34009.0, + 34174.0, + 34507.0, + 34385.0, + 34612.0, + 34134.0, + 34473.0, + 34379.0, + 34130.0, + 34251.0, + 34123.0, + 33963.0, + 34158.0, + 34063.0, + 33920.0, + 33167.0, + 33162.0, + 33277.0, + 32716.0, + 32693.0, + 32690.0, + 32629.0, + 32798.0, + 32848.0, + 32478.0, + 32640.0, + 32238.0, + 32378.0, + 32218.0, + 32007.0, + 32339.0, + 32606.0, + 32506.0, + 32595.0, + 32795.0, + 33053.0, + 33203.0, + 32977.0, + 32776.0, + 34545.0, + 35412.0, + 35573.0, + 35484.0, + 36296.0, + 36112.0, + 36205.0, + 36315.0, + 36166.0, + 36322.0, + 36232.0, + 36316.0, + 36536.0, + 36365.0, + 36327.0, + 36452.0, + 36221.0, + 36363.0, + 36248.0, + 36334.0, + 36400.0, + 36445.0, + 36337.0, + 36470.0, + 36350.0, + 36397.0, + 36468.0, + 36371.0, + 37015.0, + 36835.0, + 37559.0, + 37483.0, + 37438.0, + 37195.0, + 37365.0, + 37473.0, + 38384.0, + 38752.0, + 38751.0, + 38540.0, + 38361.0, + 38582.0, + 38671.0, + 39384.0, + 39443.0, + 38474.0, + 38536.0, + 38265.0, + 38066.0, + 37659.0, + 37739.0, + 38776.0, + 38568.0, + 38454.0, + 37976.0, + 38228.0, + 38453.0, + 37997.0, + 38315.0, + 38476.0, + 38460.0, + 38586.0, + 38923.0, + 38965.0, + 38875.0, + 38799.0, + 38366.0, + 38481.0, + 38635.0, + 38868.0, + 39276.0, + 38317.0, + 39249.0, + 39593.0, + 38804.0, + 38327.0, + 38122.0, + 37870.0, + 38100.0, + 37692.0, + 38090.0, + 38250.0, + 38076.0, + 38489.0, + 38335.0, + 38156.0, + 37719.0, + 37506.0, + 37359.0, + 37442.0, + 37361.0, + 37352.0, + 37165.0, + 37451.0, + 37400.0, + 37134.0, + 37140.0, + 37672.0, + 37584.0, + 36950.0, + 37236.0, + 37276.0, + 37281.0, + 37324.0, + 37445.0, + 37374.0, + 37506.0, + 37521.0, + 37538.0, + 37296.0, + 37031.0, + 37257.0, + 37000.0, + 36744.0, + 36990.0, + 36786.0, + 37307.0, + 37176.0, + 37239.0, + 37612.0, + 37685.0, + 37649.0, + 37335.0, + 37354.0, + 37628.0, + 38409.0, + 38475.0, + 38498.0, + 38665.0, + 38875.0, + 39015.0, + 39012.0, + 38966.0, + 38691.0, + 38768.0, + 38755.0, + 39232.0, + 38755.0, + 38795.0, + 38847.0, + 38857.0, + 38775.0, + 38857.0, + 38435.0, + 38395.0, + 38322.0, + 38856.0, + 38759.0, + 38575.0, + 38733.0, + 38490.0, + 38434.0, + 38671.0, + 38065.0, + 38024.0, + 37199.0, + 36922.0, + 36761.0, + 36294.0, + 35849.0, + 35729.0, + 35924.0, + 35846.0, + 35795.0, + 35766.0, + 36014.0, + 35367.0, + 35632.0, + 35137.0, + 35398.0, + 35480.0, + 35335.0, + 35353.0, + 35487.0, + 35495.0, + 35594.0, + 35607.0, + 35312.0, + 35213.0, + 35374.0, + 35343.0, + 35474.0, + 35299.0, + 35254.0, + 35387.0, + 35346.0, + 35171.0, + 34743.0, + 34218.0, + 33690.0, + 33803.0, + 33726.0, + 33870.0, + 33779.0, + 33920.0, + 33798.0, + 33911.0, + 34480.0, + 34311.0, + 34568.0, + 34600.0, + 34296.0, + 33131.0, + 33147.0, + 34286.0, + 34022.0, + 33683.0, + 32759.0, + 32723.0, + 32932.0, + 32347.0, + 32532.0, + 32551.0, + 32823.0, + 33101.0, + 33401.0, + 33337.0, + 33205.0, + 33604.0, + 33475.0, + 33748.0, + 33597.0, + 33332.0, + 33586.0, + 33722.0, + 34272.0, + 34205.0, + 34352.0, + 34002.0, + 33685.0, + 33289.0, + 33200.0, + 32921.0, + 32754.0, + 31133.0, + 30829.0, + 31402.0, + 31499.0, + 31730.0, + 31824.0, + 32355.0, + 32102.0, + 33380.0, + 34317.0, + 34264.0, + 34457.0, + 34747.0, + 34281.0, + 34350.0, + 34628.0, + 34677.0, + 35083.0, + 35065.0, + 34724.0, + 34397.0, + 34621.0, + 34801.0, + 35275.0, + 35037.0, + 34668.0, + 34848.0, + 34494.0, + 34629.0, + 34758.0, + 34866.0, + 34896.0, + 34875.0, + 35032.0, + 34691.0, + 33964.0, + 34313.0, + 34304.0, + 34492.0, + 34708.0, + 35029.0, + 34671.0, + 34912.0, + 34562.0, + 33474.0, + 33572.0, + 33733.0, + 34046.0, + 33895.0, + 33957.0, + 34294.0, + 34147.0, + 34274.0, + 33961.0, + 36381.0, + 36946.0, + 36874.0, + 37104.0, + 38534.0, + 38598.0, + 38594.0, + 38612.0, + 38745.0, + 38670.0, + 38999.0, + 39871.0, + 39174.0, + 39332.0, + 39315.0, + 39466.0, + 39942.0, + 39609.0, + 39871.0, + 39883.0, + 39660.0, + 39618.0, + 39785.0, + 39203.0, + 39897.0, + 39470.0, + 39324.0, + 39646.0, + 39505.0, + 39508.0, + 39073.0, + 39075.0, + 39197.0, + 38918.0, + 39146.0, + 39717.0, + 38490.0, + 38344.0, + 38180.0, + 38027.0, + 38371.0, + 37611.0, + 37607.0, + 37546.0, + 37625.0, + 37708.0, + 37958.0, + 37837.0, + 37233.0, + 37389.0, + 36394.0, + 36041.0, + 35832.0, + 35681.0, + 35758.0, + 35704.0, + 35772.0, + 35778.0, + 35850.0, + 35719.0, + 35838.0, + 36144.0, + 36145.0, + 36064.0, + 36085.0, + 36113.0, + 36049.0, + 36183.0, + 36112.0, + 35446.0, + 35147.0, + 35594.0, + 35542.0, + 35720.0, + 35417.0, + 35743.0, + 35331.0, + 35318.0, + 34863.0, + 34993.0, + 34869.0, + 35160.0, + 35357.0, + 35842.0, + 35913.0, + 35479.0, + 34388.0, + 34901.0, + 34983.0, + 35266.0, + 35575.0, + 35321.0, + 35486.0, + 35801.0, + 35808.0, + 35589.0, + 35532.0, + 35745.0, + 35584.0, + 35351.0, + 35544.0, + 35864.0, + 37785.0, + 37921.0, + 38280.0, + 38346.0, + 38407.0, + 37972.0, + 38478.0, + 38145.0, + 38160.0, + 37796.0, + 37858.0, + 37129.0, + 36912.0, + 35491.0, + 35500.0, + 35505.0, + 35446.0, + 35182.0, + 35606.0, + 35640.0, + 35899.0, + 35798.0, + 35828.0, + 35165.0, + 35214.0, + 35300.0, + 35617.0, + 35604.0, + 36226.0, + 35747.0, + 35669.0, + 35587.0, + 35582.0, + 35606.0, + 35507.0, + 35935.0, + 35855.0, + 35900.0, + 35840.0, + 35897.0, + 35838.0, + 35818.0, + 35850.0, + 35834.0, + 35820.0, + 35875.0, + 35605.0, + 35760.0, + 35946.0, + 35929.0, + 35790.0, + 35773.0, + 35556.0, + 35526.0, + 35676.0, + 35690.0, + 35600.0, + 35425.0, + 34601.0, + 34917.0, + 35031.0, + 35286.0, + 35747.0, + 35664.0, + 35569.0, + 35557.0, + 35505.0, + 35321.0, + 35468.0, + 35418.0, + 36256.0, + 35440.0, + 35360.0, + 35307.0, + 34951.0, + 35036.0, + 35215.0, + 35214.0, + 35548.0, + 35914.0, + 36249.0, + 36193.0, + 35848.0, + 36030.0, + 35733.0, + 35838.0, + 36090.0, + 36872.0, + 36795.0, + 36914.0, + 36975.0, + 36781.0, + 37000.0, + 37267.0, + 37282.0, + 37325.0, + 37148.0, + 37274.0, + 36904.0, + 36931.0, + 36882.0, + 37193.0, + 36771.0, + 36691.0, + 36805.0, + 36983.0, + 36910.0, + 36580.0, + 36622.0, + 36786.0, + 36642.0, + 36635.0, + 36674.0, + 36848.0, + 37077.0, + 37717.0, + 38057.0, + 37834.0, + 37775.0, + 37729.0, + 37838.0, + 37736.0, + 37618.0, + 37687.0, + 37733.0, + 37800.0, + 37973.0, + 37938.0, + 38060.0, + 38134.0, + 38151.0, + 37975.0, + 37920.0, + 37883.0, + 37894.0, + 37803.0, + 37644.0, + 37496.0, + 37386.0, + 37088.0, + 37452.0, + 37424.0, + 37351.0, + 37309.0, + 37005.0, + 37115.0, + 37186.0, + 37417.0, + 37420.0, + 37301.0, + 37338.0, + 37251.0, + 37358.0, + 37468.0, + 37240.0, + 37416.0, + 38340.0, + 39011.0, + 38472.0, + 38599.0, + 39079.0, + 38793.0, + 38646.0, + 38656.0, + 38349.0, + 38867.0, + 38401.0, + 38366.0, + 38206.0, + 38136.0, + 38221.0, + 38331.0, + 38294.0, + 38313.0, + 38737.0, + 38337.0, + 38400.0, + 38497.0, + 38953.0, + 38956.0, + 38892.0, + 39172.0, + 39266.0, + 39140.0, + 39139.0, + 39184.0, + 39948.0, + 39871.0, + 39943.0, + 40016.0, + 39982.0, + 39977.0, + 39898.0, + 39994.0, + 39863.0, + 40081.0, + 40471.0, + 40854.0, + 40294.0, + 40301.0, + 40488.0, + 40550.0, + 40387.0, + 40336.0, + 40489.0, + 40594.0, + 40603.0, + 40577.0, + 40451.0, + 40341.0, + 40294.0, + 40418.0, + 40434.0, + 40504.0, + 40585.0, + 40771.0, + 40699.0, + 40682.0, + 40784.0, + 40613.0, + 40590.0, + 40671.0, + 40840.0, + 40900.0, + 40810.0, + 42347.0, + 42669.0, + 42719.0, + 42902.0, + 42992.0, + 42907.0, + 42931.0, + 43132.0, + 43547.0, + 43179.0, + 43360.0, + 43659.0, + 43348.0, + 42838.0, + 43285.0, + 43078.0, + 43423.0, + 43048.0, + 43138.0, + 43226.0, + 42847.0, + 42690.0, + 42860.0, + 43061.0, + 42631.0, + 42768.0, + 42201.0, + 42711.0, + 42776.0, + 42558.0, + 42385.0, + 42465.0, + 42089.0, + 42248.0, + 42780.0, + 42244.0, + 42127.0, + 42195.0, + 42402.0, + 42169.0, + 42166.0, + 42333.0, + 42565.0, + 42499.0, + 42308.0, + 41857.0, + 41359.0, + 41245.0, + 41332.0, + 41130.0, + 40600.0, + 40318.0, + 40363.0, + 40750.0, + 40834.0, + 40787.0, + 41174.0, + 42130.0, + 42103.0, + 42000.0, + 41949.0, + 41920.0, + 42294.0, + 42174.0, + 42159.0, + 42217.0, + 42295.0, + 42192.0, + 42329.0, + 41893.0, + 41997.0, + 41769.0, + 41906.0, + 41474.0, + 41557.0, + 41655.0, + 41995.0, + 42034.0, + 42027.0, + 41889.0, + 42076.0, + 42032.0, + 42013.0, + 42001.0, + 42503.0, + 42060.0, + 41555.0, + 41641.0, + 41867.0, + 41842.0, + 41703.0, + 41965.0, + 42047.0, + 41524.0, + 41412.0, + 41900.0, + 42352.0, + 42465.0, + 42530.0, + 42497.0, + 42544.0, + 42514.0, + 42413.0, + 42566.0, + 42333.0, + 41930.0, + 42137.0, + 42209.0, + 42169.0, + 41742.0, + 41547.0, + 41521.0, + 41731.0, + 41578.0, + 41560.0, + 41072.0, + 40452.0, + 40504.0, + 40226.0, + 40175.0, + 40273.0, + 39609.0, + 39762.0, + 39708.0, + 39742.0, + 39874.0, + 39905.0, + 40126.0, + 40019.0, + 39789.0, + 40118.0, + 39937.0, + 40029.0, + 39980.0, + 40172.0, + 40127.0, + 40190.0, + 40281.0, + 40138.0, + 39865.0, + 39622.0, + 40142.0, + 39590.0, + 39285.0, + 39175.0, + 38893.0, + 38969.0, + 39002.0, + 39163.0, + 39102.0, + 39082.0, + 39072.0, + 39087.0, + 38831.0, + 39156.0, + 39140.0, + 39165.0, + 39370.0, + 39383.0, + 39394.0, + 39290.0, + 39232.0, + 39099.0, + 39306.0, + 39219.0, + 39370.0, + 39708.0, + 39705.0, + 39205.0, + 38740.0, + 38764.0, + 38726.0, + 38855.0, + 38817.0, + 38000.0, + 37684.0, + 37829.0, + 37333.0, + 37182.0, + 36729.0, + 36235.0, + 36318.0, + 36327.0, + 36570.0, + 36954.0, + 36989.0, + 36998.0, + 37200.0, + 37197.0, + 37046.0, + 36976.0, + 36294.0, + 36693.0, + 37042.0, + 36787.0, + 37012.0, + 37110.0, + 37006.0, + 37027.0, + 36729.0, + 37497.0, + 37934.0, + 37761.0, + 37760.0, + 37883.0, + 37784.0, + 38064.0, + 37912.0, + 37892.0, + 37824.0, + 37733.0, + 37622.0, + 37732.0, + 37024.0, + 36940.0, + 36723.0, + 36934.0, + 36941.0, + 36960.0, + 37220.0, + 37150.0, + 37271.0, + 37087.0, + 37173.0, + 37073.0, + 37396.0, + 37445.0, + 37349.0, + 37427.0, + 37551.0, + 37538.0, + 37406.0, + 37456.0, + 37422.0, + 37355.0, + 37393.0, + 37410.0, + 37109.0, + 37194.0, + 37267.0, + 37472.0, + 37365.0, + 37418.0, + 37288.0, + 37414.0, + 37303.0, + 37424.0, + 37490.0, + 37360.0, + 37464.0, + 37135.0, + 37356.0, + 37229.0, + 36724.0, + 36817.0, + 36905.0, + 36108.0, + 36088.0, + 36151.0, + 36114.0, + 36435.0, + 36436.0, + 37272.0, + 37712.0, + 37869.0, + 37851.0, + 37836.0, + 37801.0, + 37771.0, + 37661.0, + 37643.0, + 37722.0, + 38400.0, + 38424.0, + 38342.0, + 38404.0, + 38287.0, + 38434.0, + 38314.0, + 38307.0, + 38266.0, + 38299.0, + 38878.0, + 38351.0, + 38037.0, + 38146.0, + 37944.0, + 38270.0, + 38148.0, + 38471.0, + 38533.0, + 38251.0, + 38362.0, + 38336.0, + 39025.0, + 39265.0, + 38858.0, + 38293.0, + 38075.0, + 37615.0, + 37382.0, + 37443.0, + 37375.0, + 37532.0, + 37701.0, + 37325.0, + 37496.0, + 37244.0, + 36532.0, + 36493.0, + 36620.0, + 36730.0, + 36815.0, + 36722.0, + 36590.0, + 36702.0, + 36729.0, + 36671.0, + 36732.0, + 36838.0, + 36923.0, + 36907.0, + 36897.0, + 37019.0, + 36552.0, + 36599.0, + 36900.0, + 36767.0, + 36875.0, + 36835.0, + 36739.0, + 36691.0, + 36749.0, + 36564.0, + 36740.0, + 36700.0, + 36538.0, + 36322.0, + 36423.0, + 36182.0, + 35831.0, + 35981.0, + 36153.0, + 36161.0, + 36401.0, + 36783.0, + 37543.0, + 37529.0, + 37709.0, + 37754.0, + 37755.0, + 37839.0, + 37981.0, + 37806.0, + 37894.0, + 37252.0, + 36186.0, + 36082.0, + 35958.0, + 36057.0, + 35838.0, + 36013.0, + 36016.0, + 36053.0, + 36748.0, + 36798.0, + 36827.0, + 37313.0, + 36991.0, + 37007.0, + 36782.0, + 37189.0, + 37190.0, + 37192.0, + 37441.0, + 37420.0, + 37305.0, + 37832.0, + 37810.0, + 37176.0, + 37631.0, + 38342.0, + 38007.0, + 37945.0, + 37864.0, + 37867.0, + 37590.0, + 37487.0, + 37509.0, + 37018.0, + 36731.0, + 37342.0, + 36982.0, + 36592.0, + 36349.0, + 36602.0, + 36631.0, + 36733.0, + 36696.0, + 36733.0, + 36678.0, + 36678.0, + 36594.0, + 36559.0, + 36532.0, + 36361.0, + 36533.0, + 36385.0, + 35749.0, + 35999.0, + 36121.0, + 36151.0, + 36026.0, + 36076.0, + 36030.0, + 35968.0, + 36539.0, + 36433.0, + 35884.0, + 36376.0, + 36487.0, + 36576.0, + 36750.0, + 37100.0, + 36885.0, + 36845.0, + 36616.0, + 36966.0, + 36758.0, + 36501.0, + 36695.0, + 36781.0, + 36659.0, + 36566.0, + 36605.0, + 36665.0, + 36652.0, + 36581.0, + 36610.0, + 36344.0, + 36385.0, + 36183.0, + 35854.0, + 35902.0, + 35854.0, + 35991.0, + 36152.0, + 36214.0, + 36768.0, + 36936.0, + 37016.0, + 36694.0, + 36973.0, + 36979.0, + 37574.0, + 37376.0, + 37337.0, + 37274.0, + 37424.0, + 37300.0, + 37315.0, + 37209.0, + 37435.0, + 36949.0, + 35174.0, + 35085.0, + 34462.0, + 34598.0, + 34699.0, + 34495.0, + 34620.0, + 34701.0, + 34598.0, + 34452.0, + 33876.0, + 33799.0, + 34014.0, + 34027.0, + 34150.0, + 34113.0, + 34123.0, + 34122.0, + 33963.0, + 34038.0, + 34075.0, + 34106.0, + 34215.0, + 34080.0, + 34132.0, + 34059.0, + 34047.0, + 33200.0, + 33634.0, + 33010.0, + 32740.0, + 32700.0, + 32842.0, + 32798.0, + 32975.0, + 32600.0, + 32600.0, + 32316.0, + 32816.0, + 32686.0, + 32284.0, + 32323.0, + 31940.0, + 31860.0, + 31892.0, + 31767.0, + 31403.0, + 31303.0, + 30626.0, + 29633.0, + 29362.0, + 29220.0, + 28501.0, + 29243.0, + 29001.0, + 30110.0, + 29969.0, + 29815.0, + 29982.0, + 30169.0, + 29739.0, + 30073.0, + 29750.0, + 28750.0, + 29426.0, + 29220.0, + 29624.0, + 29829.0, + 28979.0, + 30016.0, + 29840.0, + 29377.0, + 29316.0, + 28385.0, + 27885.0, + 27557.0, + 27553.0, + 27672.0, + 26893.0, + 25502.0, + 26534.0, + 26399.0, + 27151.0, + 26913.0, + 27814.0, + 27533.0, + 27517.0, + 27325.0, + 27893.0, + 28339.0, + 29294.0, + 29337.0, + 28908.0, + 29338.0, + 29503.0, + 29643.0, + 29142.0, + 28478.0, + 28919.0, + 28837.0, + 28128.0, + 28520.0, + 28400.0, + 28274.0, + 28244.0, + 28314.0, + 27907.0, + 27673.0, + 27690.0, + 28458.0, + 28169.0, + 28513.0, + 28918.0, + 28766.0, + 28574.0, + 28591.0, + 28671.0, + 28615.0, + 29064.0, + 29008.0, + 28831.0, + 28795.0, + 29277.0, + 29901.0, + 30112.0, + 29551.0, + 29161.0, + 29074.0, + 28442.0, + 28421.0, + 28772.0, + 28348.0, + 28458.0, + 28480.0, + 28332.0, + 28899.0, + 28585.0, + 28654.0, + 29040.0, + 29173.0, + 29042.0, + 29217.0, + 28762.0, + 28961.0, + 28610.0, + 28505.0, + 28530.0, + 28942.0, + 28854.0, + 28570.0, + 28317.0, + 28467.0, + 28418.0, + 28446.0, + 28332.0, + 27851.0, + 27588.0, + 27625.0, + 27968.0, + 27853.0, + 27393.0, + 27414.0, + 27785.0, + 27662.0, + 27800.0, + 27603.0, + 28030.0, + 27873.0, + 28680.0, + 28419.0, + 28279.0, + 28558.0, + 28636.0, + 28789.0, + 28532.0, + 28450.0, + 28584.0, + 28566.0, + 28764.0, + 28733.0, + 27579.0, + 27440.0, + 27720.0, + 27619.0, + 27618.0, + 27582.0, + 27675.0, + 27717.0, + 27859.0, + 27747.0, + 27715.0, + 27737.0, + 27963.0, + 27821.0, + 27884.0, + 27750.0, + 27837.0, + 27888.0, + 27765.0, + 27782.0, + 27853.0, + 28479.0, + 28240.0, + 28418.0, + 28215.0, + 28282.0, + 28307.0, + 28393.0, + 28633.0, + 28493.0, + 28460.0, + 28538.0, + 28701.0, + 28486.0, + 28495.0, + 28405.0, + 28425.0, + 28143.0, + 27205.0, + 27446.0, + 27231.0, + 27381.0, + 27449.0, + 27482.0, + 27400.0, + 27375.0, + 27329.0, + 26923.0, + 27374.0, + 27335.0, + 27334.0, + 27540.0, + 27585.0, + 27778.0, + 28128.0, + 27840.0, + 27751.0, + 27877.0, + 27570.0, + 27840.0, + 27753.0, + 27831.0, + 27673.0, + 27905.0, + 27594.0, + 27746.0, + 27852.0, + 27825.0, + 27791.0, + 27252.0, + 27076.0, + 26887.0, + 27398.0, + 27650.0, + 27392.0, + 27542.0, + 27219.0, + 26846.0, + 27000.0, + 26776.0, + 26972.0, + 27082.0, + 26957.0, + 27280.0, + 26949.0, + 26443.0, + 26886.0, + 26729.0, + 26616.0, + 26625.0, + 26847.0, + 26894.0, + 26892.0, + 26842.0, + 26858.0, + 27081.0, + 27009.0, + 26889.0, + 27030.0, + 27027.0, + 27036.0, + 26917.0, + 27006.0, + 27051.0, + 27024.0, + 27015.0, + 27221.0, + 27309.0, + 27218.0, + 27225.0, + 27110.0, + 27221.0, + 27433.0, + 27633.0, + 28256.0, + 28289.0, + 28489.0, + 28509.0, + 28438.0, + 28314.0, + 28388.0, + 28470.0, + 28435.0, + 29500.0, + 29411.0, + 29336.0, + 29540.0, + 29440.0, + 29386.0, + 29377.0, + 29628.0, + 29297.0, + 29871.0, + 29927.0, + 29476.0, + 29527.0, + 29588.0, + 29781.0, + 29503.0, + 29528.0, + 29350.0, + 29543.0, + 29487.0, + 29641.0, + 28875.0, + 28306.0, + 28273.0, + 27776.0, + 27968.0, + 27986.0, + 27902.0, + 28011.0, + 28045.0, + 28006.0, + 28229.0, + 27937.0, + 28146.0, + 28092.0, + 28157.0, + 28235.0, + 28332.0, + 28444.0, + 28374.0, + 28395.0, + 28288.0, + 28138.0, + 27718.0, + 27643.0, + 27506.0, + 27523.0, + 27579.0, + 27807.0, + 27740.0, + 27591.0, + 27565.0, + 27709.0, + 27704.0, + 27720.0, + 27701.0, + 27635.0, + 27850.0, + 27750.0, + 27674.0, + 27860.0, + 27869.0, + 27709.0, + 27763.0, + 27798.0, + 27651.0, + 27662.0, + 27741.0, + 27672.0, + 27951.0, + 28023.0, + 28041.0, + 27944.0, + 27875.0, + 28742.0, + 29138.0, + 29004.0, + 29071.0, + 29247.0, + 29214.0, + 29308.0, + 29436.0, + 29237.0, + 29406.0, + 29440.0, + 29334.0, + 27718.0, + 27718.0, + 27647.0, + 27668.0, + 27678.0, + 27663.0, + 27660.0, + 27956.0, + 27990.0, + 28963.0, + 29268.0, + 29049.0, + 29080.0, + 28076.0, + 28585.0, + 28585.0, + 28497.0, + 28331.0, + 28632.0, + 28356.0, + 28312.0, + 28138.0, + 28347.0, + 28178.0, + 28105.0, + 28227.0, + 28272.0, + 28437.0, + 28476.0, + 28221.0, + 28223.0, + 28447.0, + 28465.0, + 28246.0, + 28367.0, + 28336.0, + 28125.0, + 28304.0, + 28309.0, + 28268.0, + 28190.0, + 28370.0, + 27909.0, + 27989.0, + 27664.0, + 27527.0, + 27745.0, + 27666.0, + 27751.0, + 27816.0, + 27854.0, + 27895.0, + 27642.0, + 27334.0, + 27381.0, + 27026.0, + 27114.0, + 27209.0, + 27141.0, + 27012.0, + 26810.0, + 26235.0, + 25957.0, + 26317.0, + 26155.0, + 26117.0, + 25984.0, + 26725.0, + 26750.0, + 26040.0, + 26007.0, + 25305.0, + 24576.0, + 24286.0, + 24034.0, + 23681.0, + 22947.0, + 22676.0, + 22646.0, + 22310.0, + 22526.0, + 22270.0, + 22162.0, + 21584.0, + 20091.0, + 21217.0, + 21811.0, + 21855.0, + 21361.0, + 21037.0, + 21473.0, + 21784.0, + 21455.0, + 21325.0, + 20624.0, + 21232.0, + 21211.0, + 20512.0, + 20264.0, + 19795.0, + 19254.0, + 20227.0, + 20638.0, + 20581.0, + 20275.0, + 20686.0, + 21241.0, + 21582.0, + 21426.0, + 21230.0, + 21033.0, + 20938.0, + 20410.0, + 20261.0, + 20111.0, + 19988.0, + 19890.0, + 19765.0, + 19552.0, + 19331.0, + 19796.0, + 19339.0, + 19760.0, + 20052.0, + 19910.0, + 19987.0, + 19811.0, + 19733.0, + 19589.0, + 19525.0, + 19566.0, + 19466.0, + 19442.0, + 19480.0, + 19445.0, + 18364.0, + 18275.0, + 18336.0, + 18292.0, + 18039.0, + 17710.0, + 17188.0, + 17614.0, + 18068.0, + 17558.0, + 17419.0, + 17264.0, + 17431.0, + 18098.0, + 18714.0, + 18280.0, + 18856.0, + 18523.0, + 19162.0, + 19450.0, + 19608.0, + 18851.0 + ], + "type": "scatter", + "xaxis": "x", + "yaxis": "y" + }, + { + "line": { + "color": "green", + "width": 1 + }, + "mode": "lines", + "name": "Close up turn", + "x": [ + "2022-12-20 00:00:00", + "2022-12-20 02:00:00", + "2022-12-20 04:00:00", + "2022-12-20 06:00:00", + "2022-12-20 08:00:00", + "2022-12-20 10:00:00", + "2022-12-20 12:00:00", + "2022-12-20 14:00:00", + "2022-12-20 16:00:00", + "2022-12-20 18:00:00", + "2022-12-20 20:00:00", + "2022-12-20 22:00:00", + "2022-12-21 00:00:00", + "2022-12-21 02:00:00", + "2022-12-21 04:00:00", + "2022-12-21 06:00:00", + "2022-12-21 08:00:00", + "2022-12-21 10:00:00", + "2022-12-21 12:00:00", + "2022-12-21 14:00:00", + "2022-12-21 16:00:00", + "2022-12-21 18:00:00", + "2022-12-21 20:00:00", + "2022-12-21 22:00:00", + "2022-12-22 00:00:00", + "2022-12-22 02:00:00", + "2022-12-22 04:00:00", + "2022-12-22 06:00:00", + "2022-12-22 08:00:00", + "2022-12-22 10:00:00", + "2022-12-22 12:00:00", + "2022-12-22 14:00:00", + "2022-12-22 16:00:00", + "2022-12-22 18:00:00", + "2022-12-22 20:00:00", + "2022-12-22 22:00:00", + "2022-12-23 00:00:00", + "2022-12-23 02:00:00", + "2022-12-23 04:00:00", + "2022-12-23 06:00:00", + "2022-12-23 08:00:00", + "2022-12-23 10:00:00", + "2022-12-23 12:00:00", + "2022-12-23 14:00:00", + "2022-12-23 16:00:00", + "2022-12-23 18:00:00", + "2022-12-23 20:00:00", + "2022-12-23 22:00:00", + "2022-12-24 00:00:00", + "2022-12-24 02:00:00", + "2022-12-24 04:00:00", + "2022-12-24 06:00:00", + "2022-12-24 08:00:00", + "2022-12-24 10:00:00", + "2022-12-24 12:00:00", + "2022-12-24 14:00:00", + "2022-12-24 16:00:00", + "2022-12-24 18:00:00", + "2022-12-24 20:00:00", + "2022-12-24 22:00:00", + "2022-12-25 00:00:00", + "2022-12-25 02:00:00", + "2022-12-25 04:00:00", + "2022-12-25 06:00:00", + "2022-12-25 08:00:00", + "2022-12-25 10:00:00", + "2022-12-25 12:00:00", + "2022-12-25 14:00:00", + "2022-12-25 16:00:00", + "2022-12-25 18:00:00", + "2022-12-25 20:00:00", + "2022-12-25 22:00:00", + "2022-12-26 00:00:00", + "2022-12-26 02:00:00", + "2022-12-26 04:00:00", + "2022-12-26 06:00:00", + "2022-12-26 08:00:00", + "2022-12-26 10:00:00", + "2022-12-26 12:00:00", + "2022-12-26 14:00:00", + "2022-12-26 16:00:00", + "2022-12-26 18:00:00", + "2022-12-26 20:00:00", + "2022-12-26 22:00:00", + "2022-12-27 00:00:00", + "2022-12-27 02:00:00", + "2022-12-27 04:00:00", + "2022-12-27 06:00:00", + "2022-12-27 08:00:00", + "2022-12-27 10:00:00", + "2022-12-27 12:00:00", + "2022-12-27 14:00:00", + "2022-12-27 16:00:00", + "2022-12-27 18:00:00", + "2022-12-27 20:00:00", + "2022-12-27 22:00:00", + "2022-12-28 00:00:00", + "2022-12-28 02:00:00", + "2022-12-28 04:00:00", + "2022-12-28 06:00:00", + "2022-12-28 08:00:00", + "2022-12-28 10:00:00", + "2022-12-28 12:00:00", + "2022-12-28 14:00:00", + "2022-12-28 16:00:00", + "2022-12-28 18:00:00", + "2022-12-28 20:00:00", + "2022-12-28 22:00:00", + "2022-12-29 00:00:00", + "2022-12-29 02:00:00", + "2022-12-29 04:00:00", + "2022-12-29 06:00:00", + "2022-12-29 08:00:00", + "2022-12-29 10:00:00", + "2022-12-29 12:00:00", + "2022-12-29 14:00:00", + "2022-12-29 16:00:00", + "2022-12-29 18:00:00", + "2022-12-29 20:00:00", + "2022-12-29 22:00:00", + "2022-12-30 00:00:00", + "2022-12-30 02:00:00", + "2022-12-30 04:00:00", + "2022-12-30 06:00:00", + "2022-12-30 08:00:00", + "2022-12-30 10:00:00", + "2022-12-30 12:00:00", + "2022-12-30 14:00:00", + "2022-12-30 16:00:00", + "2022-12-30 18:00:00", + "2022-12-30 20:00:00", + "2022-12-30 22:00:00", + "2022-12-31 00:00:00", + "2022-12-31 02:00:00", + "2022-12-31 04:00:00", + "2022-12-31 06:00:00", + "2022-12-31 08:00:00", + "2022-12-31 10:00:00", + "2022-12-31 12:00:00", + "2022-12-31 14:00:00", + "2022-12-31 16:00:00", + "2022-12-31 18:00:00", + "2022-12-31 20:00:00", + "2022-12-31 22:00:00", + "2023-01-01 00:00:00", + "2023-01-01 02:00:00", + "2023-01-01 04:00:00", + "2023-01-01 06:00:00", + "2023-01-01 08:00:00", + "2023-01-01 10:00:00", + "2023-01-01 12:00:00", + "2023-01-01 14:00:00", + "2023-01-01 16:00:00", + "2023-01-01 18:00:00", + "2023-01-01 20:00:00", + "2023-01-01 22:00:00", + "2023-01-02 00:00:00", + "2023-01-02 02:00:00", + "2023-01-02 04:00:00", + "2023-01-02 06:00:00", + "2023-01-02 08:00:00", + "2023-01-02 10:00:00", + "2023-01-02 12:00:00", + "2023-01-02 14:00:00", + "2023-01-02 16:00:00", + "2023-01-02 18:00:00", + "2023-01-02 20:00:00", + "2023-01-02 22:00:00", + "2023-01-03 00:00:00", + "2023-01-03 02:00:00", + "2023-01-03 04:00:00", + "2023-01-03 06:00:00", + "2023-01-03 08:00:00", + "2023-01-03 10:00:00", + "2023-01-03 12:00:00", + "2023-01-03 14:00:00", + "2023-01-03 16:00:00", + "2023-01-03 18:00:00", + "2023-01-03 20:00:00", + "2023-01-03 22:00:00", + "2023-01-04 00:00:00", + "2023-01-04 02:00:00", + "2023-01-04 04:00:00", + "2023-01-04 06:00:00", + "2023-01-04 08:00:00", + "2023-01-04 10:00:00", + "2023-01-04 12:00:00", + "2023-01-04 14:00:00", + "2023-01-04 16:00:00", + "2023-01-04 18:00:00", + "2023-01-04 20:00:00", + "2023-01-04 22:00:00", + "2023-01-05 00:00:00", + "2023-01-05 02:00:00", + "2023-01-05 04:00:00", + "2023-01-05 06:00:00", + "2023-01-05 08:00:00", + "2023-01-05 10:00:00", + "2023-01-05 12:00:00", + "2023-01-05 14:00:00", + "2023-01-05 16:00:00", + "2023-01-05 18:00:00", + "2023-01-05 20:00:00", + "2023-01-05 22:00:00", + "2023-01-06 00:00:00", + "2023-01-06 02:00:00", + "2023-01-06 04:00:00", + "2023-01-06 06:00:00", + "2023-01-06 08:00:00", + "2023-01-06 10:00:00", + "2023-01-06 12:00:00", + "2023-01-06 14:00:00", + "2023-01-06 16:00:00", + "2023-01-06 18:00:00", + "2023-01-06 20:00:00", + "2023-01-06 22:00:00", + "2023-01-07 00:00:00", + "2023-01-07 02:00:00", + "2023-01-07 04:00:00", + "2023-01-07 06:00:00", + "2023-01-07 08:00:00", + "2023-01-07 10:00:00", + "2023-01-07 12:00:00", + "2023-01-07 14:00:00", + "2023-01-07 16:00:00", + "2023-01-07 18:00:00", + "2023-01-07 20:00:00", + "2023-01-07 22:00:00", + "2023-01-08 00:00:00", + "2023-01-08 02:00:00", + "2023-01-08 04:00:00", + "2023-01-08 06:00:00", + "2023-01-08 08:00:00", + "2023-01-08 10:00:00", + "2023-01-08 12:00:00", + "2023-01-08 14:00:00", + "2023-01-08 16:00:00", + "2023-01-08 18:00:00", + "2023-01-08 20:00:00", + "2023-01-08 22:00:00", + "2023-01-09 00:00:00", + "2023-01-09 02:00:00", + "2023-01-09 04:00:00", + "2023-01-09 06:00:00", + "2023-01-09 08:00:00", + "2023-01-09 10:00:00", + "2023-01-09 12:00:00", + "2023-01-09 14:00:00", + "2023-01-09 16:00:00", + "2023-01-09 18:00:00", + "2023-01-09 20:00:00", + "2023-01-09 22:00:00", + "2023-01-10 00:00:00", + "2023-01-10 02:00:00", + "2023-01-10 04:00:00", + "2023-01-10 06:00:00", + "2023-01-10 08:00:00", + "2023-01-10 10:00:00", + "2023-01-10 12:00:00", + "2023-01-10 14:00:00", + "2023-01-10 16:00:00", + "2023-01-10 18:00:00", + "2023-01-10 20:00:00", + "2023-01-10 22:00:00", + "2023-01-11 00:00:00", + "2023-01-11 02:00:00", + "2023-01-11 04:00:00", + "2023-01-11 06:00:00", + "2023-01-11 08:00:00", + "2023-01-11 10:00:00", + "2023-01-11 12:00:00", + "2023-01-11 14:00:00", + "2023-01-11 16:00:00", + "2023-01-11 18:00:00", + "2023-01-11 20:00:00", + "2023-01-11 22:00:00", + "2023-01-12 00:00:00", + "2023-01-12 02:00:00", + "2023-01-12 04:00:00", + "2023-01-12 06:00:00", + "2023-01-12 08:00:00", + "2023-01-12 10:00:00", + "2023-01-12 12:00:00", + "2023-01-12 14:00:00", + "2023-01-12 16:00:00", + "2023-01-12 18:00:00", + "2023-01-12 20:00:00", + "2023-01-12 22:00:00", + "2023-01-13 00:00:00", + "2023-01-13 02:00:00", + "2023-01-13 04:00:00", + "2023-01-13 06:00:00", + "2023-01-13 08:00:00", + "2023-01-13 10:00:00", + "2023-01-13 12:00:00", + "2023-01-13 14:00:00", + "2023-01-13 16:00:00", + "2023-01-13 18:00:00", + "2023-01-13 20:00:00", + "2023-01-13 22:00:00", + "2023-01-14 00:00:00", + "2023-01-14 02:00:00", + "2023-01-14 04:00:00", + "2023-01-14 06:00:00", + "2023-01-14 08:00:00", + "2023-01-14 10:00:00", + "2023-01-14 12:00:00", + "2023-01-14 14:00:00", + "2023-01-14 16:00:00", + "2023-01-14 18:00:00", + "2023-01-14 20:00:00", + "2023-01-14 22:00:00", + "2023-01-15 00:00:00", + "2023-01-15 02:00:00", + "2023-01-15 04:00:00", + "2023-01-15 06:00:00", + "2023-01-15 08:00:00", + "2023-01-15 10:00:00", + "2023-01-15 12:00:00", + "2023-01-15 14:00:00", + "2023-01-15 16:00:00", + "2023-01-15 18:00:00", + "2023-01-15 20:00:00", + "2023-01-15 22:00:00", + "2023-01-16 00:00:00", + "2023-01-16 02:00:00", + "2023-01-16 04:00:00", + "2023-01-16 06:00:00", + "2023-01-16 08:00:00", + "2023-01-16 10:00:00", + "2023-01-16 12:00:00", + "2023-01-16 14:00:00", + "2023-01-16 16:00:00", + "2023-01-16 18:00:00", + "2023-01-16 20:00:00", + "2023-01-16 22:00:00", + "2023-01-17 00:00:00", + "2023-01-17 02:00:00", + "2023-01-17 04:00:00", + "2023-01-17 06:00:00", + "2023-01-17 08:00:00", + "2023-01-17 10:00:00", + "2023-01-17 12:00:00", + "2023-01-17 14:00:00", + "2023-01-17 16:00:00", + "2023-01-17 18:00:00", + "2023-01-17 20:00:00", + "2023-01-17 22:00:00", + "2023-01-18 00:00:00", + "2023-01-18 02:00:00", + "2023-01-18 04:00:00", + "2023-01-18 06:00:00", + "2023-01-18 08:00:00", + "2023-01-18 10:00:00", + "2023-01-18 12:00:00", + "2023-01-18 14:00:00", + "2023-01-18 16:00:00", + "2023-01-18 18:00:00", + "2023-01-18 20:00:00", + "2023-01-18 22:00:00", + "2023-01-19 00:00:00", + "2023-01-19 02:00:00", + "2023-01-19 04:00:00", + "2023-01-19 06:00:00", + "2023-01-19 08:00:00", + "2023-01-19 10:00:00", + "2023-01-19 12:00:00", + "2023-01-19 14:00:00", + "2023-01-19 16:00:00", + "2023-01-19 18:00:00", + "2023-01-19 20:00:00", + "2023-01-19 22:00:00", + "2023-01-20 00:00:00", + "2023-01-20 02:00:00", + "2023-01-20 04:00:00", + "2023-01-20 06:00:00", + "2023-01-20 08:00:00", + "2023-01-20 10:00:00", + "2023-01-20 12:00:00", + "2023-01-20 14:00:00", + "2023-01-20 16:00:00", + "2023-01-20 18:00:00", + "2023-01-20 20:00:00", + "2023-01-20 22:00:00", + "2023-01-21 00:00:00", + "2023-01-21 02:00:00", + "2023-01-21 04:00:00", + "2023-01-21 06:00:00", + "2023-01-21 08:00:00", + "2023-01-21 10:00:00", + "2023-01-21 12:00:00", + "2023-01-21 14:00:00", + "2023-01-21 16:00:00", + "2023-01-21 18:00:00", + "2023-01-21 20:00:00", + "2023-01-21 22:00:00", + "2023-01-22 00:00:00", + "2023-01-22 02:00:00", + "2023-01-22 04:00:00", + "2023-01-22 06:00:00", + "2023-01-22 08:00:00", + "2023-01-22 10:00:00", + "2023-01-22 12:00:00", + "2023-01-22 14:00:00", + "2023-01-22 16:00:00", + "2023-01-22 18:00:00", + "2023-01-22 20:00:00", + "2023-01-22 22:00:00", + "2023-01-23 00:00:00", + "2023-01-23 02:00:00", + "2023-01-23 04:00:00", + "2023-01-23 06:00:00", + "2023-01-23 08:00:00", + "2023-01-23 10:00:00", + "2023-01-23 12:00:00", + "2023-01-23 14:00:00", + "2023-01-23 16:00:00", + "2023-01-23 18:00:00", + "2023-01-23 20:00:00", + "2023-01-23 22:00:00", + "2023-01-24 00:00:00", + "2023-01-24 02:00:00", + "2023-01-24 04:00:00", + "2023-01-24 06:00:00", + "2023-01-24 08:00:00", + "2023-01-24 10:00:00", + "2023-01-24 12:00:00", + "2023-01-24 14:00:00", + "2023-01-24 16:00:00", + "2023-01-24 18:00:00", + "2023-01-24 20:00:00", + "2023-01-24 22:00:00", + "2023-01-25 00:00:00", + "2023-01-25 02:00:00", + "2023-01-25 04:00:00", + "2023-01-25 06:00:00", + "2023-01-25 08:00:00", + "2023-01-25 10:00:00", + "2023-01-25 12:00:00", + "2023-01-25 14:00:00", + "2023-01-25 16:00:00", + "2023-01-25 18:00:00", + "2023-01-25 20:00:00", + "2023-01-25 22:00:00", + "2023-01-26 00:00:00", + "2023-01-26 02:00:00", + "2023-01-26 04:00:00", + "2023-01-26 06:00:00", + "2023-01-26 08:00:00", + "2023-01-26 10:00:00", + "2023-01-26 12:00:00", + "2023-01-26 14:00:00", + "2023-01-26 16:00:00", + "2023-01-26 18:00:00", + "2023-01-26 20:00:00", + "2023-01-26 22:00:00", + "2023-01-27 00:00:00", + "2023-01-27 02:00:00", + "2023-01-27 04:00:00", + "2023-01-27 06:00:00", + "2023-01-27 08:00:00", + "2023-01-27 10:00:00", + "2023-01-27 12:00:00", + "2023-01-27 14:00:00", + "2023-01-27 16:00:00", + "2023-01-27 18:00:00", + "2023-01-27 20:00:00", + "2023-01-27 22:00:00", + "2023-01-28 00:00:00", + "2023-01-28 02:00:00", + "2023-01-28 04:00:00", + "2023-01-28 06:00:00", + "2023-01-28 08:00:00", + "2023-01-28 10:00:00", + "2023-01-28 12:00:00", + "2023-01-28 14:00:00", + "2023-01-28 16:00:00", + "2023-01-28 18:00:00", + "2023-01-28 20:00:00", + "2023-01-28 22:00:00", + "2023-01-29 00:00:00", + "2023-01-29 02:00:00", + "2023-01-29 04:00:00", + "2023-01-29 06:00:00", + "2023-01-29 08:00:00", + "2023-01-29 10:00:00", + "2023-01-29 12:00:00", + "2023-01-29 14:00:00", + "2023-01-29 16:00:00", + "2023-01-29 18:00:00", + "2023-01-29 20:00:00", + "2023-01-29 22:00:00", + "2023-01-30 00:00:00", + "2023-01-30 02:00:00", + "2023-01-30 04:00:00", + "2023-01-30 06:00:00", + "2023-01-30 08:00:00", + "2023-01-30 10:00:00", + "2023-01-30 12:00:00", + "2023-01-30 14:00:00", + "2023-01-30 16:00:00", + "2023-01-30 18:00:00", + "2023-01-30 20:00:00", + "2023-01-30 22:00:00", + "2023-01-31 00:00:00", + "2023-01-31 02:00:00", + "2023-01-31 04:00:00", + "2023-01-31 06:00:00", + "2023-01-31 08:00:00", + "2023-01-31 10:00:00", + "2023-01-31 12:00:00", + "2023-01-31 14:00:00", + "2023-01-31 16:00:00", + "2023-01-31 18:00:00", + "2023-01-31 20:00:00", + "2023-01-31 22:00:00", + "2023-02-01 00:00:00", + "2023-02-01 02:00:00", + "2023-02-01 04:00:00", + "2023-02-01 06:00:00", + "2023-02-01 08:00:00", + "2023-02-01 10:00:00", + "2023-02-01 12:00:00", + "2023-02-01 14:00:00", + "2023-02-01 16:00:00", + "2023-02-01 18:00:00", + "2023-02-01 20:00:00", + "2023-02-01 22:00:00", + "2023-02-02 00:00:00", + "2023-02-02 02:00:00", + "2023-02-02 04:00:00", + "2023-02-02 06:00:00", + "2023-02-02 08:00:00", + "2023-02-02 10:00:00", + "2023-02-02 12:00:00", + "2023-02-02 14:00:00", + "2023-02-02 16:00:00", + "2023-02-02 18:00:00", + "2023-02-02 20:00:00", + "2023-02-02 22:00:00", + "2023-02-03 00:00:00", + "2023-02-03 02:00:00", + "2023-02-03 04:00:00", + "2023-02-03 06:00:00", + "2023-02-03 08:00:00", + "2023-02-03 10:00:00", + "2023-02-03 12:00:00", + "2023-02-03 14:00:00", + "2023-02-03 16:00:00", + "2023-02-03 18:00:00", + "2023-02-03 20:00:00", + "2023-02-03 22:00:00", + "2023-02-04 00:00:00", + "2023-02-04 02:00:00", + "2023-02-04 04:00:00", + "2023-02-04 06:00:00", + "2023-02-04 08:00:00", + "2023-02-04 10:00:00", + "2023-02-04 12:00:00", + "2023-02-04 14:00:00", + "2023-02-04 16:00:00", + "2023-02-04 18:00:00", + "2023-02-04 20:00:00", + "2023-02-04 22:00:00", + "2023-02-05 00:00:00", + "2023-02-05 02:00:00", + "2023-02-05 04:00:00", + "2023-02-05 06:00:00", + "2023-02-05 08:00:00", + "2023-02-05 10:00:00", + "2023-02-05 12:00:00", + "2023-02-05 14:00:00", + "2023-02-05 16:00:00", + "2023-02-05 18:00:00", + "2023-02-05 20:00:00", + "2023-02-05 22:00:00", + "2023-02-06 00:00:00", + "2023-02-06 02:00:00", + "2023-02-06 04:00:00", + "2023-02-06 06:00:00", + "2023-02-06 08:00:00", + "2023-02-06 10:00:00", + "2023-02-06 12:00:00", + "2023-02-06 14:00:00", + "2023-02-06 16:00:00", + "2023-02-06 18:00:00", + "2023-02-06 20:00:00", + "2023-02-06 22:00:00", + "2023-02-07 00:00:00", + "2023-02-07 02:00:00", + "2023-02-07 04:00:00", + "2023-02-07 06:00:00", + "2023-02-07 08:00:00", + "2023-02-07 10:00:00", + "2023-02-07 12:00:00", + "2023-02-07 14:00:00", + "2023-02-07 16:00:00", + "2023-02-07 18:00:00", + "2023-02-07 20:00:00", + "2023-02-07 22:00:00", + "2023-02-08 00:00:00", + "2023-02-08 02:00:00", + "2023-02-08 04:00:00", + "2023-02-08 06:00:00", + "2023-02-08 08:00:00", + "2023-02-08 10:00:00", + "2023-02-08 12:00:00", + "2023-02-08 14:00:00", + "2023-02-08 16:00:00", + "2023-02-08 18:00:00", + "2023-02-08 20:00:00", + "2023-02-08 22:00:00", + "2023-02-09 00:00:00", + "2023-02-09 02:00:00", + "2023-02-09 04:00:00", + "2023-02-09 06:00:00", + "2023-02-09 08:00:00", + "2023-02-09 10:00:00", + "2023-02-09 12:00:00", + "2023-02-09 14:00:00", + "2023-02-09 16:00:00", + "2023-02-09 18:00:00", + "2023-02-09 20:00:00", + "2023-02-09 22:00:00", + "2023-02-10 00:00:00", + "2023-02-10 02:00:00", + "2023-02-10 04:00:00", + "2023-02-10 06:00:00", + "2023-02-10 08:00:00", + "2023-02-10 10:00:00", + "2023-02-10 12:00:00", + "2023-02-10 14:00:00", + "2023-02-10 16:00:00", + "2023-02-10 18:00:00", + "2023-02-10 20:00:00", + "2023-02-10 22:00:00", + "2023-02-11 00:00:00", + "2023-02-11 02:00:00", + "2023-02-11 04:00:00", + "2023-02-11 06:00:00", + "2023-02-11 08:00:00", + "2023-02-11 10:00:00", + "2023-02-11 12:00:00", + "2023-02-11 14:00:00", + "2023-02-11 16:00:00", + "2023-02-11 18:00:00", + "2023-02-11 20:00:00", + "2023-02-11 22:00:00", + "2023-02-12 00:00:00", + "2023-02-12 02:00:00", + "2023-02-12 04:00:00", + "2023-02-12 06:00:00", + "2023-02-12 08:00:00", + "2023-02-12 10:00:00", + "2023-02-12 12:00:00", + "2023-02-12 14:00:00", + "2023-02-12 16:00:00", + "2023-02-12 18:00:00", + "2023-02-12 20:00:00", + "2023-02-12 22:00:00", + "2023-02-13 00:00:00", + "2023-02-13 02:00:00", + "2023-02-13 04:00:00", + "2023-02-13 06:00:00", + "2023-02-13 08:00:00", + "2023-02-13 10:00:00", + "2023-02-13 12:00:00", + "2023-02-13 14:00:00", + "2023-02-13 16:00:00", + "2023-02-13 18:00:00", + "2023-02-13 20:00:00", + "2023-02-13 22:00:00", + "2023-02-14 00:00:00", + "2023-02-14 02:00:00", + "2023-02-14 04:00:00", + "2023-02-14 06:00:00", + "2023-02-14 08:00:00", + "2023-02-14 10:00:00", + "2023-02-14 12:00:00", + "2023-02-14 14:00:00", + "2023-02-14 16:00:00", + "2023-02-14 18:00:00", + "2023-02-14 20:00:00", + "2023-02-14 22:00:00", + "2023-02-15 00:00:00", + "2023-02-15 02:00:00", + "2023-02-15 04:00:00", + "2023-02-15 06:00:00", + "2023-02-15 08:00:00", + "2023-02-15 10:00:00", + "2023-02-15 12:00:00", + "2023-02-15 14:00:00", + "2023-02-15 16:00:00", + "2023-02-15 18:00:00", + "2023-02-15 20:00:00", + "2023-02-15 22:00:00", + "2023-02-16 00:00:00", + "2023-02-16 02:00:00", + "2023-02-16 04:00:00", + "2023-02-16 06:00:00", + "2023-02-16 08:00:00", + "2023-02-16 10:00:00", + "2023-02-16 12:00:00", + "2023-02-16 14:00:00", + "2023-02-16 16:00:00", + "2023-02-16 18:00:00", + "2023-02-16 20:00:00", + "2023-02-16 22:00:00", + "2023-02-17 00:00:00", + "2023-02-17 02:00:00", + "2023-02-17 04:00:00", + "2023-02-17 06:00:00", + "2023-02-17 08:00:00", + "2023-02-17 10:00:00", + "2023-02-17 12:00:00", + "2023-02-17 14:00:00", + "2023-02-17 16:00:00", + "2023-02-17 18:00:00", + "2023-02-17 20:00:00", + "2023-02-17 22:00:00", + "2023-02-18 00:00:00", + "2023-02-18 02:00:00", + "2023-02-18 04:00:00", + "2023-02-18 06:00:00", + "2023-02-18 08:00:00", + "2023-02-18 10:00:00", + "2023-02-18 12:00:00", + "2023-02-18 14:00:00", + "2023-02-18 16:00:00", + "2023-02-18 18:00:00", + "2023-02-18 20:00:00", + "2023-02-18 22:00:00", + "2023-02-19 00:00:00", + "2023-02-19 02:00:00", + "2023-02-19 04:00:00", + "2023-02-19 06:00:00", + "2023-02-19 08:00:00", + "2023-02-19 10:00:00", + "2023-02-19 12:00:00", + "2023-02-19 14:00:00", + "2023-02-19 16:00:00", + "2023-02-19 18:00:00", + "2023-02-19 20:00:00", + "2023-02-19 22:00:00", + "2023-02-20 00:00:00", + "2023-02-20 02:00:00", + "2023-02-20 04:00:00", + "2023-02-20 06:00:00", + "2023-02-20 08:00:00", + "2023-02-20 10:00:00", + "2023-02-20 12:00:00", + "2023-02-20 14:00:00", + "2023-02-20 16:00:00", + "2023-02-20 18:00:00", + "2023-02-20 20:00:00", + "2023-02-20 22:00:00", + "2023-02-21 00:00:00", + "2023-02-21 02:00:00", + "2023-02-21 04:00:00", + "2023-02-21 06:00:00", + "2023-02-21 08:00:00", + "2023-02-21 10:00:00", + "2023-02-21 12:00:00", + "2023-02-21 14:00:00", + "2023-02-21 16:00:00", + "2023-02-21 18:00:00", + "2023-02-21 20:00:00", + "2023-02-21 22:00:00", + "2023-02-22 00:00:00", + "2023-02-22 02:00:00", + "2023-02-22 04:00:00", + "2023-02-22 06:00:00", + "2023-02-22 08:00:00", + "2023-02-22 10:00:00", + "2023-02-22 12:00:00", + "2023-02-22 14:00:00", + "2023-02-22 16:00:00", + "2023-02-22 18:00:00", + "2023-02-22 20:00:00", + "2023-02-22 22:00:00", + "2023-02-23 00:00:00", + "2023-02-23 02:00:00", + "2023-02-23 04:00:00", + "2023-02-23 06:00:00", + "2023-02-23 08:00:00", + "2023-02-23 10:00:00", + "2023-02-23 12:00:00", + "2023-02-23 14:00:00", + "2023-02-23 16:00:00", + "2023-02-23 18:00:00", + "2023-02-23 20:00:00", + "2023-02-23 22:00:00", + "2023-02-24 00:00:00", + "2023-02-24 02:00:00", + "2023-02-24 04:00:00", + "2023-02-24 06:00:00", + "2023-02-24 08:00:00", + "2023-02-24 10:00:00", + "2023-02-24 12:00:00", + "2023-02-24 14:00:00", + "2023-02-24 16:00:00", + "2023-02-24 18:00:00", + "2023-02-24 20:00:00", + "2023-02-24 22:00:00", + "2023-02-25 00:00:00", + "2023-02-25 02:00:00", + "2023-02-25 04:00:00", + "2023-02-25 06:00:00", + "2023-02-25 08:00:00", + "2023-02-25 10:00:00", + "2023-02-25 12:00:00", + "2023-02-25 14:00:00", + "2023-02-25 16:00:00", + "2023-02-25 18:00:00", + "2023-02-25 20:00:00", + "2023-02-25 22:00:00", + "2023-02-26 00:00:00", + "2023-02-26 02:00:00", + "2023-02-26 04:00:00", + "2023-02-26 06:00:00", + "2023-02-26 08:00:00", + "2023-02-26 10:00:00", + "2023-02-26 12:00:00", + "2023-02-26 14:00:00", + "2023-02-26 16:00:00", + "2023-02-26 18:00:00", + "2023-02-26 20:00:00", + "2023-02-26 22:00:00", + "2023-02-27 00:00:00", + "2023-02-27 02:00:00", + "2023-02-27 04:00:00", + "2023-02-27 06:00:00", + "2023-02-27 08:00:00", + "2023-02-27 10:00:00", + "2023-02-27 12:00:00", + "2023-02-27 14:00:00", + "2023-02-27 16:00:00", + "2023-02-27 18:00:00", + "2023-02-27 20:00:00", + "2023-02-27 22:00:00", + "2023-02-28 00:00:00", + "2023-02-28 02:00:00", + "2023-02-28 04:00:00", + "2023-02-28 06:00:00", + "2023-02-28 08:00:00", + "2023-02-28 10:00:00", + "2023-02-28 12:00:00", + "2023-02-28 14:00:00", + "2023-02-28 16:00:00", + "2023-02-28 18:00:00", + "2023-02-28 20:00:00", + "2023-02-28 22:00:00", + "2023-03-01 00:00:00", + "2023-03-01 02:00:00", + "2023-03-01 04:00:00", + "2023-03-01 06:00:00", + "2023-03-01 08:00:00", + "2023-03-01 10:00:00", + "2023-03-01 12:00:00", + "2023-03-01 14:00:00", + "2023-03-01 16:00:00", + "2023-03-01 18:00:00", + "2023-03-01 20:00:00", + "2023-03-01 22:00:00", + "2023-03-02 00:00:00", + "2023-03-02 02:00:00", + "2023-03-02 04:00:00", + "2023-03-02 06:00:00", + "2023-03-02 08:00:00", + "2023-03-02 10:00:00", + "2023-03-02 12:00:00", + "2023-03-02 14:00:00", + "2023-03-02 16:00:00", + "2023-03-02 18:00:00", + "2023-03-02 20:00:00", + "2023-03-02 22:00:00", + "2023-03-03 00:00:00", + "2023-03-03 02:00:00", + "2023-03-03 04:00:00", + "2023-03-03 06:00:00", + "2023-03-03 08:00:00", + "2023-03-03 10:00:00", + "2023-03-03 12:00:00", + "2023-03-03 14:00:00", + "2023-03-03 16:00:00", + "2023-03-03 18:00:00", + "2023-03-03 20:00:00", + "2023-03-03 22:00:00", + "2023-03-04 00:00:00", + "2023-03-04 02:00:00", + "2023-03-04 04:00:00", + "2023-03-04 06:00:00", + "2023-03-04 08:00:00", + "2023-03-04 10:00:00", + "2023-03-04 12:00:00", + "2023-03-04 14:00:00", + "2023-03-04 16:00:00", + "2023-03-04 18:00:00", + "2023-03-04 20:00:00", + "2023-03-04 22:00:00", + "2023-03-05 00:00:00", + "2023-03-05 02:00:00", + "2023-03-05 04:00:00", + "2023-03-05 06:00:00", + "2023-03-05 08:00:00", + "2023-03-05 10:00:00", + "2023-03-05 12:00:00", + "2023-03-05 14:00:00", + "2023-03-05 16:00:00", + "2023-03-05 18:00:00", + "2023-03-05 20:00:00", + "2023-03-05 22:00:00", + "2023-03-06 00:00:00", + "2023-03-06 02:00:00", + "2023-03-06 04:00:00", + "2023-03-06 06:00:00", + "2023-03-06 08:00:00", + "2023-03-06 10:00:00", + "2023-03-06 12:00:00", + "2023-03-06 14:00:00", + "2023-03-06 16:00:00", + "2023-03-06 18:00:00", + "2023-03-06 20:00:00", + "2023-03-06 22:00:00", + "2023-03-07 00:00:00", + "2023-03-07 02:00:00", + "2023-03-07 04:00:00", + "2023-03-07 06:00:00", + "2023-03-07 08:00:00", + "2023-03-07 10:00:00", + "2023-03-07 12:00:00", + "2023-03-07 14:00:00", + "2023-03-07 16:00:00", + "2023-03-07 18:00:00", + "2023-03-07 20:00:00", + "2023-03-07 22:00:00", + "2023-03-08 00:00:00", + "2023-03-08 02:00:00", + "2023-03-08 04:00:00", + "2023-03-08 06:00:00", + "2023-03-08 08:00:00", + "2023-03-08 10:00:00", + "2023-03-08 12:00:00", + "2023-03-08 14:00:00", + "2023-03-08 16:00:00", + "2023-03-08 18:00:00", + "2023-03-08 20:00:00", + "2023-03-08 22:00:00", + "2023-03-09 00:00:00", + "2023-03-09 02:00:00", + "2023-03-09 04:00:00", + "2023-03-09 06:00:00", + "2023-03-09 08:00:00", + "2023-03-09 10:00:00", + "2023-03-09 12:00:00", + "2023-03-09 14:00:00", + "2023-03-09 16:00:00", + "2023-03-09 18:00:00", + "2023-03-09 20:00:00", + "2023-03-09 22:00:00", + "2023-03-10 00:00:00", + "2023-03-10 02:00:00", + "2023-03-10 04:00:00", + "2023-03-10 06:00:00", + "2023-03-10 08:00:00", + "2023-03-10 10:00:00", + "2023-03-10 12:00:00", + "2023-03-10 14:00:00", + "2023-03-10 16:00:00", + "2023-03-10 18:00:00", + "2023-03-10 20:00:00", + "2023-03-10 22:00:00", + "2023-03-11 00:00:00", + "2023-03-11 02:00:00", + "2023-03-11 04:00:00", + "2023-03-11 06:00:00", + "2023-03-11 08:00:00", + "2023-03-11 10:00:00", + "2023-03-11 12:00:00", + "2023-03-11 14:00:00", + "2023-03-11 16:00:00", + "2023-03-11 18:00:00", + "2023-03-11 20:00:00", + "2023-03-11 22:00:00", + "2023-03-12 00:00:00", + "2023-03-12 02:00:00", + "2023-03-12 04:00:00", + "2023-03-12 06:00:00", + "2023-03-12 08:00:00", + "2023-03-12 10:00:00", + "2023-03-12 12:00:00", + "2023-03-12 14:00:00", + "2023-03-12 16:00:00", + "2023-03-12 18:00:00", + "2023-03-12 20:00:00", + "2023-03-12 22:00:00", + "2023-03-13 00:00:00", + "2023-03-13 02:00:00", + "2023-03-13 04:00:00", + "2023-03-13 06:00:00", + "2023-03-13 08:00:00", + "2023-03-13 10:00:00", + "2023-03-13 12:00:00", + "2023-03-13 14:00:00", + "2023-03-13 16:00:00", + "2023-03-13 18:00:00", + "2023-03-13 20:00:00", + "2023-03-13 22:00:00", + "2023-03-14 00:00:00", + "2023-03-14 02:00:00", + "2023-03-14 04:00:00", + "2023-03-14 06:00:00", + "2023-03-14 08:00:00", + "2023-03-14 10:00:00", + "2023-03-14 12:00:00", + "2023-03-14 14:00:00", + "2023-03-14 16:00:00", + "2023-03-14 18:00:00", + "2023-03-14 20:00:00", + "2023-03-14 22:00:00", + "2023-03-15 00:00:00", + "2023-03-15 02:00:00", + "2023-03-15 04:00:00", + "2023-03-15 06:00:00", + "2023-03-15 08:00:00", + "2023-03-15 10:00:00", + "2023-03-15 12:00:00", + "2023-03-15 14:00:00", + "2023-03-15 16:00:00", + "2023-03-15 18:00:00", + "2023-03-15 20:00:00", + "2023-03-15 22:00:00", + "2023-03-16 00:00:00", + "2023-03-16 02:00:00", + "2023-03-16 04:00:00", + "2023-03-16 06:00:00", + "2023-03-16 08:00:00", + "2023-03-16 10:00:00", + "2023-03-16 12:00:00", + "2023-03-16 14:00:00", + "2023-03-16 16:00:00", + "2023-03-16 18:00:00", + "2023-03-16 20:00:00", + "2023-03-16 22:00:00", + "2023-03-17 00:00:00", + "2023-03-17 02:00:00", + "2023-03-17 04:00:00", + "2023-03-17 06:00:00", + "2023-03-17 08:00:00", + "2023-03-17 10:00:00", + "2023-03-17 12:00:00", + "2023-03-17 14:00:00", + "2023-03-17 16:00:00", + "2023-03-17 18:00:00", + "2023-03-17 20:00:00", + "2023-03-17 22:00:00", + "2023-03-18 00:00:00", + "2023-03-18 02:00:00", + "2023-03-18 04:00:00", + "2023-03-18 06:00:00", + "2023-03-18 08:00:00", + "2023-03-18 10:00:00", + "2023-03-18 12:00:00", + "2023-03-18 14:00:00", + "2023-03-18 16:00:00", + "2023-03-18 18:00:00", + "2023-03-18 20:00:00", + "2023-03-18 22:00:00", + "2023-03-19 00:00:00", + "2023-03-19 02:00:00", + "2023-03-19 04:00:00", + "2023-03-19 06:00:00", + "2023-03-19 08:00:00", + "2023-03-19 10:00:00", + "2023-03-19 12:00:00", + "2023-03-19 14:00:00", + "2023-03-19 16:00:00", + "2023-03-19 18:00:00", + "2023-03-19 20:00:00", + "2023-03-19 22:00:00", + "2023-03-20 00:00:00", + "2023-03-20 02:00:00", + "2023-03-20 04:00:00", + "2023-03-20 06:00:00", + "2023-03-20 08:00:00", + "2023-03-20 10:00:00", + "2023-03-20 12:00:00", + "2023-03-20 14:00:00", + "2023-03-20 16:00:00", + "2023-03-20 18:00:00", + "2023-03-20 20:00:00", + "2023-03-20 22:00:00", + "2023-03-21 00:00:00", + "2023-03-21 02:00:00", + "2023-03-21 04:00:00", + "2023-03-21 06:00:00", + "2023-03-21 08:00:00", + "2023-03-21 10:00:00", + "2023-03-21 12:00:00", + "2023-03-21 14:00:00", + "2023-03-21 16:00:00", + "2023-03-21 18:00:00", + "2023-03-21 20:00:00", + "2023-03-21 22:00:00", + "2023-03-22 00:00:00", + "2023-03-22 02:00:00", + "2023-03-22 04:00:00", + "2023-03-22 06:00:00", + "2023-03-22 08:00:00", + "2023-03-22 10:00:00", + "2023-03-22 12:00:00", + "2023-03-22 14:00:00", + "2023-03-22 16:00:00", + "2023-03-22 18:00:00", + "2023-03-22 20:00:00", + "2023-03-22 22:00:00", + "2023-03-23 00:00:00", + "2023-03-23 02:00:00", + "2023-03-23 04:00:00", + "2023-03-23 06:00:00", + "2023-03-23 08:00:00", + "2023-03-23 10:00:00", + "2023-03-23 12:00:00", + "2023-03-23 14:00:00", + "2023-03-23 16:00:00", + "2023-03-23 18:00:00", + "2023-03-23 20:00:00", + "2023-03-23 22:00:00", + "2023-03-24 00:00:00", + "2023-03-24 02:00:00", + "2023-03-24 04:00:00", + "2023-03-24 06:00:00", + "2023-03-24 08:00:00", + "2023-03-24 10:00:00", + "2023-03-24 12:00:00", + "2023-03-24 14:00:00", + "2023-03-24 16:00:00", + "2023-03-24 18:00:00", + "2023-03-24 20:00:00", + "2023-03-24 22:00:00", + "2023-03-25 00:00:00", + "2023-03-25 02:00:00", + "2023-03-25 04:00:00", + "2023-03-25 06:00:00", + "2023-03-25 08:00:00", + "2023-03-25 10:00:00", + "2023-03-25 12:00:00", + "2023-03-25 14:00:00", + "2023-03-25 16:00:00", + "2023-03-25 18:00:00", + "2023-03-25 20:00:00", + "2023-03-25 22:00:00", + "2023-03-26 00:00:00", + "2023-03-26 02:00:00", + "2023-03-26 04:00:00", + "2023-03-26 06:00:00", + "2023-03-26 08:00:00", + "2023-03-26 10:00:00", + "2023-03-26 12:00:00", + "2023-03-26 14:00:00", + "2023-03-26 16:00:00", + "2023-03-26 18:00:00", + "2023-03-26 20:00:00", + "2023-03-26 22:00:00", + "2023-03-27 00:00:00", + "2023-03-27 02:00:00", + "2023-03-27 04:00:00", + "2023-03-27 06:00:00", + "2023-03-27 08:00:00", + "2023-03-27 10:00:00", + "2023-03-27 12:00:00", + "2023-03-27 14:00:00", + "2023-03-27 16:00:00", + "2023-03-27 18:00:00", + "2023-03-27 20:00:00", + "2023-03-27 22:00:00", + "2023-03-28 00:00:00", + "2023-03-28 02:00:00", + "2023-03-28 04:00:00", + "2023-03-28 06:00:00", + "2023-03-28 08:00:00", + "2023-03-28 10:00:00", + "2023-03-28 12:00:00", + "2023-03-28 14:00:00", + "2023-03-28 16:00:00", + "2023-03-28 18:00:00", + "2023-03-28 20:00:00", + "2023-03-28 22:00:00", + "2023-03-29 00:00:00", + "2023-03-29 02:00:00", + "2023-03-29 04:00:00", + "2023-03-29 06:00:00", + "2023-03-29 08:00:00", + "2023-03-29 10:00:00", + "2023-03-29 12:00:00", + "2023-03-29 14:00:00", + "2023-03-29 16:00:00", + "2023-03-29 18:00:00", + "2023-03-29 20:00:00", + "2023-03-29 22:00:00", + "2023-03-30 00:00:00", + "2023-03-30 02:00:00", + "2023-03-30 04:00:00", + "2023-03-30 06:00:00", + "2023-03-30 08:00:00", + "2023-03-30 10:00:00", + "2023-03-30 12:00:00", + "2023-03-30 14:00:00", + "2023-03-30 16:00:00", + "2023-03-30 18:00:00", + "2023-03-30 20:00:00", + "2023-03-30 22:00:00", + "2023-03-31 00:00:00", + "2023-03-31 02:00:00", + "2023-03-31 04:00:00", + "2023-03-31 06:00:00", + "2023-03-31 08:00:00", + "2023-03-31 10:00:00", + "2023-03-31 12:00:00", + "2023-03-31 14:00:00", + "2023-03-31 16:00:00", + "2023-03-31 18:00:00", + "2023-03-31 20:00:00", + "2023-03-31 22:00:00", + "2023-04-01 00:00:00", + "2023-04-01 02:00:00", + "2023-04-01 04:00:00", + "2023-04-01 06:00:00", + "2023-04-01 08:00:00", + "2023-04-01 10:00:00", + "2023-04-01 12:00:00", + "2023-04-01 14:00:00", + "2023-04-01 16:00:00", + "2023-04-01 18:00:00", + "2023-04-01 20:00:00", + "2023-04-01 22:00:00", + "2023-04-02 00:00:00", + "2023-04-02 02:00:00", + "2023-04-02 04:00:00", + "2023-04-02 06:00:00", + "2023-04-02 08:00:00", + "2023-04-02 10:00:00", + "2023-04-02 12:00:00", + "2023-04-02 14:00:00", + "2023-04-02 16:00:00", + "2023-04-02 18:00:00", + "2023-04-02 20:00:00", + "2023-04-02 22:00:00", + "2023-04-03 00:00:00", + "2023-04-03 02:00:00", + "2023-04-03 04:00:00", + "2023-04-03 06:00:00", + "2023-04-03 08:00:00", + "2023-04-03 10:00:00", + "2023-04-03 12:00:00", + "2023-04-03 14:00:00", + "2023-04-03 16:00:00", + "2023-04-03 18:00:00", + "2023-04-03 20:00:00", + "2023-04-03 22:00:00", + "2023-04-04 00:00:00", + "2023-04-04 02:00:00", + "2023-04-04 04:00:00", + "2023-04-04 06:00:00", + "2023-04-04 08:00:00", + "2023-04-04 10:00:00", + "2023-04-04 12:00:00", + "2023-04-04 14:00:00", + "2023-04-04 16:00:00", + "2023-04-04 18:00:00", + "2023-04-04 20:00:00", + "2023-04-04 22:00:00", + "2023-04-05 00:00:00", + "2023-04-05 02:00:00", + "2023-04-05 04:00:00", + "2023-04-05 06:00:00", + "2023-04-05 08:00:00", + "2023-04-05 10:00:00", + "2023-04-05 12:00:00", + "2023-04-05 14:00:00", + "2023-04-05 16:00:00", + "2023-04-05 18:00:00", + "2023-04-05 20:00:00", + "2023-04-05 22:00:00", + "2023-04-06 00:00:00", + "2023-04-06 02:00:00", + "2023-04-06 04:00:00", + "2023-04-06 06:00:00", + "2023-04-06 08:00:00", + "2023-04-06 10:00:00", + "2023-04-06 12:00:00", + "2023-04-06 14:00:00", + "2023-04-06 16:00:00", + "2023-04-06 18:00:00", + "2023-04-06 20:00:00", + "2023-04-06 22:00:00", + "2023-04-07 00:00:00", + "2023-04-07 02:00:00", + "2023-04-07 04:00:00", + "2023-04-07 06:00:00", + "2023-04-07 08:00:00", + "2023-04-07 10:00:00", + "2023-04-07 12:00:00", + "2023-04-07 14:00:00", + "2023-04-07 16:00:00", + "2023-04-07 18:00:00", + "2023-04-07 20:00:00", + "2023-04-07 22:00:00", + "2023-04-08 00:00:00", + "2023-04-08 02:00:00", + "2023-04-08 04:00:00", + "2023-04-08 06:00:00", + "2023-04-08 08:00:00", + "2023-04-08 10:00:00", + "2023-04-08 12:00:00", + "2023-04-08 14:00:00", + "2023-04-08 16:00:00", + "2023-04-08 18:00:00", + "2023-04-08 20:00:00", + "2023-04-08 22:00:00", + "2023-04-09 00:00:00", + "2023-04-09 02:00:00", + "2023-04-09 04:00:00", + "2023-04-09 06:00:00", + "2023-04-09 08:00:00", + "2023-04-09 10:00:00", + "2023-04-09 12:00:00", + "2023-04-09 14:00:00", + "2023-04-09 16:00:00", + "2023-04-09 18:00:00", + "2023-04-09 20:00:00", + "2023-04-09 22:00:00", + "2023-04-10 00:00:00", + "2023-04-10 02:00:00", + "2023-04-10 04:00:00", + "2023-04-10 06:00:00", + "2023-04-10 08:00:00", + "2023-04-10 10:00:00", + "2023-04-10 12:00:00", + "2023-04-10 14:00:00", + "2023-04-10 16:00:00", + "2023-04-10 18:00:00", + "2023-04-10 20:00:00", + "2023-04-10 22:00:00", + "2023-04-11 00:00:00", + "2023-04-11 02:00:00", + "2023-04-11 04:00:00", + "2023-04-11 06:00:00", + "2023-04-11 08:00:00", + "2023-04-11 10:00:00", + "2023-04-11 12:00:00", + "2023-04-11 14:00:00", + "2023-04-11 16:00:00", + "2023-04-11 18:00:00", + "2023-04-11 20:00:00", + "2023-04-11 22:00:00", + "2023-04-12 00:00:00", + "2023-04-12 02:00:00", + "2023-04-12 04:00:00", + "2023-04-12 06:00:00", + "2023-04-12 08:00:00", + "2023-04-12 10:00:00", + "2023-04-12 12:00:00", + "2023-04-12 14:00:00", + "2023-04-12 16:00:00", + "2023-04-12 18:00:00", + "2023-04-12 20:00:00", + "2023-04-12 22:00:00", + "2023-04-13 00:00:00", + "2023-04-13 02:00:00", + "2023-04-13 04:00:00", + "2023-04-13 06:00:00", + "2023-04-13 08:00:00", + "2023-04-13 10:00:00", + "2023-04-13 12:00:00", + "2023-04-13 14:00:00", + "2023-04-13 16:00:00", + "2023-04-13 18:00:00", + "2023-04-13 20:00:00", + "2023-04-13 22:00:00", + "2023-04-14 00:00:00", + "2023-04-14 02:00:00", + "2023-04-14 04:00:00", + "2023-04-14 06:00:00", + "2023-04-14 08:00:00", + "2023-04-14 10:00:00", + "2023-04-14 12:00:00", + "2023-04-14 14:00:00", + "2023-04-14 16:00:00", + "2023-04-14 18:00:00", + "2023-04-14 20:00:00", + "2023-04-14 22:00:00", + "2023-04-15 00:00:00", + "2023-04-15 02:00:00", + "2023-04-15 04:00:00", + "2023-04-15 06:00:00", + "2023-04-15 08:00:00", + "2023-04-15 10:00:00", + "2023-04-15 12:00:00", + "2023-04-15 14:00:00", + "2023-04-15 16:00:00", + "2023-04-15 18:00:00", + "2023-04-15 20:00:00", + "2023-04-15 22:00:00", + "2023-04-16 00:00:00", + "2023-04-16 04:00:00", + "2023-04-16 06:00:00", + "2023-04-16 08:00:00", + "2023-04-16 10:00:00", + "2023-04-16 12:00:00", + "2023-04-16 14:00:00", + "2023-04-16 16:00:00", + "2023-04-16 18:00:00", + "2023-04-16 20:00:00", + "2023-04-16 22:00:00", + "2023-04-17 00:00:00", + "2023-04-17 02:00:00", + "2023-04-17 04:00:00", + "2023-04-17 06:00:00", + "2023-04-17 08:00:00", + "2023-04-17 10:00:00", + "2023-04-17 12:00:00", + "2023-04-17 14:00:00", + "2023-04-17 16:00:00", + "2023-04-17 18:00:00", + "2023-04-17 20:00:00", + "2023-04-17 22:00:00", + "2023-04-18 00:00:00", + "2023-04-18 02:00:00", + "2023-04-18 04:00:00", + "2023-04-18 06:00:00", + "2023-04-18 08:00:00", + "2023-04-18 10:00:00", + "2023-04-18 12:00:00", + "2023-04-18 14:00:00", + "2023-04-18 16:00:00", + "2023-04-18 18:00:00", + "2023-04-18 20:00:00", + "2023-04-18 22:00:00", + "2023-04-19 00:00:00", + "2023-04-19 02:00:00", + "2023-04-19 04:00:00", + "2023-04-19 06:00:00", + "2023-04-19 08:00:00", + "2023-04-19 10:00:00", + "2023-04-19 12:00:00", + "2023-04-19 14:00:00", + "2023-04-19 16:00:00", + "2023-04-19 18:00:00", + "2023-04-19 20:00:00", + "2023-04-19 22:00:00", + "2023-04-20 00:00:00", + "2023-04-20 02:00:00", + "2023-04-20 04:00:00", + "2023-04-20 06:00:00", + "2023-04-20 08:00:00", + "2023-04-20 10:00:00", + "2023-04-20 12:00:00", + "2023-04-20 14:00:00", + "2023-04-20 16:00:00", + "2023-04-20 18:00:00", + "2023-04-20 20:00:00", + "2023-04-20 22:00:00", + "2023-04-21 00:00:00", + "2023-04-21 02:00:00", + "2023-04-21 04:00:00", + "2023-04-21 06:00:00", + "2023-04-21 08:00:00", + "2023-04-21 10:00:00", + "2023-04-21 12:00:00", + "2023-04-21 14:00:00", + "2023-04-21 16:00:00", + "2023-04-21 18:00:00", + "2023-04-21 20:00:00", + "2023-04-21 22:00:00", + "2023-04-22 00:00:00", + "2023-04-22 02:00:00", + "2023-04-22 04:00:00", + "2023-04-22 06:00:00", + "2023-04-22 08:00:00", + "2023-04-22 10:00:00", + "2023-04-22 12:00:00", + "2023-04-22 14:00:00", + "2023-04-22 16:00:00", + "2023-04-22 18:00:00", + "2023-04-22 20:00:00", + "2023-04-22 22:00:00", + "2023-04-23 00:00:00", + "2023-04-23 02:00:00", + "2023-04-23 04:00:00", + "2023-04-23 06:00:00", + "2023-04-23 08:00:00", + "2023-04-23 10:00:00", + "2023-04-23 12:00:00", + "2023-04-23 14:00:00", + "2023-04-23 16:00:00", + "2023-04-23 18:00:00", + "2023-04-23 20:00:00", + "2023-04-23 22:00:00", + "2023-04-24 00:00:00", + "2023-04-24 02:00:00", + "2023-04-24 04:00:00", + "2023-04-24 06:00:00", + "2023-04-24 08:00:00", + "2023-04-24 10:00:00", + "2023-04-24 12:00:00", + "2023-04-24 14:00:00", + "2023-04-24 16:00:00", + "2023-04-24 18:00:00", + "2023-04-24 20:00:00", + "2023-04-24 22:00:00", + "2023-04-25 00:00:00", + "2023-04-25 02:00:00", + "2023-04-25 04:00:00", + "2023-04-25 06:00:00", + "2023-04-25 08:00:00", + "2023-04-25 10:00:00", + "2023-04-25 12:00:00", + "2023-04-25 14:00:00", + "2023-04-25 16:00:00", + "2023-04-25 18:00:00", + "2023-04-25 20:00:00", + "2023-04-25 22:00:00", + "2023-04-26 00:00:00", + "2023-04-26 02:00:00", + "2023-04-26 04:00:00", + "2023-04-26 06:00:00", + "2023-04-26 08:00:00", + "2023-04-26 10:00:00", + "2023-04-26 12:00:00", + "2023-04-26 14:00:00", + "2023-04-26 16:00:00", + "2023-04-26 18:00:00", + "2023-04-26 20:00:00", + "2023-04-26 22:00:00", + "2023-04-27 00:00:00", + "2023-04-27 02:00:00", + "2023-04-27 04:00:00", + "2023-04-27 06:00:00", + "2023-04-27 08:00:00", + "2023-04-27 10:00:00", + "2023-04-27 12:00:00", + "2023-04-27 14:00:00", + "2023-04-27 16:00:00", + "2023-04-27 18:00:00", + "2023-04-27 20:00:00", + "2023-04-27 22:00:00", + "2023-04-28 00:00:00", + "2023-04-28 02:00:00", + "2023-04-28 04:00:00", + "2023-04-28 06:00:00", + "2023-04-28 08:00:00", + "2023-04-28 10:00:00", + "2023-04-28 12:00:00", + "2023-04-28 14:00:00", + "2023-04-28 16:00:00", + "2023-04-28 18:00:00", + "2023-04-28 20:00:00", + "2023-04-28 22:00:00", + "2023-04-29 00:00:00", + "2023-04-29 02:00:00", + "2023-04-29 04:00:00", + "2023-04-29 06:00:00", + "2023-04-29 08:00:00", + "2023-04-29 10:00:00", + "2023-04-29 12:00:00", + "2023-04-29 14:00:00", + "2023-04-29 16:00:00", + "2023-04-29 18:00:00", + "2023-04-29 20:00:00", + "2023-04-29 22:00:00", + "2023-04-30 00:00:00", + "2023-04-30 02:00:00", + "2023-04-30 04:00:00", + "2023-04-30 06:00:00", + "2023-04-30 08:00:00", + "2023-04-30 10:00:00", + "2023-04-30 12:00:00", + "2023-04-30 14:00:00", + "2023-04-30 16:00:00", + "2023-04-30 18:00:00", + "2023-04-30 20:00:00", + "2023-04-30 22:00:00", + "2023-05-01 00:00:00", + "2023-05-01 02:00:00", + "2023-05-01 04:00:00", + "2023-05-01 06:00:00", + "2023-05-01 08:00:00", + "2023-05-01 10:00:00", + "2023-05-01 12:00:00", + "2023-05-01 14:00:00", + "2023-05-01 16:00:00", + "2023-05-01 18:00:00", + "2023-05-01 20:00:00", + "2023-05-01 22:00:00", + "2023-05-02 00:00:00", + "2023-05-02 02:00:00", + "2023-05-02 04:00:00", + "2023-05-02 06:00:00", + "2023-05-02 08:00:00", + "2023-05-02 10:00:00", + "2023-05-02 12:00:00", + "2023-05-02 14:00:00", + "2023-05-02 16:00:00", + "2023-05-02 18:00:00", + "2023-05-02 20:00:00", + "2023-05-02 22:00:00", + "2023-05-03 00:00:00", + "2023-05-03 02:00:00", + "2023-05-03 04:00:00", + "2023-05-03 06:00:00", + "2023-05-03 08:00:00", + "2023-05-03 10:00:00", + "2023-05-03 12:00:00", + "2023-05-03 14:00:00", + "2023-05-03 16:00:00", + "2023-05-03 18:00:00", + "2023-05-03 20:00:00", + "2023-05-03 22:00:00", + "2023-05-04 00:00:00", + "2023-05-04 02:00:00", + "2023-05-04 04:00:00", + "2023-05-04 06:00:00", + "2023-05-04 08:00:00", + "2023-05-04 10:00:00", + "2023-05-04 12:00:00", + "2023-05-04 14:00:00", + "2023-05-04 16:00:00", + "2023-05-04 18:00:00", + "2023-05-04 20:00:00", + "2023-05-04 22:00:00", + "2023-05-05 00:00:00", + "2023-05-05 02:00:00", + "2023-05-05 04:00:00", + "2023-05-05 06:00:00", + "2023-05-05 08:00:00", + "2023-05-05 10:00:00", + "2023-05-05 12:00:00", + "2023-05-05 14:00:00", + "2023-05-05 16:00:00", + "2023-05-05 18:00:00", + "2023-05-05 20:00:00", + "2023-05-05 22:00:00", + "2023-05-06 00:00:00", + "2023-05-06 02:00:00", + "2023-05-06 04:00:00", + "2023-05-06 06:00:00", + "2023-05-06 08:00:00", + "2023-05-06 10:00:00", + "2023-05-06 12:00:00", + "2023-05-06 14:00:00", + "2023-05-06 16:00:00", + "2023-05-06 18:00:00", + "2023-05-06 20:00:00", + "2023-05-06 22:00:00", + "2023-05-07 00:00:00", + "2023-05-07 02:00:00", + "2023-05-07 04:00:00", + "2023-05-07 06:00:00", + "2023-05-07 08:00:00", + "2023-05-07 10:00:00", + "2023-05-07 12:00:00", + "2023-05-07 14:00:00", + "2023-05-07 16:00:00", + "2023-05-07 18:00:00", + "2023-05-07 20:00:00", + "2023-05-07 22:00:00", + "2023-05-08 00:00:00", + "2023-05-08 02:00:00", + "2023-05-08 04:00:00", + "2023-05-08 06:00:00", + "2023-05-08 08:00:00", + "2023-05-08 10:00:00", + "2023-05-08 12:00:00", + "2023-05-08 14:00:00", + "2023-05-08 16:00:00", + "2023-05-08 18:00:00", + "2023-05-08 20:00:00", + "2023-05-08 22:00:00", + "2023-05-09 00:00:00", + "2023-05-09 02:00:00", + "2023-05-09 04:00:00", + "2023-05-09 06:00:00", + "2023-05-09 08:00:00", + "2023-05-09 10:00:00", + "2023-05-09 12:00:00", + "2023-05-09 14:00:00", + "2023-05-09 16:00:00", + "2023-05-09 18:00:00", + "2023-05-09 20:00:00", + "2023-05-09 22:00:00", + "2023-05-10 00:00:00", + "2023-05-10 02:00:00", + "2023-05-10 04:00:00", + "2023-05-10 06:00:00", + "2023-05-10 08:00:00", + "2023-05-10 10:00:00", + "2023-05-10 12:00:00", + "2023-05-10 14:00:00", + "2023-05-10 16:00:00", + "2023-05-10 18:00:00", + "2023-05-10 20:00:00", + "2023-05-10 22:00:00", + "2023-05-11 00:00:00", + "2023-05-11 02:00:00", + "2023-05-11 04:00:00", + "2023-05-11 06:00:00", + "2023-05-11 08:00:00", + "2023-05-11 10:00:00", + "2023-05-11 12:00:00", + "2023-05-11 14:00:00", + "2023-05-11 16:00:00", + "2023-05-11 18:00:00", + "2023-05-11 20:00:00", + "2023-05-11 22:00:00", + "2023-05-12 00:00:00", + "2023-05-12 02:00:00", + "2023-05-12 04:00:00", + "2023-05-12 06:00:00", + "2023-05-12 08:00:00", + "2023-05-12 10:00:00", + "2023-05-12 12:00:00", + "2023-05-12 14:00:00", + "2023-05-12 16:00:00", + "2023-05-12 18:00:00", + "2023-05-12 20:00:00", + "2023-05-12 22:00:00", + "2023-05-13 00:00:00", + "2023-05-13 02:00:00", + "2023-05-13 04:00:00", + "2023-05-13 06:00:00", + "2023-05-13 08:00:00", + "2023-05-13 10:00:00", + "2023-05-13 12:00:00", + "2023-05-13 14:00:00", + "2023-05-13 16:00:00", + "2023-05-13 18:00:00", + "2023-05-13 20:00:00", + "2023-05-13 22:00:00", + "2023-05-14 00:00:00", + "2023-05-14 02:00:00", + "2023-05-14 04:00:00", + "2023-05-14 06:00:00", + "2023-05-14 08:00:00", + "2023-05-14 10:00:00", + "2023-05-14 12:00:00", + "2023-05-14 14:00:00", + "2023-05-14 16:00:00", + "2023-05-14 18:00:00", + "2023-05-14 20:00:00", + "2023-05-14 22:00:00", + "2023-05-15 00:00:00", + "2023-05-15 02:00:00", + "2023-05-15 04:00:00", + "2023-05-15 06:00:00", + "2023-05-15 08:00:00", + "2023-05-15 10:00:00", + "2023-05-15 12:00:00", + "2023-05-15 14:00:00", + "2023-05-15 16:00:00", + "2023-05-15 18:00:00", + "2023-05-15 20:00:00", + "2023-05-15 22:00:00", + "2023-05-16 00:00:00", + "2023-05-16 02:00:00", + "2023-05-16 04:00:00", + "2023-05-16 06:00:00", + "2023-05-16 08:00:00", + "2023-05-16 10:00:00", + "2023-05-16 12:00:00", + "2023-05-16 14:00:00", + "2023-05-16 16:00:00", + "2023-05-16 18:00:00", + "2023-05-16 20:00:00", + "2023-05-16 22:00:00", + "2023-05-17 00:00:00", + "2023-05-17 02:00:00", + "2023-05-17 04:00:00", + "2023-05-17 06:00:00", + "2023-05-17 08:00:00", + "2023-05-17 10:00:00", + "2023-05-17 12:00:00", + "2023-05-17 14:00:00", + "2023-05-17 16:00:00", + "2023-05-17 18:00:00", + "2023-05-17 20:00:00", + "2023-05-17 22:00:00", + "2023-05-18 00:00:00", + "2023-05-18 02:00:00", + "2023-05-18 04:00:00", + "2023-05-18 06:00:00", + "2023-05-18 08:00:00", + "2023-05-18 10:00:00", + "2023-05-18 12:00:00", + "2023-05-18 14:00:00", + "2023-05-18 16:00:00", + "2023-05-18 18:00:00", + "2023-05-18 20:00:00", + "2023-05-18 22:00:00", + "2023-05-19 00:00:00", + "2023-05-19 02:00:00", + "2023-05-19 04:00:00", + "2023-05-19 06:00:00", + "2023-05-19 08:00:00", + "2023-05-19 10:00:00", + "2023-05-19 12:00:00", + "2023-05-19 14:00:00", + "2023-05-19 16:00:00", + "2023-05-19 18:00:00", + "2023-05-19 20:00:00", + "2023-05-19 22:00:00", + "2023-05-20 00:00:00", + "2023-05-20 02:00:00", + "2023-05-20 04:00:00", + "2023-05-20 06:00:00", + "2023-05-20 08:00:00", + "2023-05-20 10:00:00", + "2023-05-20 12:00:00", + "2023-05-20 14:00:00", + "2023-05-20 16:00:00", + "2023-05-20 18:00:00", + "2023-05-20 20:00:00", + "2023-05-20 22:00:00", + "2023-05-21 00:00:00", + "2023-05-21 02:00:00", + "2023-05-21 04:00:00", + "2023-05-21 06:00:00", + "2023-05-21 08:00:00", + "2023-05-21 10:00:00", + "2023-05-21 12:00:00", + "2023-05-21 14:00:00", + "2023-05-21 16:00:00", + "2023-05-21 18:00:00", + "2023-05-21 20:00:00", + "2023-05-21 22:00:00", + "2023-05-22 00:00:00", + "2023-05-22 02:00:00", + "2023-05-22 04:00:00", + "2023-05-22 06:00:00", + "2023-05-22 08:00:00", + "2023-05-22 10:00:00", + "2023-05-22 12:00:00", + "2023-05-22 14:00:00", + "2023-05-22 16:00:00", + "2023-05-22 18:00:00", + "2023-05-22 20:00:00", + "2023-05-22 22:00:00", + "2023-05-23 00:00:00", + "2023-05-23 02:00:00", + "2023-05-23 04:00:00", + "2023-05-23 06:00:00", + "2023-05-23 08:00:00", + "2023-05-23 10:00:00", + "2023-05-23 12:00:00", + "2023-05-23 14:00:00", + "2023-05-23 16:00:00", + "2023-05-23 18:00:00", + "2023-05-23 20:00:00", + "2023-05-23 22:00:00", + "2023-05-24 00:00:00", + "2023-05-24 02:00:00", + "2023-05-24 04:00:00", + "2023-05-24 06:00:00", + "2023-05-24 08:00:00", + "2023-05-24 10:00:00", + "2023-05-24 12:00:00", + "2023-05-24 14:00:00", + "2023-05-24 16:00:00", + "2023-05-24 18:00:00", + "2023-05-24 20:00:00", + "2023-05-24 22:00:00", + "2023-05-25 00:00:00", + "2023-05-25 02:00:00", + "2023-05-25 04:00:00", + "2023-05-25 06:00:00", + "2023-05-25 08:00:00", + "2023-05-25 10:00:00", + "2023-05-25 12:00:00", + "2023-05-25 14:00:00", + "2023-05-25 16:00:00", + "2023-05-25 18:00:00", + "2023-05-25 20:00:00", + "2023-05-25 22:00:00", + "2023-05-26 00:00:00", + "2023-05-26 02:00:00", + "2023-05-26 04:00:00", + "2023-05-26 06:00:00", + "2023-05-26 08:00:00", + "2023-05-26 10:00:00", + "2023-05-26 12:00:00", + "2023-05-26 14:00:00", + "2023-05-26 16:00:00", + "2023-05-26 18:00:00", + "2023-05-26 20:00:00", + "2023-05-26 22:00:00", + "2023-05-27 00:00:00", + "2023-05-27 02:00:00", + "2023-05-27 04:00:00", + "2023-05-27 06:00:00", + "2023-05-27 08:00:00", + "2023-05-27 10:00:00", + "2023-05-27 12:00:00", + "2023-05-27 14:00:00", + "2023-05-27 16:00:00", + "2023-05-27 18:00:00", + "2023-05-27 20:00:00", + "2023-05-27 22:00:00", + "2023-05-28 00:00:00", + "2023-05-28 02:00:00", + "2023-05-28 04:00:00", + "2023-05-28 06:00:00", + "2023-05-28 08:00:00", + "2023-05-28 10:00:00", + "2023-05-28 12:00:00", + "2023-05-28 14:00:00", + "2023-05-28 16:00:00", + "2023-05-28 18:00:00", + "2023-05-28 20:00:00", + "2023-05-28 22:00:00", + "2023-05-29 00:00:00", + "2023-05-29 02:00:00", + "2023-05-29 04:00:00", + "2023-05-29 06:00:00", + "2023-05-29 08:00:00", + "2023-05-29 10:00:00", + "2023-05-29 12:00:00", + "2023-05-29 14:00:00", + "2023-05-29 16:00:00", + "2023-05-29 18:00:00", + "2023-05-29 20:00:00", + "2023-05-29 22:00:00", + "2023-05-30 00:00:00", + "2023-05-30 02:00:00", + "2023-05-30 04:00:00", + "2023-05-30 06:00:00", + "2023-05-30 08:00:00", + "2023-05-30 10:00:00", + "2023-05-30 12:00:00", + "2023-05-30 14:00:00", + "2023-05-30 16:00:00", + "2023-05-30 18:00:00", + "2023-05-30 20:00:00", + "2023-05-30 22:00:00", + "2023-05-31 00:00:00", + "2023-05-31 02:00:00", + "2023-05-31 04:00:00", + "2023-05-31 06:00:00", + "2023-05-31 08:00:00", + "2023-05-31 10:00:00", + "2023-05-31 12:00:00", + "2023-05-31 14:00:00", + "2023-05-31 16:00:00", + "2023-05-31 18:00:00", + "2023-05-31 20:00:00", + "2023-05-31 22:00:00", + "2023-06-01 00:00:00" + ], + "y": [ + 15603.0, + 15748.0, + 15831.0, + 15832.0, + 15801.0, + 15795.0, + 15801.0, + 15906.0, + 15839.0, + 15898.0, + 15877.0, + 15906.0, + 15868.0, + 15858.0, + 15839.0, + 15818.0, + 15901.0, + 15916.0, + 15846.0, + 15870.0, + 15867.0, + 15774.0, + 15837.0, + 15860.0, + 15820.0, + 15832.0, + 15811.0, + 15805.0, + 15828.0, + 15857.0, + 15793.0, + 15692.0, + 15678.0, + 15734.0, + 15843.0, + 15861.0, + 15825.0, + 15859.0, + 15857.0, + 15850.0, + 15866.0, + 15873.0, + 15883.0, + 15863.0, + 15865.0, + 15869.0, + 15839.0, + 15773.0, + 15832.0, + 15847.0, + 15814.0, + 15854.0, + 15854.0, + 15818.0, + 15809.0, + 15845.0, + 15848.0, + 15847.0, + 15834.0, + 15822.0, + 15826.0, + 15823.0, + 15843.0, + 15834.0, + 15854.0, + 15820.0, + 15830.0, + 15819.0, + 15815.0, + 15805.0, + 15842.0, + 15831.0, + 15879.0, + 15912.0, + 15848.0, + 15827.0, + 15837.0, + 15866.0, + 15842.0, + 15811.0, + 15837.0, + 15836.0, + 15815.0, + 15897.0, + 15820.0, + 15824.0, + 15802.0, + 15821.0, + 15807.0, + 15786.0, + 15823.0, + 15755.0, + 15675.0, + 15678.0, + 15700.0, + 15707.0, + 15673.0, + 15658.0, + 15592.0, + 15637.0, + 15631.0, + 15650.0, + 15619.0, + 15585.0, + 15647.0, + 15622.0, + 15550.0, + 15569.0, + 15544.0, + 15560.0, + 15606.0, + 15579.0, + 15578.0, + 15599.0, + 15578.0, + 15561.0, + 15532.0, + 15562.0, + 15565.0, + 15580.0, + 15585.0, + 15581.0, + 15529.0, + 15473.0, + 15501.0, + 15452.0, + 15438.0, + 15523.0, + 15415.0, + 15454.0, + 15497.0, + 15518.0, + 15479.0, + 15451.0, + 15452.0, + 15476.0, + 15445.0, + 15461.0, + 15510.0, + 15504.0, + 15489.0, + 15470.0, + 15444.0, + 15439.0, + 15437.0, + 15433.0, + 15425.0, + 15426.0, + 15439.0, + 15465.0, + 15462.0, + 15442.0, + 15466.0, + 15504.0, + 15516.0, + 15533.0, + 15483.0, + 15569.0, + 15549.0, + 15661.0, + 15653.0, + 15660.0, + 15629.0, + 15692.0, + 15666.0, + 15682.0, + 15682.0, + 15605.0, + 15639.0, + 15621.0, + 15637.0, + 15710.0, + 15859.0, + 15874.0, + 15833.0, + 15790.0, + 15763.0, + 15729.0, + 15770.0, + 15784.0, + 15803.0, + 15929.0, + 15921.0, + 15897.0, + 15869.0, + 15869.0, + 15856.0, + 15889.0, + 15936.0, + 15872.0, + 15849.0, + 15896.0, + 15838.0, + 15866.0, + 15863.0, + 15847.0, + 15797.0, + 15848.0, + 15895.0, + 16001.0, + 15970.0, + 16001.0, + 15992.0, + 16001.0, + 15975.0, + 15991.0, + 15988.0, + 15966.0, + 15953.0, + 15944.0, + 15887.0, + 15871.0, + 15823.0, + 15888.0, + 15891.0, + 15924.0, + 15926.0, + 15922.0, + 15910.0, + 15929.0, + 15888.0, + 15887.0, + 15901.0, + 15926.0, + 15919.0, + 15910.0, + 15904.0, + 15911.0, + 15912.0, + 15921.0, + 15923.0, + 15904.0, + 15911.0, + 15910.0, + 15883.0, + 15962.0, + 15883.0, + 15879.0, + 15918.0, + 16069.0, + 16114.0, + 16126.0, + 16091.0, + 16114.0, + 16156.0, + 16148.0, + 16070.0, + 16073.0, + 16150.0, + 16101.0, + 16016.0, + 16017.0, + 16027.0, + 16035.0, + 16043.0, + 16010.0, + 16050.0, + 16065.0, + 16074.0, + 16144.0, + 16135.0, + 16222.0, + 16287.0, + 16235.0, + 16282.0, + 16240.0, + 16171.0, + 16238.0, + 16245.0, + 16230.0, + 16210.0, + 16124.0, + 16171.0, + 16299.0, + 16307.0, + 16635.0, + 16923.0, + 16922.0, + 16795.0, + 16836.0, + 16875.0, + 16914.0, + 16896.0, + 16736.0, + 17360.0, + 17430.0, + 17350.0, + 17374.0, + 17297.0, + 17389.0, + 17342.0, + 17347.0, + 17462.0, + 17515.0, + 17482.0, + 17816.0, + 17800.0, + 17880.0, + 18281.0, + 18384.0, + 19320.0, + 19309.0, + 19211.0, + 19301.0, + 18935.0, + 19122.0, + 19328.0, + 19164.0, + 19137.0, + 19170.0, + 19260.0, + 19347.0, + 19157.0, + 19081.0, + 19129.0, + 19092.0, + 19136.0, + 19102.0, + 19068.0, + 19281.0, + 19301.0, + 19243.0, + 19301.0, + 19277.0, + 19496.0, + 19412.0, + 19533.0, + 19500.0, + 19244.0, + 19237.0, + 19251.0, + 19381.0, + 19524.0, + 19700.0, + 19510.0, + 19566.0, + 19466.0, + 19529.0, + 19541.0, + 19536.0, + 19595.0, + 19579.0, + 19606.0, + 19628.0, + 19694.0, + 19763.0, + 19751.0, + 19610.0, + 19675.0, + 19759.0, + 19783.0, + 19696.0, + 19548.0, + 19616.0, + 19722.0, + 19436.0, + 19338.0, + 19347.0, + 19225.0, + 19133.0, + 19171.0, + 19185.0, + 19278.0, + 19224.0, + 19205.0, + 19131.0, + 19233.0, + 19337.0, + 19265.0, + 19488.0, + 19338.0, + 19447.0, + 19499.0, + 19465.0, + 19367.0, + 19339.0, + 19365.0, + 19340.0, + 19487.0, + 19540.0, + 19678.0, + 19797.0, + 20531.0, + 20858.0, + 20779.0, + 20757.0, + 20790.0, + 20848.0, + 21235.0, + 21113.0, + 21118.0, + 21186.0, + 21426.0, + 21469.0, + 21376.0, + 20990.0, + 21030.0, + 20981.0, + 21108.0, + 21128.0, + 21088.0, + 20985.0, + 21121.0, + 20997.0, + 21131.0, + 20936.0, + 20794.0, + 20912.0, + 20868.0, + 20793.0, + 20876.0, + 20813.0, + 20884.0, + 21062.0, + 21005.0, + 21046.0, + 21230.0, + 21003.0, + 21145.0, + 21078.0, + 21242.0, + 21234.0, + 21262.0, + 21160.0, + 21053.0, + 21089.0, + 21054.0, + 21068.0, + 21032.0, + 21147.0, + 21054.0, + 20799.0, + 20665.0, + 20764.0, + 20817.0, + 20897.0, + 20777.0, + 20784.0, + 20771.0, + 20693.0, + 20707.0, + 20854.0, + 21615.0, + 21126.0, + 21217.0, + 21176.0, + 21226.0, + 21045.0, + 21070.0, + 21108.0, + 21216.0, + 21151.0, + 21136.0, + 21173.0, + 21196.0, + 21112.0, + 20772.0, + 20957.0, + 21162.0, + 21206.0, + 21083.0, + 21110.0, + 21078.0, + 21188.0, + 21365.0, + 21389.0, + 21248.0, + 21257.0, + 21241.0, + 21304.0, + 21243.0, + 21182.0, + 21160.0, + 21168.0, + 21169.0, + 21194.0, + 21176.0, + 21224.0, + 21172.0, + 21212.0, + 21380.0, + 21337.0, + 21400.0, + 21369.0, + 21421.0, + 21540.0, + 21665.0, + 21628.0, + 21693.0, + 21988.0, + 21913.0, + 21840.0, + 21766.0, + 21810.0, + 21835.0, + 21785.0, + 21251.0, + 21191.0, + 21176.0, + 21341.0, + 21296.0, + 21000.0, + 20977.0, + 21067.0, + 21050.0, + 21062.0, + 21000.0, + 21206.0, + 21138.0, + 21112.0, + 21308.0, + 21303.0, + 21318.0, + 21317.0, + 21132.0, + 21311.0, + 21282.0, + 21293.0, + 21270.0, + 21213.0, + 21141.0, + 21172.0, + 21180.0, + 21058.0, + 21092.0, + 21321.0, + 21550.0, + 21550.0, + 21752.0, + 21632.0, + 21611.0, + 21625.0, + 21646.0, + 21646.0, + 21714.0, + 21812.0, + 21909.0, + 21827.0, + 21507.0, + 21532.0, + 21638.0, + 21600.0, + 21578.0, + 21532.0, + 21445.0, + 21554.0, + 21553.0, + 21730.0, + 21731.0, + 21562.0, + 21671.0, + 21687.0, + 21659.0, + 21600.0, + 21601.0, + 21622.0, + 21634.0, + 21655.0, + 21758.0, + 21695.0, + 21729.0, + 21711.0, + 21671.0, + 21626.0, + 21616.0, + 21623.0, + 21656.0, + 21680.0, + 21661.0, + 21654.0, + 21491.0, + 21398.0, + 21169.0, + 21216.0, + 21248.0, + 21269.0, + 21301.0, + 21229.0, + 21099.0, + 21250.0, + 21227.0, + 21239.0, + 21209.0, + 21459.0, + 21499.0, + 21453.0, + 21369.0, + 21216.0, + 21248.0, + 21298.0, + 21341.0, + 21354.0, + 21481.0, + 21462.0, + 21495.0, + 21400.0, + 21616.0, + 21546.0, + 21604.0, + 21661.0, + 21673.0, + 21670.0, + 21630.0, + 21576.0, + 21552.0, + 21570.0, + 21525.0, + 21332.0, + 21435.0, + 21339.0, + 21425.0, + 21445.0, + 21378.0, + 20992.0, + 21073.0, + 21137.0, + 21130.0, + 21081.0, + 21059.0, + 21012.0, + 20974.0, + 20522.0, + 20348.0, + 20303.0, + 20406.0, + 20349.0, + 20329.0, + 20400.0, + 20400.0, + 20318.0, + 20371.0, + 20296.0, + 20346.0, + 20392.0, + 20180.0, + 20275.0, + 20275.0, + 20320.0, + 20318.0, + 20333.0, + 20334.0, + 20334.0, + 20392.0, + 20350.0, + 20322.0, + 20312.0, + 20468.0, + 20505.0, + 20446.0, + 20409.0, + 20437.0, + 20428.0, + 20551.0, + 20522.0, + 20475.0, + 20573.0, + 20623.0, + 20651.0, + 20385.0, + 20421.0, + 20342.0, + 20470.0, + 20471.0, + 20493.0, + 20240.0, + 20231.0, + 20200.0, + 20139.0, + 20040.0, + 20160.0, + 20148.0, + 20302.0, + 20223.0, + 20225.0, + 20251.0, + 20304.0, + 20281.0, + 20294.0, + 20199.0, + 20595.0, + 20547.0, + 20704.0, + 20709.0, + 20690.0, + 20597.0, + 20601.0, + 20668.0, + 20629.0, + 20679.0, + 20950.0, + 21220.0, + 21370.0, + 21370.0, + 21799.0, + 22596.0, + 22714.0, + 22969.0, + 23072.0, + 23014.0, + 22929.0, + 22992.0, + 22947.0, + 22852.0, + 23500.0, + 23268.0, + 23264.0, + 22982.0, + 22043.0, + 22395.0, + 22378.0, + 22286.0, + 22224.0, + 22334.0, + 22393.0, + 22360.0, + 22653.0, + 22754.0, + 22936.0, + 22861.0, + 22970.0, + 23068.0, + 22987.0, + 23049.0, + 22925.0, + 22971.0, + 22913.0, + 22971.0, + 23065.0, + 23082.0, + 23022.0, + 23018.0, + 23029.0, + 23108.0, + 23049.0, + 23127.0, + 22982.0, + 22981.0, + 23083.0, + 23089.0, + 23265.0, + 22780.0, + 22951.0, + 22961.0, + 22724.0, + 22715.0, + 22867.0, + 22921.0, + 22905.0, + 23265.0, + 23277.0, + 23242.0, + 23315.0, + 23221.0, + 23243.0, + 23186.0, + 23250.0, + 23299.0, + 23369.0, + 23363.0, + 23436.0, + 23261.0, + 23066.0, + 23075.0, + 23000.0, + 23156.0, + 23126.0, + 22748.0, + 22974.0, + 22715.0, + 22721.0, + 22634.0, + 22582.0, + 22674.0, + 22746.0, + 22669.0, + 22338.0, + 22352.0, + 22463.0, + 22440.0, + 22816.0, + 22787.0, + 23028.0, + 22950.0, + 22936.0, + 22929.0, + 22467.0, + 22644.0, + 22590.0, + 22537.0, + 22650.0, + 22556.0, + 22602.0, + 22652.0, + 22628.0, + 22573.0, + 22530.0, + 22543.0, + 22586.0, + 22526.0, + 22176.0, + 21906.0, + 21965.0, + 21936.0, + 22009.0, + 22016.0, + 21904.0, + 21881.0, + 21943.0, + 21899.0, + 21801.0, + 21812.0, + 21857.0, + 21875.0, + 21808.0, + 21822.0, + 22067.0, + 21989.0, + 22103.0, + 22000.0, + 22046.0, + 22178.0, + 22130.0, + 22082.0, + 22146.0, + 22085.0, + 22362.0, + 22389.0, + 22335.0, + 22333.0, + 22334.0, + 22194.0, + 22209.0, + 22143.0, + 22198.0, + 22416.0, + 22247.0, + 22034.0, + 21967.0, + 22035.0, + 22142.0, + 22153.0, + 22167.0, + 22104.0, + 21937.0, + 21953.0, + 22068.0, + 22030.0, + 22180.0, + 22181.0, + 21991.0, + 21895.0, + 21885.0, + 21986.0, + 22143.0, + 22357.0, + 22269.0, + 22330.0, + 22249.0, + 22205.0, + 22210.0, + 22237.0, + 21929.0, + 22089.0, + 22163.0, + 22089.0, + 22090.0, + 22036.0, + 21980.0, + 22042.0, + 22030.0, + 22028.0, + 22010.0, + 21992.0, + 22135.0, + 22102.0, + 22115.0, + 20961.0, + 21075.0, + 21086.0, + 21121.0, + 21104.0, + 21076.0, + 21116.0, + 21098.0, + 21104.0, + 21035.0, + 20917.0, + 21031.0, + 21026.0, + 21039.0, + 21017.0, + 21034.0, + 21007.0, + 21043.0, + 21047.0, + 20998.0, + 20979.0, + 20931.0, + 20864.0, + 21008.0, + 21256.0, + 21051.0, + 21092.0, + 21071.0, + 21052.0, + 21066.0, + 21148.0, + 21124.0, + 21094.0, + 21093.0, + 21171.0, + 21126.0, + 21073.0, + 21046.0, + 21009.0, + 21030.0, + 21079.0, + 21010.0, + 21056.0, + 21139.0, + 21049.0, + 20971.0, + 20972.0, + 20962.0, + 21051.0, + 21000.0, + 21022.0, + 20977.0, + 20996.0, + 20965.0, + 20996.0, + 21065.0, + 21112.0, + 20968.0, + 20913.0, + 21042.0, + 21019.0, + 21024.0, + 20849.0, + 20812.0, + 20887.0, + 20948.0, + 20859.0, + 20983.0, + 20895.0, + 20853.0, + 20845.0, + 20587.0, + 20593.0, + 20641.0, + 20577.0, + 20520.0, + 20475.0, + 20482.0, + 20518.0, + 20446.0, + 20269.0, + 19683.0, + 19145.0, + 19257.0, + 18984.0, + 18946.0, + 18903.0, + 18843.0, + 18779.0, + 18673.0, + 19026.0, + 18760.0, + 18697.0, + 18844.0, + 18902.0, + 18989.0, + 19567.0, + 19342.0, + 19277.0, + 18786.0, + 18949.0, + 19034.0, + 18942.0, + 18888.0, + 19017.0, + 19050.0, + 19155.0, + 19219.0, + 19217.0, + 19181.0, + 19200.0, + 19195.0, + 19216.0, + 19237.0, + 19209.0, + 19257.0, + 19638.0, + 19577.0, + 19974.0, + 20665.0, + 20993.0, + 20775.0, + 20880.0, + 20891.0, + 20562.0, + 20616.0, + 21000.0, + 22323.0, + 22407.0, + 22505.0, + 22192.0, + 22338.0, + 22600.0, + 22678.0, + 22547.0, + 22488.0, + 22613.0, + 23072.0, + 23972.0, + 24160.0, + 23810.0, + 23275.0, + 22855.0, + 23000.0, + 23137.0, + 22987.0, + 23006.0, + 23194.0, + 22994.0, + 23422.0, + 23514.0, + 23244.0, + 23036.0, + 23052.0, + 23163.0, + 22973.0, + 22982.0, + 22945.0, + 23000.0, + 23212.0, + 23257.0, + 23469.0, + 23433.0, + 23475.0, + 23324.0, + 23590.0, + 23523.0, + 23605.0, + 24196.0, + 24237.0, + 24200.0, + 24511.0, + 24721.0, + 25360.0, + 24911.0, + 24863.0, + 24884.0, + 25192.0, + 25426.0, + 25656.0, + 25591.0, + 25620.0, + 25879.0, + 25699.0, + 25708.0, + 25765.0, + 25732.0, + 25518.0, + 25591.0, + 25678.0, + 25568.0, + 25245.0, + 25419.0, + 25539.0, + 25411.0, + 25280.0, + 25350.0, + 25492.0, + 25506.0, + 25854.0, + 26222.0, + 26549.0, + 26259.0, + 26264.0, + 25987.0, + 25661.0, + 25882.0, + 26519.0, + 26484.0, + 26441.0, + 26025.0, + 25908.0, + 25882.0, + 25967.0, + 26166.0, + 25952.0, + 26091.0, + 25968.0, + 26048.0, + 25756.0, + 26098.0, + 26103.0, + 26100.0, + 26100.0, + 26055.0, + 26200.0, + 26083.0, + 26173.0, + 26158.0, + 26200.0, + 26279.0, + 26160.0, + 26119.0, + 26132.0, + 26340.0, + 26535.0, + 26451.0, + 24551.0, + 25010.0, + 25158.0, + 25005.0, + 25207.0, + 25443.0, + 25420.0, + 25450.0, + 25447.0, + 25207.0, + 26296.0, + 26075.0, + 26216.0, + 26042.0, + 26145.0, + 26121.0, + 26102.0, + 26157.0, + 26130.0, + 26149.0, + 25769.0, + 25967.0, + 26064.0, + 25672.0, + 25921.0, + 25508.0, + 25596.0, + 25615.0, + 25686.0, + 25588.0, + 25622.0, + 25596.0, + 25581.0, + 25679.0, + 25719.0, + 25604.0, + 25323.0, + 25562.0, + 25570.0, + 25708.0, + 25618.0, + 25631.0, + 25619.0, + 25740.0, + 25940.0, + 26165.0, + 25902.0, + 25922.0, + 25908.0, + 25911.0, + 25968.0, + 25864.0, + 25901.0, + 25725.0, + 25873.0, + 25956.0, + 25886.0, + 25697.0, + 24973.0, + 25000.0, + 25003.0, + 25180.0, + 25140.0, + 25062.0, + 24966.0, + 24972.0, + 24920.0, + 24880.0, + 25012.0, + 24832.0, + 24911.0, + 24798.0, + 25268.0, + 25063.0, + 25187.0, + 25230.0, + 25256.0, + 25449.0, + 25892.0, + 26044.0, + 26073.0, + 26175.0, + 26240.0, + 26018.0, + 26198.0, + 26089.0, + 26155.0, + 26185.0, + 26256.0, + 26394.0, + 26493.0, + 26341.0, + 26343.0, + 26122.0, + 25999.0, + 25579.0, + 25686.0, + 25775.0, + 25760.0, + 25833.0, + 25871.0, + 25757.0, + 25510.0, + 25596.0, + 25714.0, + 26017.0, + 26194.0, + 26113.0, + 26237.0, + 26269.0, + 26233.0, + 26388.0, + 26302.0, + 26327.0, + 26207.0, + 26231.0, + 26200.0, + 26205.0, + 26212.0, + 26192.0, + 26161.0, + 26296.0, + 26234.0, + 26211.0, + 26245.0, + 26259.0, + 26195.0, + 26216.0, + 26156.0, + 26103.0, + 25979.0, + 26061.0, + 25837.0, + 25868.0, + 26082.0, + 25668.0, + 25756.0, + 25701.0, + 25796.0, + 26128.0, + 25984.0, + 25986.0, + 25810.0, + 25745.0, + 25793.0, + 25448.0, + 25507.0, + 25520.0, + 25656.0, + 25644.0, + 25662.0, + 25828.0, + 25942.0, + 25753.0, + 25622.0, + 25790.0, + 25746.0, + 25782.0, + 25711.0, + 26066.0, + 26029.0, + 26100.0, + 26041.0, + 26044.0, + 26108.0, + 25987.0, + 25718.0, + 25755.0, + 25926.0, + 25856.0, + 25857.0, + 25780.0, + 25855.0, + 25766.0, + 25615.0, + 25593.0, + 25630.0, + 25624.0, + 25717.0, + 25674.0, + 25714.0, + 25678.0, + 25715.0, + 25735.0, + 25722.0, + 25672.0, + 25535.0, + 25571.0, + 25534.0, + 25673.0, + 25662.0, + 25632.0, + 25622.0, + 25600.0, + 25629.0, + 25638.0, + 25731.0, + 25818.0, + 25812.0, + 25741.0, + 25754.0, + 25742.0, + 25722.0, + 25689.0, + 25634.0, + 25658.0, + 25685.0, + 25821.0, + 25787.0, + 25750.0, + 25650.0, + 25651.0, + 25677.0, + 25665.0, + 25650.0, + 25644.0, + 25811.0, + 26090.0, + 25952.0, + 25970.0, + 25961.0, + 25989.0, + 25967.0, + 25980.0, + 26034.0, + 26011.0, + 26236.0, + 26837.0, + 26853.0, + 26889.0, + 27264.0, + 27668.0, + 27647.0, + 27387.0, + 27615.0, + 27545.0, + 27537.0, + 27687.0, + 27700.0, + 27678.0, + 27620.0, + 27692.0, + 27652.0, + 27649.0, + 27414.0, + 27382.0, + 27452.0, + 27490.0, + 27503.0, + 27405.0, + 27317.0, + 27316.0, + 27102.0, + 27258.0, + 27179.0, + 27357.0, + 27379.0, + 27419.0, + 27368.0, + 27413.0, + 27410.0, + 27334.0, + 27567.0, + 27580.0, + 27513.0, + 27451.0, + 27541.0, + 27842.0, + 27730.0, + 27847.0, + 27799.0, + 27854.0, + 27905.0, + 27890.0, + 27554.0, + 27586.0, + 27617.0, + 27730.0, + 27706.0, + 27639.0, + 27639.0, + 27696.0, + 27717.0, + 27748.0, + 27665.0, + 27640.0, + 27610.0, + 27570.0, + 27621.0, + 27576.0, + 27577.0, + 27544.0, + 27611.0, + 27652.0, + 27583.0, + 27548.0, + 27541.0, + 27616.0, + 27585.0, + 27594.0, + 27659.0, + 27625.0, + 27336.0, + 27340.0, + 27321.0, + 27134.0, + 27243.0, + 26973.0, + 26894.0, + 26923.0, + 27003.0, + 27039.0, + 27020.0, + 26978.0, + 26955.0, + 26998.0, + 27100.0, + 27212.0, + 27258.0, + 27680.0, + 27715.0, + 27550.0, + 27389.0, + 27583.0, + 27689.0, + 27691.0, + 27575.0, + 27552.0, + 27635.0, + 27457.0, + 26751.0, + 26844.0, + 26801.0, + 26747.0, + 26790.0, + 26703.0, + 26641.0, + 26343.0, + 26409.0, + 26364.0, + 26383.0, + 26358.0, + 26342.0, + 26113.0, + 26275.0, + 25972.0, + 25955.0, + 25644.0, + 25750.0, + 25757.0, + 25734.0, + 25831.0, + 25681.0, + 25693.0, + 25630.0, + 25552.0, + 25657.0, + 25557.0, + 25403.0, + 24834.0, + 24833.0, + 24793.0, + 24831.0, + 24842.0, + 24951.0, + 24860.0, + 24829.0, + 24880.0, + 24895.0, + 25104.0, + 25341.0, + 25250.0, + 25330.0, + 25503.0, + 25182.0, + 25148.0, + 25238.0, + 25399.0, + 25320.0, + 25280.0, + 25267.0, + 25084.0, + 25131.0, + 25092.0, + 25063.0, + 25136.0, + 25267.0, + 25326.0, + 25247.0, + 24979.0, + 24839.0, + 25034.0, + 25067.0, + 24732.0, + 24800.0, + 24810.0, + 24824.0, + 24876.0, + 24792.0, + 24727.0, + 24794.0, + 24712.0, + 24763.0, + 24869.0, + 24859.0, + 24937.0, + 25203.0, + 25197.0, + 25782.0, + 25795.0, + 25844.0, + 25800.0, + 25868.0, + 25763.0, + 26157.0, + 26188.0, + 26910.0, + 26986.0, + 26920.0, + 25365.0, + 25999.0, + 25735.0, + 26034.0, + 26162.0, + 26324.0, + 26180.0, + 26239.0, + 26238.0, + 26273.0, + 26463.0, + 26576.0, + 26888.0, + 26879.0, + 26735.0, + 26777.0, + 26686.0, + 26781.0, + 26792.0, + 26587.0, + 26678.0, + 26404.0, + 26426.0, + 26547.0, + 26617.0, + 26620.0, + 26588.0, + 26576.0, + 26646.0, + 26659.0, + 26657.0, + 26586.0, + 26619.0, + 26701.0, + 26595.0, + 26486.0, + 26561.0, + 26546.0, + 26529.0, + 26425.0, + 26481.0, + 26568.0, + 26579.0, + 26556.0, + 26514.0, + 26580.0, + 26920.0, + 26887.0, + 26667.0, + 26703.0, + 26526.0, + 25946.0, + 25963.0, + 25913.0, + 26039.0, + 25944.0, + 25948.0, + 25865.0, + 25717.0, + 25801.0, + 25397.0, + 25548.0, + 25603.0, + 25503.0, + 25586.0, + 25521.0, + 25538.0, + 25559.0, + 25630.0, + 25583.0, + 25980.0, + 26003.0, + 26062.0, + 26053.0, + 26032.0, + 25883.0, + 25869.0, + 25860.0, + 25981.0, + 25971.0, + 25874.0, + 25732.0, + 25645.0, + 25847.0, + 25656.0, + 26152.0, + 26182.0, + 26226.0, + 26246.0, + 26373.0, + 26262.0, + 26316.0, + 26338.0, + 26102.0, + 26257.0, + 26161.0, + 26241.0, + 26207.0, + 26161.0, + 26548.0, + 26434.0, + 26453.0, + 26344.0, + 26396.0, + 26462.0, + 26565.0, + 26642.0, + 26763.0, + 26817.0, + 26762.0, + 26783.0, + 26837.0, + 26658.0, + 26631.0, + 26673.0, + 26626.0, + 26609.0, + 26316.0, + 26007.0, + 26198.0, + 26253.0, + 26220.0, + 26256.0, + 26236.0, + 26211.0, + 26233.0, + 26308.0, + 26205.0, + 26229.0, + 26275.0, + 26322.0, + 26291.0, + 26322.0, + 26137.0, + 25868.0, + 25639.0, + 25606.0, + 25659.0, + 25382.0, + 25359.0, + 25358.0, + 25264.0, + 25340.0, + 25106.0, + 24889.0, + 25039.0, + 25197.0, + 25263.0, + 25174.0, + 25067.0, + 25221.0, + 25121.0, + 25272.0, + 25223.0, + 25045.0, + 25213.0, + 25280.0, + 25189.0, + 25217.0, + 25265.0, + 25238.0, + 25255.0, + 25137.0, + 25159.0, + 25275.0, + 25666.0, + 25683.0, + 25093.0, + 25231.0, + 25082.0, + 25156.0, + 25094.0, + 25024.0, + 25106.0, + 25130.0, + 25106.0, + 25080.0, + 24931.0, + 24904.0, + 24687.0, + 24600.0, + 24729.0, + 24748.0, + 24606.0, + 24327.0, + 24084.0, + 24127.0, + 24202.0, + 24214.0, + 24309.0, + 24254.0, + 24234.0, + 24397.0, + 24691.0, + 24695.0, + 24743.0, + 24725.0, + 24662.0, + 24689.0, + 24759.0, + 24731.0, + 24741.0, + 24746.0, + 24745.0, + 24782.0, + 24797.0, + 24708.0, + 24614.0, + 24784.0, + 24746.0, + 24748.0, + 24767.0, + 24714.0, + 24817.0, + 24959.0, + 24847.0, + 24777.0, + 24790.0, + 24825.0, + 25053.0, + 25082.0, + 25170.0, + 25208.0, + 25223.0, + 25152.0, + 25175.0, + 25200.0, + 25284.0, + 25209.0, + 25173.0, + 24984.0, + 24835.0, + 24945.0, + 24893.0, + 25048.0, + 24865.0, + 24854.0, + 24810.0, + 24886.0, + 24923.0, + 24802.0, + 24857.0, + 24888.0, + 24991.0, + 24912.0, + 24851.0, + 24781.0, + 24817.0, + 24600.0, + 24623.0, + 24753.0, + 25009.0, + 25263.0, + 25228.0, + 25260.0, + 25182.0, + 25225.0, + 25119.0, + 25317.0, + 25332.0, + 25322.0, + 25285.0, + 25115.0, + 24611.0, + 24827.0, + 24977.0, + 24893.0, + 24909.0, + 24925.0, + 24942.0, + 24921.0, + 24855.0, + 24865.0, + 24903.0, + 24864.0, + 24875.0, + 24849.0, + 24910.0, + 24878.0, + 24870.0, + 24869.0, + 24876.0, + 24864.0, + 24899.0, + 24893.0, + 24889.0, + 24954.0, + 25120.0, + 25044.0, + 25024.0, + 25089.0, + 25114.0, + 25151.0, + 25077.0, + 25022.0, + 25028.0, + 24836.0, + 24873.0, + 24889.0, + 24858.0, + 24901.0, + 24763.0, + 24711.0, + 24589.0, + 24635.0, + 24762.0, + 24845.0, + 24821.0, + 24798.0, + 24977.0, + 24880.0, + 24831.0, + 24820.0, + 24884.0, + 24842.0, + 24970.0, + 25304.0, + 25360.0, + 25258.0, + 25282.0, + 25359.0, + 25253.0, + 25352.0, + 25229.0, + 25251.0, + 25225.0, + 25274.0, + 25203.0, + 24840.0, + 24837.0, + 24742.0, + 24829.0, + 24819.0, + 24579.0, + 24458.0, + 24438.0, + 24407.0, + 24537.0, + 24500.0, + 24311.0, + 24435.0, + 24525.0, + 24399.0, + 24500.0, + 24518.0, + 24589.0, + 24441.0, + 24566.0, + 24675.0, + 24689.0, + 24695.0, + 24615.0, + 24631.0, + 24545.0, + 24674.0, + 24652.0, + 24619.0, + 24734.0, + 24965.0, + 24909.0, + 24954.0, + 24911.0, + 24910.0, + 24894.0, + 24957.0, + 24909.0, + 24926.0, + 24910.0, + 24908.0, + 24844.0, + 24893.0, + 24945.0, + 24933.0, + 24953.0, + 25047.0, + 25238.0, + 25322.0, + 25309.0, + 25346.0, + 25292.0, + 25300.0, + 25301.0, + 25402.0, + 25470.0, + 25627.0, + 25948.0, + 26162.0, + 26245.0, + 26038.0, + 26053.0, + 26006.0, + 26053.0, + 26056.0, + 26035.0, + 25780.0, + 25856.0, + 25800.0, + 25837.0, + 25915.0, + 25893.0, + 25973.0, + 25960.0, + 25951.0, + 26001.0, + 26092.0, + 25921.0, + 25811.0, + 25866.0, + 25956.0, + 25835.0, + 25820.0, + 25904.0, + 25850.0, + 25332.0, + 25452.0, + 25431.0, + 25389.0, + 25380.0, + 25278.0, + 25388.0, + 25292.0, + 25350.0, + 25469.0, + 25358.0 + ], + "type": "scatter", + "xaxis": "x2", + "yaxis": "y2" + }, + { + "line": { + "color": "blue", + "width": 1 + }, + "mode": "lines", + "name": "Close side ways", + "x": [ + "2022-06-10 02:00:00", + "2022-06-10 04:00:00", + "2022-06-10 06:00:00", + "2022-06-10 08:00:00", + "2022-06-10 10:00:00", + "2022-06-10 12:00:00", + "2022-06-10 14:00:00", + "2022-06-10 16:00:00", + "2022-06-10 18:00:00", + "2022-06-10 20:00:00", + "2022-06-10 22:00:00", + "2022-06-11 00:00:00", + "2022-06-11 02:00:00", + "2022-06-11 04:00:00", + "2022-06-11 06:00:00", + "2022-06-11 08:00:00", + "2022-06-11 10:00:00", + "2022-06-11 12:00:00", + "2022-06-11 14:00:00", + "2022-06-11 16:00:00", + "2022-06-11 18:00:00", + "2022-06-11 20:00:00", + "2022-06-11 22:00:00", + "2022-06-12 00:00:00", + "2022-06-12 02:00:00", + "2022-06-12 04:00:00", + "2022-06-12 06:00:00", + "2022-06-12 08:00:00", + "2022-06-12 10:00:00", + "2022-06-12 12:00:00", + "2022-06-12 14:00:00", + "2022-06-12 16:00:00", + "2022-06-12 18:00:00", + "2022-06-12 20:00:00", + "2022-06-12 22:00:00", + "2022-06-13 00:00:00", + "2022-06-13 02:00:00", + "2022-06-13 04:00:00", + "2022-06-13 06:00:00", + "2022-06-13 08:00:00", + "2022-06-13 10:00:00", + "2022-06-13 12:00:00", + "2022-06-13 14:00:00", + "2022-06-13 16:00:00", + "2022-06-13 18:00:00", + "2022-06-13 20:00:00", + "2022-06-13 22:00:00", + "2022-06-14 00:00:00", + "2022-06-14 02:00:00", + "2022-06-14 04:00:00", + "2022-06-14 06:00:00", + "2022-06-14 08:00:00", + "2022-06-14 10:00:00", + "2022-06-14 12:00:00", + "2022-06-14 14:00:00", + "2022-06-14 16:00:00", + "2022-06-14 18:00:00", + "2022-06-14 20:00:00", + "2022-06-14 22:00:00", + "2022-06-15 00:00:00", + "2022-06-15 02:00:00", + "2022-06-15 04:00:00", + "2022-06-15 06:00:00", + "2022-06-15 08:00:00", + "2022-06-15 10:00:00", + "2022-06-15 12:00:00", + "2022-06-15 14:00:00", + "2022-06-15 16:00:00", + "2022-06-15 18:00:00", + "2022-06-15 20:00:00", + "2022-06-15 22:00:00", + "2022-06-16 00:00:00", + "2022-06-16 02:00:00", + "2022-06-16 04:00:00", + "2022-06-16 06:00:00", + "2022-06-16 08:00:00", + "2022-06-16 10:00:00", + "2022-06-16 12:00:00", + "2022-06-16 14:00:00", + "2022-06-16 16:00:00", + "2022-06-16 18:00:00", + "2022-06-16 20:00:00", + "2022-06-16 22:00:00", + "2022-06-17 00:00:00", + "2022-06-17 02:00:00", + "2022-06-17 04:00:00", + "2022-06-17 06:00:00", + "2022-06-17 08:00:00", + "2022-06-17 10:00:00", + "2022-06-17 12:00:00", + "2022-06-17 14:00:00", + "2022-06-17 16:00:00", + "2022-06-17 18:00:00", + "2022-06-17 20:00:00", + "2022-06-17 22:00:00", + "2022-06-18 00:00:00", + "2022-06-18 02:00:00", + "2022-06-18 04:00:00", + "2022-06-18 06:00:00", + "2022-06-18 08:00:00", + "2022-06-18 10:00:00", + "2022-06-18 12:00:00", + "2022-06-18 14:00:00", + "2022-06-18 16:00:00", + "2022-06-18 18:00:00", + "2022-06-18 20:00:00", + "2022-06-18 22:00:00", + "2022-06-19 00:00:00", + "2022-06-19 02:00:00", + "2022-06-19 04:00:00", + "2022-06-19 06:00:00", + "2022-06-19 08:00:00", + "2022-06-19 10:00:00", + "2022-06-19 12:00:00", + "2022-06-19 14:00:00", + "2022-06-19 16:00:00", + "2022-06-19 18:00:00", + "2022-06-19 20:00:00", + "2022-06-19 22:00:00", + "2022-06-20 00:00:00", + "2022-06-20 02:00:00", + "2022-06-20 04:00:00", + "2022-06-20 06:00:00", + "2022-06-20 08:00:00", + "2022-06-20 10:00:00", + "2022-06-20 12:00:00", + "2022-06-20 14:00:00", + "2022-06-20 16:00:00", + "2022-06-20 18:00:00", + "2022-06-20 20:00:00", + "2022-06-20 22:00:00", + "2022-06-21 00:00:00", + "2022-06-21 02:00:00", + "2022-06-21 04:00:00", + "2022-06-21 06:00:00", + "2022-06-21 08:00:00", + "2022-06-21 10:00:00", + "2022-06-21 12:00:00", + "2022-06-21 14:00:00", + "2022-06-21 16:00:00", + "2022-06-21 18:00:00", + "2022-06-21 20:00:00", + "2022-06-21 22:00:00", + "2022-06-22 00:00:00", + "2022-06-22 02:00:00", + "2022-06-22 04:00:00", + "2022-06-22 06:00:00", + "2022-06-22 08:00:00", + "2022-06-22 10:00:00", + "2022-06-22 12:00:00", + "2022-06-22 14:00:00", + "2022-06-22 16:00:00", + "2022-06-22 18:00:00", + "2022-06-22 20:00:00", + "2022-06-22 22:00:00", + "2022-06-23 00:00:00", + "2022-06-23 02:00:00", + "2022-06-23 04:00:00", + "2022-06-23 06:00:00", + "2022-06-23 08:00:00", + "2022-06-23 10:00:00", + "2022-06-23 12:00:00", + "2022-06-23 14:00:00", + "2022-06-23 16:00:00", + "2022-06-23 18:00:00", + "2022-06-23 20:00:00", + "2022-06-23 22:00:00", + "2022-06-24 00:00:00", + "2022-06-24 02:00:00", + "2022-06-24 04:00:00", + "2022-06-24 06:00:00", + "2022-06-24 08:00:00", + "2022-06-24 10:00:00", + "2022-06-24 12:00:00", + "2022-06-24 14:00:00", + "2022-06-24 16:00:00", + "2022-06-24 18:00:00", + "2022-06-24 20:00:00", + "2022-06-24 22:00:00", + "2022-06-25 00:00:00", + "2022-06-25 02:00:00", + "2022-06-25 04:00:00", + "2022-06-25 06:00:00", + "2022-06-25 08:00:00", + "2022-06-25 10:00:00", + "2022-06-25 12:00:00", + "2022-06-25 14:00:00", + "2022-06-25 16:00:00", + "2022-06-25 18:00:00", + "2022-06-25 20:00:00", + "2022-06-25 22:00:00", + "2022-06-26 00:00:00", + "2022-06-26 02:00:00", + "2022-06-26 04:00:00", + "2022-06-26 06:00:00", + "2022-06-26 08:00:00", + "2022-06-26 10:00:00", + "2022-06-26 12:00:00", + "2022-06-26 14:00:00", + "2022-06-26 16:00:00", + "2022-06-26 18:00:00", + "2022-06-26 20:00:00", + "2022-06-26 22:00:00", + "2022-06-27 00:00:00", + "2022-06-27 02:00:00", + "2022-06-27 04:00:00", + "2022-06-27 06:00:00", + "2022-06-27 08:00:00", + "2022-06-27 10:00:00", + "2022-06-27 12:00:00", + "2022-06-27 14:00:00", + "2022-06-27 16:00:00", + "2022-06-27 18:00:00", + "2022-06-27 20:00:00", + "2022-06-27 22:00:00", + "2022-06-28 00:00:00", + "2022-06-28 02:00:00", + "2022-06-28 04:00:00", + "2022-06-28 06:00:00", + "2022-06-28 08:00:00", + "2022-06-28 10:00:00", + "2022-06-28 12:00:00", + "2022-06-28 14:00:00", + "2022-06-28 16:00:00", + "2022-06-28 18:00:00", + "2022-06-28 20:00:00", + "2022-06-28 22:00:00", + "2022-06-29 00:00:00", + "2022-06-29 02:00:00", + "2022-06-29 04:00:00", + "2022-06-29 06:00:00", + "2022-06-29 08:00:00", + "2022-06-29 10:00:00", + "2022-06-29 12:00:00", + "2022-06-29 14:00:00", + "2022-06-29 16:00:00", + "2022-06-29 18:00:00", + "2022-06-29 20:00:00", + "2022-06-29 22:00:00", + "2022-06-30 00:00:00", + "2022-06-30 02:00:00", + "2022-06-30 04:00:00", + "2022-06-30 06:00:00", + "2022-06-30 08:00:00", + "2022-06-30 10:00:00", + "2022-06-30 12:00:00", + "2022-06-30 14:00:00", + "2022-06-30 16:00:00", + "2022-06-30 18:00:00", + "2022-06-30 20:00:00", + "2022-06-30 22:00:00", + "2022-07-01 00:00:00", + "2022-07-01 02:00:00", + "2022-07-01 04:00:00", + "2022-07-01 06:00:00", + "2022-07-01 08:00:00", + "2022-07-01 10:00:00", + "2022-07-01 12:00:00", + "2022-07-01 14:00:00", + "2022-07-01 16:00:00", + "2022-07-01 18:00:00", + "2022-07-01 20:00:00", + "2022-07-01 22:00:00", + "2022-07-02 00:00:00", + "2022-07-02 02:00:00", + "2022-07-02 04:00:00", + "2022-07-02 06:00:00", + "2022-07-02 08:00:00", + "2022-07-02 10:00:00", + "2022-07-02 12:00:00", + "2022-07-02 14:00:00", + "2022-07-02 16:00:00", + "2022-07-02 18:00:00", + "2022-07-02 20:00:00", + "2022-07-02 22:00:00", + "2022-07-03 00:00:00", + "2022-07-03 02:00:00", + "2022-07-03 04:00:00", + "2022-07-03 06:00:00", + "2022-07-03 08:00:00", + "2022-07-03 10:00:00", + "2022-07-03 12:00:00", + "2022-07-03 14:00:00", + "2022-07-03 16:00:00", + "2022-07-03 18:00:00", + "2022-07-03 20:00:00", + "2022-07-03 22:00:00", + "2022-07-04 00:00:00", + "2022-07-04 02:00:00", + "2022-07-04 04:00:00", + "2022-07-04 06:00:00", + "2022-07-04 08:00:00", + "2022-07-04 10:00:00", + "2022-07-04 12:00:00", + "2022-07-04 14:00:00", + "2022-07-04 16:00:00", + "2022-07-04 18:00:00", + "2022-07-04 20:00:00", + "2022-07-04 22:00:00", + "2022-07-05 00:00:00", + "2022-07-05 02:00:00", + "2022-07-05 04:00:00", + "2022-07-05 06:00:00", + "2022-07-05 08:00:00", + "2022-07-05 10:00:00", + "2022-07-05 12:00:00", + "2022-07-05 14:00:00", + "2022-07-05 16:00:00", + "2022-07-05 18:00:00", + "2022-07-05 20:00:00", + "2022-07-05 22:00:00", + "2022-07-06 00:00:00", + "2022-07-06 02:00:00", + "2022-07-06 04:00:00", + "2022-07-06 06:00:00", + "2022-07-06 08:00:00", + "2022-07-06 10:00:00", + "2022-07-06 12:00:00", + "2022-07-06 14:00:00", + "2022-07-06 16:00:00", + "2022-07-06 18:00:00", + "2022-07-06 20:00:00", + "2022-07-06 22:00:00", + "2022-07-07 00:00:00", + "2022-07-07 02:00:00", + "2022-07-07 04:00:00", + "2022-07-07 06:00:00", + "2022-07-07 08:00:00", + "2022-07-07 10:00:00", + "2022-07-07 12:00:00", + "2022-07-07 14:00:00", + "2022-07-07 16:00:00", + "2022-07-07 18:00:00", + "2022-07-07 20:00:00", + "2022-07-07 22:00:00", + "2022-07-08 00:00:00", + "2022-07-08 02:00:00", + "2022-07-08 04:00:00", + "2022-07-08 06:00:00", + "2022-07-08 08:00:00", + "2022-07-08 10:00:00", + "2022-07-08 12:00:00", + "2022-07-08 14:00:00", + "2022-07-08 16:00:00", + "2022-07-08 18:00:00", + "2022-07-08 20:00:00", + "2022-07-08 22:00:00", + "2022-07-09 00:00:00", + "2022-07-09 02:00:00", + "2022-07-09 04:00:00", + "2022-07-09 06:00:00", + "2022-07-09 08:00:00", + "2022-07-09 10:00:00", + "2022-07-09 12:00:00", + "2022-07-09 14:00:00", + "2022-07-09 16:00:00", + "2022-07-09 18:00:00", + "2022-07-09 20:00:00", + "2022-07-09 22:00:00", + "2022-07-10 00:00:00", + "2022-07-10 02:00:00", + "2022-07-10 04:00:00", + "2022-07-10 06:00:00", + "2022-07-10 08:00:00", + "2022-07-10 10:00:00", + "2022-07-10 12:00:00", + "2022-07-10 14:00:00", + "2022-07-10 16:00:00", + "2022-07-10 18:00:00", + "2022-07-10 20:00:00", + "2022-07-10 22:00:00", + "2022-07-11 00:00:00", + "2022-07-11 02:00:00", + "2022-07-11 04:00:00", + "2022-07-11 06:00:00", + "2022-07-11 08:00:00", + "2022-07-11 10:00:00", + "2022-07-11 12:00:00", + "2022-07-11 14:00:00", + "2022-07-11 16:00:00", + "2022-07-11 18:00:00", + "2022-07-11 20:00:00", + "2022-07-11 22:00:00", + "2022-07-12 00:00:00", + "2022-07-12 02:00:00", + "2022-07-12 04:00:00", + "2022-07-12 06:00:00", + "2022-07-12 08:00:00", + "2022-07-12 10:00:00", + "2022-07-12 12:00:00", + "2022-07-12 14:00:00", + "2022-07-12 16:00:00", + "2022-07-12 18:00:00", + "2022-07-12 20:00:00", + "2022-07-12 22:00:00", + "2022-07-13 00:00:00", + "2022-07-13 02:00:00", + "2022-07-13 04:00:00", + "2022-07-13 06:00:00", + "2022-07-13 08:00:00", + "2022-07-13 10:00:00", + "2022-07-13 12:00:00", + "2022-07-13 14:00:00", + "2022-07-13 16:00:00", + "2022-07-13 18:00:00", + "2022-07-13 20:00:00", + "2022-07-13 22:00:00", + "2022-07-14 00:00:00", + "2022-07-14 02:00:00", + "2022-07-14 04:00:00", + "2022-07-14 06:00:00", + "2022-07-14 08:00:00", + "2022-07-14 10:00:00", + "2022-07-14 12:00:00", + "2022-07-14 14:00:00", + "2022-07-14 16:00:00", + "2022-07-14 18:00:00", + "2022-07-14 20:00:00", + "2022-07-14 22:00:00", + "2022-07-15 00:00:00", + "2022-07-15 02:00:00", + "2022-07-15 04:00:00", + "2022-07-15 06:00:00", + "2022-07-15 08:00:00", + "2022-07-15 10:00:00", + "2022-07-15 12:00:00", + "2022-07-15 14:00:00", + "2022-07-15 16:00:00", + "2022-07-15 18:00:00", + "2022-07-15 20:00:00", + "2022-07-15 22:00:00", + "2022-07-16 00:00:00", + "2022-07-16 02:00:00", + "2022-07-16 04:00:00", + "2022-07-16 06:00:00", + "2022-07-16 08:00:00", + "2022-07-16 10:00:00", + "2022-07-16 12:00:00", + "2022-07-16 14:00:00", + "2022-07-16 16:00:00", + "2022-07-16 18:00:00", + "2022-07-16 20:00:00", + "2022-07-16 22:00:00", + "2022-07-17 00:00:00", + "2022-07-17 02:00:00", + "2022-07-17 04:00:00", + "2022-07-17 06:00:00", + "2022-07-17 08:00:00", + "2022-07-17 10:00:00", + "2022-07-17 12:00:00", + "2022-07-17 14:00:00", + "2022-07-17 16:00:00", + "2022-07-17 18:00:00", + "2022-07-17 20:00:00", + "2022-07-17 22:00:00", + "2022-07-18 00:00:00", + "2022-07-18 02:00:00", + "2022-07-18 04:00:00", + "2022-07-18 06:00:00", + "2022-07-18 08:00:00", + "2022-07-18 10:00:00", + "2022-07-18 12:00:00", + "2022-07-18 14:00:00", + "2022-07-18 16:00:00", + "2022-07-18 18:00:00", + "2022-07-18 20:00:00", + "2022-07-18 22:00:00", + "2022-07-19 00:00:00", + "2022-07-19 02:00:00", + "2022-07-19 04:00:00", + "2022-07-19 06:00:00", + "2022-07-19 08:00:00", + "2022-07-19 10:00:00", + "2022-07-19 12:00:00", + "2022-07-19 14:00:00", + "2022-07-19 16:00:00", + "2022-07-19 18:00:00", + "2022-07-19 20:00:00", + "2022-07-19 22:00:00", + "2022-07-20 00:00:00", + "2022-07-20 02:00:00", + "2022-07-20 04:00:00", + "2022-07-20 06:00:00", + "2022-07-20 08:00:00", + "2022-07-20 10:00:00", + "2022-07-20 12:00:00", + "2022-07-20 14:00:00", + "2022-07-20 16:00:00", + "2022-07-20 18:00:00", + "2022-07-20 20:00:00", + "2022-07-20 22:00:00", + "2022-07-21 00:00:00", + "2022-07-21 02:00:00", + "2022-07-21 04:00:00", + "2022-07-21 06:00:00", + "2022-07-21 08:00:00", + "2022-07-21 10:00:00", + "2022-07-21 12:00:00", + "2022-07-21 14:00:00", + "2022-07-21 16:00:00", + "2022-07-21 18:00:00", + "2022-07-21 20:00:00", + "2022-07-21 22:00:00", + "2022-07-22 00:00:00", + "2022-07-22 02:00:00", + "2022-07-22 04:00:00", + "2022-07-22 06:00:00", + "2022-07-22 08:00:00", + "2022-07-22 10:00:00", + "2022-07-22 12:00:00", + "2022-07-22 14:00:00", + "2022-07-22 16:00:00", + "2022-07-22 18:00:00", + "2022-07-22 20:00:00", + "2022-07-22 22:00:00", + "2022-07-23 00:00:00", + "2022-07-23 02:00:00", + "2022-07-23 04:00:00", + "2022-07-23 06:00:00", + "2022-07-23 08:00:00", + "2022-07-23 10:00:00", + "2022-07-23 12:00:00", + "2022-07-23 14:00:00", + "2022-07-23 16:00:00", + "2022-07-23 18:00:00", + "2022-07-23 20:00:00", + "2022-07-23 22:00:00", + "2022-07-24 00:00:00", + "2022-07-24 02:00:00", + "2022-07-24 04:00:00", + "2022-07-24 06:00:00", + "2022-07-24 08:00:00", + "2022-07-24 10:00:00", + "2022-07-24 12:00:00", + "2022-07-24 14:00:00", + "2022-07-24 16:00:00", + "2022-07-24 18:00:00", + "2022-07-24 20:00:00", + "2022-07-24 22:00:00", + "2022-07-25 00:00:00", + "2022-07-25 02:00:00", + "2022-07-25 04:00:00", + "2022-07-25 06:00:00", + "2022-07-25 08:00:00", + "2022-07-25 10:00:00", + "2022-07-25 12:00:00", + "2022-07-25 14:00:00", + "2022-07-25 16:00:00", + "2022-07-25 18:00:00", + "2022-07-25 20:00:00", + "2022-07-25 22:00:00", + "2022-07-26 00:00:00", + "2022-07-26 02:00:00", + "2022-07-26 04:00:00", + "2022-07-26 06:00:00", + "2022-07-26 08:00:00", + "2022-07-26 10:00:00", + "2022-07-26 12:00:00", + "2022-07-26 14:00:00", + "2022-07-26 16:00:00", + "2022-07-26 18:00:00", + "2022-07-26 20:00:00", + "2022-07-26 22:00:00", + "2022-07-27 00:00:00", + "2022-07-27 02:00:00", + "2022-07-27 04:00:00", + "2022-07-27 06:00:00", + "2022-07-27 08:00:00", + "2022-07-27 10:00:00", + "2022-07-27 12:00:00", + "2022-07-27 14:00:00", + "2022-07-27 16:00:00", + "2022-07-27 18:00:00", + "2022-07-27 20:00:00", + "2022-07-27 22:00:00", + "2022-07-28 00:00:00", + "2022-07-28 02:00:00", + "2022-07-28 04:00:00", + "2022-07-28 06:00:00", + "2022-07-28 08:00:00", + "2022-07-28 10:00:00", + "2022-07-28 12:00:00", + "2022-07-28 14:00:00", + "2022-07-28 16:00:00", + "2022-07-28 18:00:00", + "2022-07-28 20:00:00", + "2022-07-28 22:00:00", + "2022-07-29 00:00:00", + "2022-07-29 02:00:00", + "2022-07-29 04:00:00", + "2022-07-29 06:00:00", + "2022-07-29 08:00:00", + "2022-07-29 10:00:00", + "2022-07-29 12:00:00", + "2022-07-29 14:00:00", + "2022-07-29 16:00:00", + "2022-07-29 18:00:00", + "2022-07-29 20:00:00", + "2022-07-29 22:00:00", + "2022-07-30 00:00:00", + "2022-07-30 02:00:00", + "2022-07-30 04:00:00", + "2022-07-30 06:00:00", + "2022-07-30 08:00:00", + "2022-07-30 10:00:00", + "2022-07-30 12:00:00", + "2022-07-30 14:00:00", + "2022-07-30 16:00:00", + "2022-07-30 18:00:00", + "2022-07-30 20:00:00", + "2022-07-30 22:00:00", + "2022-07-31 00:00:00", + "2022-07-31 02:00:00", + "2022-07-31 04:00:00", + "2022-07-31 06:00:00", + "2022-07-31 08:00:00", + "2022-07-31 10:00:00", + "2022-07-31 12:00:00", + "2022-07-31 14:00:00", + "2022-07-31 16:00:00", + "2022-07-31 18:00:00", + "2022-07-31 20:00:00", + "2022-07-31 22:00:00", + "2022-08-01 00:00:00", + "2022-08-01 02:00:00", + "2022-08-01 04:00:00", + "2022-08-01 06:00:00", + "2022-08-01 08:00:00", + "2022-08-01 10:00:00", + "2022-08-01 12:00:00", + "2022-08-01 14:00:00", + "2022-08-01 16:00:00", + "2022-08-01 18:00:00", + "2022-08-01 20:00:00", + "2022-08-01 22:00:00", + "2022-08-02 00:00:00", + "2022-08-02 02:00:00", + "2022-08-02 04:00:00", + "2022-08-02 06:00:00", + "2022-08-02 08:00:00", + "2022-08-02 10:00:00", + "2022-08-02 12:00:00", + "2022-08-02 14:00:00", + "2022-08-02 16:00:00", + "2022-08-02 18:00:00", + "2022-08-02 20:00:00", + "2022-08-02 22:00:00", + "2022-08-03 00:00:00", + "2022-08-03 02:00:00", + "2022-08-03 04:00:00", + "2022-08-03 06:00:00", + "2022-08-03 08:00:00", + "2022-08-03 10:00:00", + "2022-08-03 12:00:00", + "2022-08-03 14:00:00", + "2022-08-03 16:00:00", + "2022-08-03 18:00:00", + "2022-08-03 20:00:00", + "2022-08-03 22:00:00", + "2022-08-04 00:00:00", + "2022-08-04 02:00:00", + "2022-08-04 04:00:00", + "2022-08-04 06:00:00", + "2022-08-04 08:00:00", + "2022-08-04 10:00:00", + "2022-08-04 12:00:00", + "2022-08-04 14:00:00", + "2022-08-04 16:00:00", + "2022-08-04 18:00:00", + "2022-08-04 20:00:00", + "2022-08-04 22:00:00", + "2022-08-05 00:00:00", + "2022-08-05 02:00:00", + "2022-08-05 04:00:00", + "2022-08-05 06:00:00", + "2022-08-05 08:00:00", + "2022-08-05 10:00:00", + "2022-08-05 12:00:00", + "2022-08-05 14:00:00", + "2022-08-05 16:00:00", + "2022-08-05 18:00:00", + "2022-08-05 20:00:00", + "2022-08-05 22:00:00", + "2022-08-06 00:00:00", + "2022-08-06 02:00:00", + "2022-08-06 04:00:00", + "2022-08-06 06:00:00", + "2022-08-06 08:00:00", + "2022-08-06 10:00:00", + "2022-08-06 12:00:00", + "2022-08-06 14:00:00", + "2022-08-06 16:00:00", + "2022-08-06 18:00:00", + "2022-08-06 20:00:00", + "2022-08-06 22:00:00", + "2022-08-07 00:00:00", + "2022-08-07 02:00:00", + "2022-08-07 04:00:00", + "2022-08-07 06:00:00", + "2022-08-07 08:00:00", + "2022-08-07 10:00:00", + "2022-08-07 12:00:00", + "2022-08-07 14:00:00", + "2022-08-07 16:00:00", + "2022-08-07 18:00:00", + "2022-08-07 20:00:00", + "2022-08-07 22:00:00", + "2022-08-08 00:00:00", + "2022-08-08 02:00:00", + "2022-08-08 04:00:00", + "2022-08-08 06:00:00", + "2022-08-08 08:00:00", + "2022-08-08 10:00:00", + "2022-08-08 12:00:00", + "2022-08-08 14:00:00", + "2022-08-08 16:00:00", + "2022-08-08 18:00:00", + "2022-08-08 20:00:00", + "2022-08-08 22:00:00", + "2022-08-09 00:00:00", + "2022-08-09 02:00:00", + "2022-08-09 04:00:00", + "2022-08-09 06:00:00", + "2022-08-09 08:00:00", + "2022-08-09 10:00:00", + "2022-08-09 12:00:00", + "2022-08-09 14:00:00", + "2022-08-09 16:00:00", + "2022-08-09 18:00:00", + "2022-08-09 20:00:00", + "2022-08-09 22:00:00", + "2022-08-10 00:00:00", + "2022-08-10 02:00:00", + "2022-08-10 04:00:00", + "2022-08-10 06:00:00", + "2022-08-10 08:00:00", + "2022-08-10 10:00:00", + "2022-08-10 12:00:00", + "2022-08-10 14:00:00", + "2022-08-10 16:00:00", + "2022-08-10 18:00:00", + "2022-08-10 20:00:00", + "2022-08-10 22:00:00", + "2022-08-11 00:00:00", + "2022-08-11 02:00:00", + "2022-08-11 04:00:00", + "2022-08-11 06:00:00", + "2022-08-11 08:00:00", + "2022-08-11 10:00:00", + "2022-08-11 12:00:00", + "2022-08-11 14:00:00", + "2022-08-11 16:00:00", + "2022-08-11 18:00:00", + "2022-08-11 20:00:00", + "2022-08-11 22:00:00", + "2022-08-12 00:00:00", + "2022-08-12 02:00:00", + "2022-08-12 04:00:00", + "2022-08-12 06:00:00", + "2022-08-12 08:00:00", + "2022-08-12 10:00:00", + "2022-08-12 12:00:00", + "2022-08-12 14:00:00", + "2022-08-12 16:00:00", + "2022-08-12 18:00:00", + "2022-08-12 20:00:00", + "2022-08-12 22:00:00", + "2022-08-13 00:00:00", + "2022-08-13 02:00:00", + "2022-08-13 04:00:00", + "2022-08-13 06:00:00", + "2022-08-13 08:00:00", + "2022-08-13 10:00:00", + "2022-08-13 12:00:00", + "2022-08-13 14:00:00", + "2022-08-13 16:00:00", + "2022-08-13 18:00:00", + "2022-08-13 20:00:00", + "2022-08-13 22:00:00", + "2022-08-14 00:00:00", + "2022-08-14 02:00:00", + "2022-08-14 04:00:00", + "2022-08-14 06:00:00", + "2022-08-14 08:00:00", + "2022-08-14 10:00:00", + "2022-08-14 12:00:00", + "2022-08-14 14:00:00", + "2022-08-14 16:00:00", + "2022-08-14 18:00:00", + "2022-08-14 20:00:00", + "2022-08-14 22:00:00", + "2022-08-15 00:00:00", + "2022-08-15 02:00:00", + "2022-08-15 04:00:00", + "2022-08-15 06:00:00", + "2022-08-15 08:00:00", + "2022-08-15 10:00:00", + "2022-08-15 12:00:00", + "2022-08-15 14:00:00", + "2022-08-15 16:00:00", + "2022-08-15 18:00:00", + "2022-08-15 20:00:00", + "2022-08-15 22:00:00", + "2022-08-16 00:00:00", + "2022-08-16 02:00:00", + "2022-08-16 04:00:00", + "2022-08-16 06:00:00", + "2022-08-16 08:00:00", + "2022-08-16 10:00:00", + "2022-08-16 12:00:00", + "2022-08-16 14:00:00", + "2022-08-16 16:00:00", + "2022-08-16 18:00:00", + "2022-08-16 20:00:00", + "2022-08-16 22:00:00", + "2022-08-17 00:00:00", + "2022-08-17 02:00:00", + "2022-08-17 04:00:00", + "2022-08-17 06:00:00", + "2022-08-17 08:00:00", + "2022-08-17 10:00:00", + "2022-08-17 12:00:00", + "2022-08-17 14:00:00", + "2022-08-17 16:00:00", + "2022-08-17 18:00:00", + "2022-08-17 20:00:00", + "2022-08-17 22:00:00", + "2022-08-18 00:00:00", + "2022-08-18 02:00:00", + "2022-08-18 04:00:00", + "2022-08-18 06:00:00", + "2022-08-18 08:00:00", + "2022-08-18 10:00:00", + "2022-08-18 12:00:00", + "2022-08-18 14:00:00", + "2022-08-18 16:00:00", + "2022-08-18 18:00:00", + "2022-08-18 20:00:00", + "2022-08-18 22:00:00", + "2022-08-19 00:00:00", + "2022-08-19 02:00:00", + "2022-08-19 04:00:00", + "2022-08-19 06:00:00", + "2022-08-19 08:00:00", + "2022-08-19 10:00:00", + "2022-08-19 12:00:00", + "2022-08-19 14:00:00", + "2022-08-19 16:00:00", + "2022-08-19 18:00:00", + "2022-08-19 20:00:00", + "2022-08-19 22:00:00", + "2022-08-20 00:00:00", + "2022-08-20 02:00:00", + "2022-08-20 04:00:00", + "2022-08-20 06:00:00", + "2022-08-20 08:00:00", + "2022-08-20 10:00:00", + "2022-08-20 12:00:00", + "2022-08-20 14:00:00", + "2022-08-20 16:00:00", + "2022-08-20 18:00:00", + "2022-08-20 20:00:00", + "2022-08-20 22:00:00", + "2022-08-21 00:00:00", + "2022-08-21 02:00:00", + "2022-08-21 04:00:00", + "2022-08-21 06:00:00", + "2022-08-21 08:00:00", + "2022-08-21 10:00:00", + "2022-08-21 12:00:00", + "2022-08-21 14:00:00", + "2022-08-21 16:00:00", + "2022-08-21 18:00:00", + "2022-08-21 20:00:00", + "2022-08-21 22:00:00", + "2022-08-22 00:00:00", + "2022-08-22 02:00:00", + "2022-08-22 04:00:00", + "2022-08-22 06:00:00", + "2022-08-22 08:00:00", + "2022-08-22 10:00:00", + "2022-08-22 12:00:00", + "2022-08-22 14:00:00", + "2022-08-22 16:00:00", + "2022-08-22 18:00:00", + "2022-08-22 20:00:00", + "2022-08-22 22:00:00", + "2022-08-23 00:00:00", + "2022-08-23 02:00:00", + "2022-08-23 04:00:00", + "2022-08-23 06:00:00", + "2022-08-23 08:00:00", + "2022-08-23 10:00:00", + "2022-08-23 12:00:00", + "2022-08-23 14:00:00", + "2022-08-23 16:00:00", + "2022-08-23 18:00:00", + "2022-08-23 20:00:00", + "2022-08-23 22:00:00", + "2022-08-24 00:00:00", + "2022-08-24 02:00:00", + "2022-08-24 04:00:00", + "2022-08-24 06:00:00", + "2022-08-24 08:00:00", + "2022-08-24 10:00:00", + "2022-08-24 12:00:00", + "2022-08-24 14:00:00", + "2022-08-24 16:00:00", + "2022-08-24 18:00:00", + "2022-08-24 20:00:00", + "2022-08-24 22:00:00", + "2022-08-25 00:00:00", + "2022-08-25 02:00:00", + "2022-08-25 04:00:00", + "2022-08-25 06:00:00", + "2022-08-25 08:00:00", + "2022-08-25 10:00:00", + "2022-08-25 12:00:00", + "2022-08-25 14:00:00", + "2022-08-25 16:00:00", + "2022-08-25 18:00:00", + "2022-08-25 20:00:00", + "2022-08-25 22:00:00", + "2022-08-26 00:00:00", + "2022-08-26 02:00:00", + "2022-08-26 04:00:00", + "2022-08-26 06:00:00", + "2022-08-26 08:00:00", + "2022-08-26 10:00:00", + "2022-08-26 12:00:00", + "2022-08-26 14:00:00", + "2022-08-26 16:00:00", + "2022-08-26 18:00:00", + "2022-08-26 20:00:00", + "2022-08-26 22:00:00", + "2022-08-27 00:00:00", + "2022-08-27 02:00:00", + "2022-08-27 04:00:00", + "2022-08-27 06:00:00", + "2022-08-27 08:00:00", + "2022-08-27 10:00:00", + "2022-08-27 12:00:00", + "2022-08-27 14:00:00", + "2022-08-27 16:00:00", + "2022-08-27 18:00:00", + "2022-08-27 20:00:00", + "2022-08-27 22:00:00", + "2022-08-28 00:00:00", + "2022-08-28 02:00:00", + "2022-08-28 04:00:00", + "2022-08-28 06:00:00", + "2022-08-28 08:00:00", + "2022-08-28 10:00:00", + "2022-08-28 12:00:00", + "2022-08-28 14:00:00", + "2022-08-28 16:00:00", + "2022-08-28 18:00:00", + "2022-08-28 20:00:00", + "2022-08-28 22:00:00", + "2022-08-29 00:00:00", + "2022-08-29 02:00:00", + "2022-08-29 04:00:00", + "2022-08-29 06:00:00", + "2022-08-29 08:00:00", + "2022-08-29 10:00:00", + "2022-08-29 12:00:00", + "2022-08-29 14:00:00", + "2022-08-29 16:00:00", + "2022-08-29 18:00:00", + "2022-08-29 20:00:00", + "2022-08-29 22:00:00", + "2022-08-30 00:00:00", + "2022-08-30 02:00:00", + "2022-08-30 04:00:00", + "2022-08-30 06:00:00", + "2022-08-30 08:00:00", + "2022-08-30 10:00:00", + "2022-08-30 12:00:00", + "2022-08-30 14:00:00", + "2022-08-30 16:00:00", + "2022-08-30 18:00:00", + "2022-08-30 20:00:00", + "2022-08-30 22:00:00", + "2022-08-31 00:00:00", + "2022-08-31 02:00:00", + "2022-08-31 04:00:00", + "2022-08-31 06:00:00", + "2022-08-31 08:00:00", + "2022-08-31 10:00:00", + "2022-08-31 12:00:00", + "2022-08-31 14:00:00", + "2022-08-31 16:00:00", + "2022-08-31 18:00:00", + "2022-08-31 20:00:00", + "2022-08-31 22:00:00", + "2022-09-01 00:00:00", + "2022-09-01 02:00:00", + "2022-09-01 04:00:00", + "2022-09-01 06:00:00", + "2022-09-01 08:00:00", + "2022-09-01 10:00:00", + "2022-09-01 12:00:00", + "2022-09-01 14:00:00", + "2022-09-01 16:00:00", + "2022-09-01 18:00:00", + "2022-09-01 20:00:00", + "2022-09-01 22:00:00", + "2022-09-02 00:00:00", + "2022-09-02 02:00:00", + "2022-09-02 04:00:00", + "2022-09-02 06:00:00", + "2022-09-02 08:00:00", + "2022-09-02 10:00:00", + "2022-09-02 12:00:00", + "2022-09-02 14:00:00", + "2022-09-02 16:00:00", + "2022-09-02 18:00:00", + "2022-09-02 20:00:00", + "2022-09-02 22:00:00", + "2022-09-03 00:00:00", + "2022-09-03 02:00:00", + "2022-09-03 04:00:00", + "2022-09-03 06:00:00", + "2022-09-03 08:00:00", + "2022-09-03 10:00:00", + "2022-09-03 12:00:00", + "2022-09-03 14:00:00", + "2022-09-03 16:00:00", + "2022-09-03 18:00:00", + "2022-09-03 20:00:00", + "2022-09-03 22:00:00", + "2022-09-04 00:00:00", + "2022-09-04 02:00:00", + "2022-09-04 04:00:00", + "2022-09-04 06:00:00", + "2022-09-04 08:00:00", + "2022-09-04 10:00:00", + "2022-09-04 12:00:00", + "2022-09-04 14:00:00", + "2022-09-04 16:00:00", + "2022-09-04 18:00:00", + "2022-09-04 20:00:00", + "2022-09-04 22:00:00", + "2022-09-05 00:00:00", + "2022-09-05 02:00:00", + "2022-09-05 04:00:00", + "2022-09-05 06:00:00", + "2022-09-05 08:00:00", + "2022-09-05 10:00:00", + "2022-09-05 12:00:00", + "2022-09-05 14:00:00", + "2022-09-05 16:00:00", + "2022-09-05 18:00:00", + "2022-09-05 20:00:00", + "2022-09-05 22:00:00", + "2022-09-06 00:00:00", + "2022-09-06 02:00:00", + "2022-09-06 04:00:00", + "2022-09-06 06:00:00", + "2022-09-06 08:00:00", + "2022-09-06 10:00:00", + "2022-09-06 12:00:00", + "2022-09-06 14:00:00", + "2022-09-06 16:00:00", + "2022-09-06 18:00:00", + "2022-09-06 20:00:00", + "2022-09-06 22:00:00", + "2022-09-07 00:00:00", + "2022-09-07 02:00:00", + "2022-09-07 04:00:00", + "2022-09-07 06:00:00", + "2022-09-07 08:00:00", + "2022-09-07 10:00:00", + "2022-09-07 12:00:00", + "2022-09-07 14:00:00", + "2022-09-07 16:00:00", + "2022-09-07 18:00:00", + "2022-09-07 20:00:00", + "2022-09-07 22:00:00", + "2022-09-08 00:00:00", + "2022-09-08 02:00:00", + "2022-09-08 04:00:00", + "2022-09-08 06:00:00", + "2022-09-08 08:00:00", + "2022-09-08 10:00:00", + "2022-09-08 12:00:00", + "2022-09-08 14:00:00", + "2022-09-08 16:00:00", + "2022-09-08 18:00:00", + "2022-09-08 20:00:00", + "2022-09-08 22:00:00", + "2022-09-09 00:00:00", + "2022-09-09 02:00:00", + "2022-09-09 04:00:00", + "2022-09-09 06:00:00", + "2022-09-09 08:00:00", + "2022-09-09 10:00:00", + "2022-09-09 12:00:00", + "2022-09-09 14:00:00", + "2022-09-09 16:00:00", + "2022-09-09 18:00:00", + "2022-09-09 20:00:00", + "2022-09-09 22:00:00", + "2022-09-10 00:00:00", + "2022-09-10 02:00:00", + "2022-09-10 04:00:00", + "2022-09-10 06:00:00", + "2022-09-10 08:00:00", + "2022-09-10 10:00:00", + "2022-09-10 12:00:00", + "2022-09-10 14:00:00", + "2022-09-10 16:00:00", + "2022-09-10 18:00:00", + "2022-09-10 20:00:00", + "2022-09-10 22:00:00", + "2022-09-11 00:00:00", + "2022-09-11 02:00:00", + "2022-09-11 04:00:00", + "2022-09-11 06:00:00", + "2022-09-11 08:00:00", + "2022-09-11 10:00:00", + "2022-09-11 12:00:00", + "2022-09-11 14:00:00", + "2022-09-11 16:00:00", + "2022-09-11 18:00:00", + "2022-09-11 20:00:00", + "2022-09-11 22:00:00", + "2022-09-12 00:00:00", + "2022-09-12 02:00:00", + "2022-09-12 04:00:00", + "2022-09-12 06:00:00", + "2022-09-12 08:00:00", + "2022-09-12 10:00:00", + "2022-09-12 12:00:00", + "2022-09-12 14:00:00", + "2022-09-12 16:00:00", + "2022-09-12 18:00:00", + "2022-09-12 20:00:00", + "2022-09-12 22:00:00", + "2022-09-13 00:00:00", + "2022-09-13 02:00:00", + "2022-09-13 04:00:00", + "2022-09-13 06:00:00", + "2022-09-13 08:00:00", + "2022-09-13 10:00:00", + "2022-09-13 12:00:00", + "2022-09-13 14:00:00", + "2022-09-13 16:00:00", + "2022-09-13 18:00:00", + "2022-09-13 20:00:00", + "2022-09-13 22:00:00", + "2022-09-14 00:00:00", + "2022-09-14 02:00:00", + "2022-09-14 04:00:00", + "2022-09-14 06:00:00", + "2022-09-14 08:00:00", + "2022-09-14 10:00:00", + "2022-09-14 12:00:00", + "2022-09-14 14:00:00", + "2022-09-14 16:00:00", + "2022-09-14 18:00:00", + "2022-09-14 20:00:00", + "2022-09-14 22:00:00", + "2022-09-15 00:00:00", + "2022-09-15 02:00:00", + "2022-09-15 04:00:00", + "2022-09-15 06:00:00", + "2022-09-15 08:00:00", + "2022-09-15 10:00:00", + "2022-09-15 12:00:00", + "2022-09-15 14:00:00", + "2022-09-15 16:00:00", + "2022-09-15 18:00:00", + "2022-09-15 20:00:00", + "2022-09-15 22:00:00", + "2022-09-16 00:00:00", + "2022-09-16 02:00:00", + "2022-09-16 04:00:00", + "2022-09-16 06:00:00", + "2022-09-16 08:00:00", + "2022-09-16 10:00:00", + "2022-09-16 12:00:00", + "2022-09-16 14:00:00", + "2022-09-16 16:00:00", + "2022-09-16 18:00:00", + "2022-09-16 20:00:00", + "2022-09-16 22:00:00", + "2022-09-17 00:00:00", + "2022-09-17 02:00:00", + "2022-09-17 04:00:00", + "2022-09-17 06:00:00", + "2022-09-17 08:00:00", + "2022-09-17 10:00:00", + "2022-09-17 12:00:00", + "2022-09-17 14:00:00", + "2022-09-17 16:00:00", + "2022-09-17 18:00:00", + "2022-09-17 20:00:00", + "2022-09-17 22:00:00", + "2022-09-18 00:00:00", + "2022-09-18 02:00:00", + "2022-09-18 04:00:00", + "2022-09-18 06:00:00", + "2022-09-18 08:00:00", + "2022-09-18 10:00:00", + "2022-09-18 12:00:00", + "2022-09-18 14:00:00", + "2022-09-18 16:00:00", + "2022-09-18 18:00:00", + "2022-09-18 20:00:00", + "2022-09-18 22:00:00", + "2022-09-19 00:00:00", + "2022-09-19 02:00:00", + "2022-09-19 04:00:00", + "2022-09-19 06:00:00", + "2022-09-19 08:00:00", + "2022-09-19 10:00:00", + "2022-09-19 12:00:00", + "2022-09-19 14:00:00", + "2022-09-19 16:00:00", + "2022-09-19 18:00:00", + "2022-09-19 20:00:00", + "2022-09-19 22:00:00", + "2022-09-20 00:00:00", + "2022-09-20 02:00:00", + "2022-09-20 04:00:00", + "2022-09-20 06:00:00", + "2022-09-20 08:00:00", + "2022-09-20 10:00:00", + "2022-09-20 12:00:00", + "2022-09-20 14:00:00", + "2022-09-20 16:00:00", + "2022-09-20 18:00:00", + "2022-09-20 20:00:00", + "2022-09-20 22:00:00", + "2022-09-21 00:00:00", + "2022-09-21 02:00:00", + "2022-09-21 04:00:00", + "2022-09-21 06:00:00", + "2022-09-21 08:00:00", + "2022-09-21 10:00:00", + "2022-09-21 12:00:00", + "2022-09-21 14:00:00", + "2022-09-21 16:00:00", + "2022-09-21 18:00:00", + "2022-09-21 20:00:00", + "2022-09-21 22:00:00", + "2022-09-22 00:00:00", + "2022-09-22 02:00:00", + "2022-09-22 04:00:00", + "2022-09-22 06:00:00", + "2022-09-22 08:00:00", + "2022-09-22 10:00:00", + "2022-09-22 12:00:00", + "2022-09-22 14:00:00", + "2022-09-22 16:00:00", + "2022-09-22 18:00:00", + "2022-09-22 20:00:00", + "2022-09-22 22:00:00", + "2022-09-23 00:00:00", + "2022-09-23 02:00:00", + "2022-09-23 04:00:00", + "2022-09-23 06:00:00", + "2022-09-23 08:00:00", + "2022-09-23 10:00:00", + "2022-09-23 12:00:00", + "2022-09-23 14:00:00", + "2022-09-23 16:00:00", + "2022-09-23 18:00:00", + "2022-09-23 20:00:00", + "2022-09-23 22:00:00", + "2022-09-24 00:00:00", + "2022-09-24 02:00:00", + "2022-09-24 04:00:00", + "2022-09-24 06:00:00", + "2022-09-24 08:00:00", + "2022-09-24 10:00:00", + "2022-09-24 12:00:00", + "2022-09-24 14:00:00", + "2022-09-24 16:00:00", + "2022-09-24 18:00:00", + "2022-09-24 20:00:00", + "2022-09-24 22:00:00", + "2022-09-25 00:00:00", + "2022-09-25 02:00:00", + "2022-09-25 04:00:00", + "2022-09-25 06:00:00", + "2022-09-25 08:00:00", + "2022-09-25 10:00:00", + "2022-09-25 12:00:00", + "2022-09-25 14:00:00", + "2022-09-25 16:00:00", + "2022-09-25 18:00:00", + "2022-09-25 20:00:00", + "2022-09-25 22:00:00", + "2022-09-26 00:00:00", + "2022-09-26 02:00:00", + "2022-09-26 04:00:00", + "2022-09-26 06:00:00", + "2022-09-26 08:00:00", + "2022-09-26 10:00:00", + "2022-09-26 12:00:00", + "2022-09-26 14:00:00", + "2022-09-26 16:00:00", + "2022-09-26 18:00:00", + "2022-09-26 20:00:00", + "2022-09-26 22:00:00", + "2022-09-27 00:00:00", + "2022-09-27 02:00:00", + "2022-09-27 04:00:00", + "2022-09-27 06:00:00", + "2022-09-27 08:00:00", + "2022-09-27 10:00:00", + "2022-09-27 12:00:00", + "2022-09-27 14:00:00", + "2022-09-27 16:00:00", + "2022-09-27 18:00:00", + "2022-09-27 20:00:00", + "2022-09-27 22:00:00", + "2022-09-28 00:00:00", + "2022-09-28 02:00:00", + "2022-09-28 04:00:00", + "2022-09-28 06:00:00", + "2022-09-28 08:00:00", + "2022-09-28 10:00:00", + "2022-09-28 12:00:00", + "2022-09-28 14:00:00", + "2022-09-28 16:00:00", + "2022-09-28 18:00:00", + "2022-09-28 20:00:00", + "2022-09-28 22:00:00", + "2022-09-29 00:00:00", + "2022-09-29 02:00:00", + "2022-09-29 04:00:00", + "2022-09-29 06:00:00", + "2022-09-29 08:00:00", + "2022-09-29 10:00:00", + "2022-09-29 12:00:00", + "2022-09-29 14:00:00", + "2022-09-29 16:00:00", + "2022-09-29 18:00:00", + "2022-09-29 20:00:00", + "2022-09-29 22:00:00", + "2022-09-30 00:00:00", + "2022-09-30 02:00:00", + "2022-09-30 04:00:00", + "2022-09-30 06:00:00", + "2022-09-30 08:00:00", + "2022-09-30 10:00:00", + "2022-09-30 12:00:00", + "2022-09-30 14:00:00", + "2022-09-30 16:00:00", + "2022-09-30 18:00:00", + "2022-09-30 20:00:00", + "2022-09-30 22:00:00", + "2022-10-01 00:00:00", + "2022-10-01 02:00:00", + "2022-10-01 04:00:00", + "2022-10-01 06:00:00", + "2022-10-01 08:00:00", + "2022-10-01 10:00:00", + "2022-10-01 12:00:00", + "2022-10-01 14:00:00", + "2022-10-01 16:00:00", + "2022-10-01 18:00:00", + "2022-10-01 20:00:00", + "2022-10-01 22:00:00", + "2022-10-02 00:00:00", + "2022-10-02 02:00:00", + "2022-10-02 04:00:00", + "2022-10-02 06:00:00", + "2022-10-02 08:00:00", + "2022-10-02 10:00:00", + "2022-10-02 12:00:00", + "2022-10-02 14:00:00", + "2022-10-02 16:00:00", + "2022-10-02 18:00:00", + "2022-10-02 20:00:00", + "2022-10-02 22:00:00", + "2022-10-03 00:00:00", + "2022-10-03 02:00:00", + "2022-10-03 04:00:00", + "2022-10-03 06:00:00", + "2022-10-03 08:00:00", + "2022-10-03 10:00:00", + "2022-10-03 12:00:00", + "2022-10-03 14:00:00", + "2022-10-03 16:00:00", + "2022-10-03 18:00:00", + "2022-10-03 20:00:00", + "2022-10-03 22:00:00", + "2022-10-04 00:00:00", + "2022-10-04 02:00:00", + "2022-10-04 04:00:00", + "2022-10-04 06:00:00", + "2022-10-04 08:00:00", + "2022-10-04 10:00:00", + "2022-10-04 12:00:00", + "2022-10-04 14:00:00", + "2022-10-04 16:00:00", + "2022-10-04 18:00:00", + "2022-10-04 20:00:00", + "2022-10-04 22:00:00", + "2022-10-05 00:00:00", + "2022-10-05 02:00:00", + "2022-10-05 04:00:00", + "2022-10-05 06:00:00", + "2022-10-05 08:00:00", + "2022-10-05 10:00:00", + "2022-10-05 12:00:00", + "2022-10-05 14:00:00", + "2022-10-05 16:00:00", + "2022-10-05 18:00:00", + "2022-10-05 20:00:00", + "2022-10-05 22:00:00", + "2022-10-06 00:00:00", + "2022-10-06 02:00:00", + "2022-10-06 04:00:00", + "2022-10-06 06:00:00", + "2022-10-06 08:00:00", + "2022-10-06 10:00:00", + "2022-10-06 12:00:00", + "2022-10-06 14:00:00", + "2022-10-06 16:00:00", + "2022-10-06 18:00:00", + "2022-10-06 20:00:00", + "2022-10-06 22:00:00", + "2022-10-07 00:00:00", + "2022-10-07 02:00:00", + "2022-10-07 04:00:00", + "2022-10-07 06:00:00", + "2022-10-07 08:00:00", + "2022-10-07 10:00:00", + "2022-10-07 12:00:00", + "2022-10-07 14:00:00", + "2022-10-07 16:00:00", + "2022-10-07 18:00:00", + "2022-10-07 20:00:00", + "2022-10-07 22:00:00", + "2022-10-08 00:00:00", + "2022-10-08 04:00:00", + "2022-10-08 06:00:00", + "2022-10-08 08:00:00", + "2022-10-08 10:00:00", + "2022-10-08 12:00:00", + "2022-10-08 14:00:00", + "2022-10-08 16:00:00", + "2022-10-08 18:00:00", + "2022-10-08 20:00:00", + "2022-10-08 22:00:00", + "2022-10-09 00:00:00", + "2022-10-09 02:00:00", + "2022-10-09 04:00:00", + "2022-10-09 06:00:00", + "2022-10-09 08:00:00", + "2022-10-09 10:00:00", + "2022-10-09 12:00:00", + "2022-10-09 14:00:00", + "2022-10-09 16:00:00", + "2022-10-09 18:00:00", + "2022-10-09 20:00:00", + "2022-10-09 22:00:00", + "2022-10-10 00:00:00", + "2022-10-10 02:00:00", + "2022-10-10 04:00:00", + "2022-10-10 06:00:00", + "2022-10-10 08:00:00", + "2022-10-10 10:00:00", + "2022-10-10 12:00:00", + "2022-10-10 14:00:00", + "2022-10-10 16:00:00", + "2022-10-10 18:00:00", + "2022-10-10 20:00:00", + "2022-10-10 22:00:00", + "2022-10-11 00:00:00", + "2022-10-11 02:00:00", + "2022-10-11 04:00:00", + "2022-10-11 06:00:00", + "2022-10-11 08:00:00", + "2022-10-11 10:00:00", + "2022-10-11 12:00:00", + "2022-10-11 14:00:00", + "2022-10-11 16:00:00", + "2022-10-11 18:00:00", + "2022-10-11 20:00:00", + "2022-10-11 22:00:00", + "2022-10-12 00:00:00", + "2022-10-12 02:00:00", + "2022-10-12 04:00:00", + "2022-10-12 06:00:00", + "2022-10-12 08:00:00", + "2022-10-12 10:00:00", + "2022-10-12 12:00:00", + "2022-10-12 14:00:00", + "2022-10-12 16:00:00", + "2022-10-12 18:00:00", + "2022-10-12 20:00:00", + "2022-10-12 22:00:00", + "2022-10-13 00:00:00", + "2022-10-13 02:00:00", + "2022-10-13 04:00:00", + "2022-10-13 06:00:00", + "2022-10-13 08:00:00", + "2022-10-13 10:00:00", + "2022-10-13 12:00:00", + "2022-10-13 14:00:00", + "2022-10-13 16:00:00", + "2022-10-13 18:00:00", + "2022-10-13 20:00:00", + "2022-10-13 22:00:00", + "2022-10-14 00:00:00", + "2022-10-14 02:00:00", + "2022-10-14 04:00:00", + "2022-10-14 06:00:00", + "2022-10-14 08:00:00", + "2022-10-14 10:00:00", + "2022-10-14 12:00:00", + "2022-10-14 14:00:00", + "2022-10-14 16:00:00", + "2022-10-14 18:00:00", + "2022-10-14 20:00:00", + "2022-10-14 22:00:00", + "2022-10-15 00:00:00", + "2022-10-15 02:00:00", + "2022-10-15 04:00:00", + "2022-10-15 06:00:00", + "2022-10-15 08:00:00", + "2022-10-15 10:00:00", + "2022-10-15 12:00:00", + "2022-10-15 14:00:00", + "2022-10-15 16:00:00", + "2022-10-15 18:00:00", + "2022-10-15 20:00:00", + "2022-10-15 22:00:00", + "2022-10-16 00:00:00", + "2022-10-16 02:00:00", + "2022-10-16 04:00:00", + "2022-10-16 06:00:00", + "2022-10-16 08:00:00", + "2022-10-16 10:00:00", + "2022-10-16 12:00:00", + "2022-10-16 14:00:00", + "2022-10-16 16:00:00", + "2022-10-16 18:00:00", + "2022-10-16 20:00:00", + "2022-10-16 22:00:00", + "2022-10-17 00:00:00", + "2022-10-17 02:00:00", + "2022-10-17 04:00:00", + "2022-10-17 06:00:00", + "2022-10-17 08:00:00", + "2022-10-17 10:00:00", + "2022-10-17 12:00:00", + "2022-10-17 14:00:00", + "2022-10-17 16:00:00", + "2022-10-17 18:00:00", + "2022-10-17 20:00:00", + "2022-10-17 22:00:00", + "2022-10-18 00:00:00", + "2022-10-18 02:00:00", + "2022-10-18 04:00:00", + "2022-10-18 06:00:00", + "2022-10-18 08:00:00", + "2022-10-18 10:00:00", + "2022-10-18 12:00:00", + "2022-10-18 14:00:00", + "2022-10-18 16:00:00", + "2022-10-18 18:00:00", + "2022-10-18 20:00:00", + "2022-10-18 22:00:00", + "2022-10-19 00:00:00", + "2022-10-19 02:00:00", + "2022-10-19 04:00:00", + "2022-10-19 06:00:00", + "2022-10-19 08:00:00", + "2022-10-19 10:00:00", + "2022-10-19 12:00:00", + "2022-10-19 14:00:00", + "2022-10-19 16:00:00", + "2022-10-19 18:00:00", + "2022-10-19 20:00:00", + "2022-10-19 22:00:00", + "2022-10-20 00:00:00", + "2022-10-20 02:00:00", + "2022-10-20 04:00:00", + "2022-10-20 06:00:00", + "2022-10-20 08:00:00", + "2022-10-20 10:00:00", + "2022-10-20 12:00:00", + "2022-10-20 14:00:00", + "2022-10-20 16:00:00", + "2022-10-20 18:00:00", + "2022-10-20 20:00:00", + "2022-10-20 22:00:00", + "2022-10-21 00:00:00", + "2022-10-21 02:00:00", + "2022-10-21 04:00:00", + "2022-10-21 06:00:00", + "2022-10-21 08:00:00", + "2022-10-21 10:00:00", + "2022-10-21 12:00:00", + "2022-10-21 14:00:00", + "2022-10-21 16:00:00", + "2022-10-21 18:00:00", + "2022-10-21 20:00:00", + "2022-10-21 22:00:00", + "2022-10-22 00:00:00", + "2022-10-22 02:00:00", + "2022-10-22 04:00:00", + "2022-10-22 06:00:00", + "2022-10-22 08:00:00", + "2022-10-22 10:00:00", + "2022-10-22 12:00:00", + "2022-10-22 14:00:00", + "2022-10-22 16:00:00", + "2022-10-22 18:00:00", + "2022-10-22 20:00:00", + "2022-10-22 22:00:00", + "2022-10-23 00:00:00", + "2022-10-23 02:00:00", + "2022-10-23 04:00:00", + "2022-10-23 06:00:00", + "2022-10-23 08:00:00", + "2022-10-23 10:00:00", + "2022-10-23 12:00:00", + "2022-10-23 14:00:00", + "2022-10-23 16:00:00", + "2022-10-23 18:00:00", + "2022-10-23 20:00:00", + "2022-10-23 22:00:00", + "2022-10-24 00:00:00", + "2022-10-24 02:00:00", + "2022-10-24 04:00:00", + "2022-10-24 06:00:00", + "2022-10-24 08:00:00", + "2022-10-24 10:00:00", + "2022-10-24 12:00:00", + "2022-10-24 14:00:00", + "2022-10-24 16:00:00", + "2022-10-24 18:00:00", + "2022-10-24 20:00:00", + "2022-10-24 22:00:00", + "2022-10-25 00:00:00", + "2022-10-25 02:00:00", + "2022-10-25 04:00:00", + "2022-10-25 06:00:00", + "2022-10-25 08:00:00", + "2022-10-25 10:00:00", + "2022-10-25 12:00:00", + "2022-10-25 14:00:00", + "2022-10-25 16:00:00", + "2022-10-25 18:00:00", + "2022-10-25 20:00:00", + "2022-10-25 22:00:00", + "2022-10-26 00:00:00", + "2022-10-26 02:00:00", + "2022-10-26 04:00:00", + "2022-10-26 06:00:00", + "2022-10-26 08:00:00", + "2022-10-26 10:00:00", + "2022-10-26 12:00:00", + "2022-10-26 14:00:00", + "2022-10-26 16:00:00", + "2022-10-26 18:00:00", + "2022-10-26 20:00:00", + "2022-10-26 22:00:00", + "2022-10-27 00:00:00", + "2022-10-27 02:00:00", + "2022-10-27 04:00:00", + "2022-10-27 06:00:00", + "2022-10-27 08:00:00", + "2022-10-27 10:00:00", + "2022-10-27 12:00:00", + "2022-10-27 14:00:00", + "2022-10-27 16:00:00", + "2022-10-27 18:00:00", + "2022-10-27 20:00:00", + "2022-10-27 22:00:00", + "2022-10-28 00:00:00", + "2022-10-28 02:00:00", + "2022-10-28 04:00:00", + "2022-10-28 06:00:00", + "2022-10-28 08:00:00", + "2022-10-28 10:00:00", + "2022-10-28 12:00:00", + "2022-10-28 14:00:00", + "2022-10-28 16:00:00", + "2022-10-28 18:00:00", + "2022-10-28 20:00:00", + "2022-10-28 22:00:00", + "2022-10-29 00:00:00", + "2022-10-29 02:00:00", + "2022-10-29 04:00:00", + "2022-10-29 06:00:00", + "2022-10-29 08:00:00", + "2022-10-29 10:00:00", + "2022-10-29 12:00:00", + "2022-10-29 14:00:00", + "2022-10-29 16:00:00", + "2022-10-29 18:00:00", + "2022-10-29 20:00:00", + "2022-10-29 22:00:00", + "2022-10-30 00:00:00", + "2022-10-30 02:00:00", + "2022-10-30 04:00:00", + "2022-10-30 06:00:00", + "2022-10-30 08:00:00", + "2022-10-30 10:00:00", + "2022-10-30 12:00:00", + "2022-10-30 14:00:00", + "2022-10-30 16:00:00", + "2022-10-30 18:00:00", + "2022-10-30 20:00:00", + "2022-10-30 22:00:00", + "2022-10-31 00:00:00", + "2022-10-31 02:00:00", + "2022-10-31 04:00:00", + "2022-10-31 06:00:00", + "2022-10-31 08:00:00", + "2022-10-31 10:00:00", + "2022-10-31 12:00:00", + "2022-10-31 14:00:00", + "2022-10-31 16:00:00", + "2022-10-31 18:00:00", + "2022-10-31 20:00:00", + "2022-10-31 22:00:00", + "2022-11-01 00:00:00", + "2022-11-01 02:00:00", + "2022-11-01 04:00:00", + "2022-11-01 06:00:00", + "2022-11-01 08:00:00", + "2022-11-01 10:00:00", + "2022-11-01 12:00:00", + "2022-11-01 14:00:00", + "2022-11-01 16:00:00", + "2022-11-01 18:00:00", + "2022-11-01 20:00:00", + "2022-11-01 22:00:00", + "2022-11-02 00:00:00", + "2022-11-02 02:00:00", + "2022-11-02 04:00:00", + "2022-11-02 06:00:00", + "2022-11-02 08:00:00", + "2022-11-02 10:00:00", + "2022-11-02 12:00:00", + "2022-11-02 14:00:00", + "2022-11-02 16:00:00", + "2022-11-02 18:00:00", + "2022-11-02 20:00:00", + "2022-11-02 22:00:00", + "2022-11-03 00:00:00", + "2022-11-03 02:00:00", + "2022-11-03 04:00:00", + "2022-11-03 06:00:00", + "2022-11-03 08:00:00", + "2022-11-03 10:00:00", + "2022-11-03 12:00:00", + "2022-11-03 14:00:00", + "2022-11-03 16:00:00", + "2022-11-03 18:00:00", + "2022-11-03 20:00:00", + "2022-11-03 22:00:00", + "2022-11-04 00:00:00", + "2022-11-04 02:00:00", + "2022-11-04 04:00:00", + "2022-11-04 06:00:00", + "2022-11-04 08:00:00", + "2022-11-04 10:00:00", + "2022-11-04 12:00:00", + "2022-11-04 14:00:00", + "2022-11-04 16:00:00", + "2022-11-04 18:00:00", + "2022-11-04 20:00:00", + "2022-11-04 22:00:00", + "2022-11-05 00:00:00", + "2022-11-05 02:00:00", + "2022-11-05 04:00:00", + "2022-11-05 06:00:00", + "2022-11-05 08:00:00", + "2022-11-05 10:00:00", + "2022-11-05 12:00:00", + "2022-11-05 14:00:00", + "2022-11-05 16:00:00", + "2022-11-05 18:00:00", + "2022-11-05 20:00:00", + "2022-11-05 22:00:00", + "2022-11-06 00:00:00", + "2022-11-06 02:00:00", + "2022-11-06 04:00:00", + "2022-11-06 06:00:00", + "2022-11-06 08:00:00", + "2022-11-06 10:00:00", + "2022-11-06 12:00:00", + "2022-11-06 14:00:00", + "2022-11-06 16:00:00", + "2022-11-06 18:00:00", + "2022-11-06 20:00:00", + "2022-11-06 22:00:00", + "2022-11-07 00:00:00", + "2022-11-07 02:00:00", + "2022-11-07 04:00:00", + "2022-11-07 06:00:00", + "2022-11-07 08:00:00", + "2022-11-07 10:00:00", + "2022-11-07 12:00:00", + "2022-11-07 14:00:00", + "2022-11-07 16:00:00", + "2022-11-07 18:00:00", + "2022-11-07 20:00:00", + "2022-11-07 22:00:00", + "2022-11-08 00:00:00", + "2022-11-08 02:00:00", + "2022-11-08 04:00:00", + "2022-11-08 06:00:00", + "2022-11-08 08:00:00", + "2022-11-08 10:00:00", + "2022-11-08 12:00:00", + "2022-11-08 14:00:00", + "2022-11-08 16:00:00", + "2022-11-08 18:00:00", + "2022-11-08 20:00:00", + "2022-11-08 22:00:00", + "2022-11-09 00:00:00", + "2022-11-09 02:00:00", + "2022-11-09 04:00:00", + "2022-11-09 06:00:00", + "2022-11-09 08:00:00", + "2022-11-09 10:00:00", + "2022-11-09 12:00:00", + "2022-11-09 14:00:00", + "2022-11-09 16:00:00", + "2022-11-09 18:00:00", + "2022-11-09 20:00:00", + "2022-11-09 22:00:00", + "2022-11-10 00:00:00", + "2022-11-10 02:00:00", + "2022-11-10 04:00:00", + "2022-11-10 06:00:00", + "2022-11-10 08:00:00", + "2022-11-10 10:00:00", + "2022-11-10 12:00:00", + "2022-11-10 14:00:00", + "2022-11-10 16:00:00", + "2022-11-10 18:00:00", + "2022-11-10 20:00:00", + "2022-11-10 22:00:00", + "2022-11-11 00:00:00", + "2022-11-11 02:00:00", + "2022-11-11 04:00:00", + "2022-11-11 06:00:00", + "2022-11-11 08:00:00", + "2022-11-11 10:00:00", + "2022-11-11 12:00:00", + "2022-11-11 14:00:00", + "2022-11-11 16:00:00", + "2022-11-11 18:00:00", + "2022-11-11 20:00:00", + "2022-11-11 22:00:00", + "2022-11-12 00:00:00", + "2022-11-12 02:00:00", + "2022-11-12 04:00:00", + "2022-11-12 06:00:00", + "2022-11-12 08:00:00", + "2022-11-12 10:00:00", + "2022-11-12 12:00:00", + "2022-11-12 14:00:00", + "2022-11-12 16:00:00", + "2022-11-12 18:00:00", + "2022-11-12 20:00:00", + "2022-11-12 22:00:00", + "2022-11-13 00:00:00", + "2022-11-13 02:00:00", + "2022-11-13 04:00:00", + "2022-11-13 06:00:00", + "2022-11-13 08:00:00", + "2022-11-13 10:00:00", + "2022-11-13 12:00:00", + "2022-11-13 14:00:00", + "2022-11-13 16:00:00", + "2022-11-13 18:00:00", + "2022-11-13 20:00:00", + "2022-11-13 22:00:00", + "2022-11-14 00:00:00", + "2022-11-14 02:00:00", + "2022-11-14 04:00:00", + "2022-11-14 06:00:00", + "2022-11-14 08:00:00", + "2022-11-14 10:00:00", + "2022-11-14 12:00:00", + "2022-11-14 14:00:00", + "2022-11-14 16:00:00", + "2022-11-14 18:00:00", + "2022-11-14 20:00:00", + "2022-11-14 22:00:00", + "2022-11-15 00:00:00", + "2022-11-15 02:00:00", + "2022-11-15 04:00:00", + "2022-11-15 06:00:00", + "2022-11-15 08:00:00", + "2022-11-15 10:00:00", + "2022-11-15 12:00:00", + "2022-11-15 14:00:00", + "2022-11-15 16:00:00", + "2022-11-15 18:00:00", + "2022-11-15 20:00:00", + "2022-11-15 22:00:00", + "2022-11-16 00:00:00", + "2022-11-16 02:00:00", + "2022-11-16 04:00:00", + "2022-11-16 06:00:00", + "2022-11-16 08:00:00", + "2022-11-16 10:00:00", + "2022-11-16 12:00:00", + "2022-11-16 14:00:00", + "2022-11-16 16:00:00", + "2022-11-16 18:00:00", + "2022-11-16 20:00:00", + "2022-11-16 22:00:00", + "2022-11-17 00:00:00", + "2022-11-17 02:00:00", + "2022-11-17 04:00:00", + "2022-11-17 06:00:00", + "2022-11-17 08:00:00", + "2022-11-17 10:00:00", + "2022-11-17 12:00:00", + "2022-11-17 14:00:00", + "2022-11-17 16:00:00", + "2022-11-17 18:00:00", + "2022-11-17 20:00:00", + "2022-11-17 22:00:00", + "2022-11-18 00:00:00", + "2022-11-18 02:00:00", + "2022-11-18 04:00:00", + "2022-11-18 06:00:00", + "2022-11-18 08:00:00", + "2022-11-18 10:00:00", + "2022-11-18 12:00:00", + "2022-11-18 14:00:00", + "2022-11-18 16:00:00", + "2022-11-18 18:00:00", + "2022-11-18 20:00:00", + "2022-11-18 22:00:00", + "2022-11-19 00:00:00", + "2022-11-19 02:00:00", + "2022-11-19 04:00:00", + "2022-11-19 06:00:00", + "2022-11-19 08:00:00", + "2022-11-19 10:00:00", + "2022-11-19 12:00:00", + "2022-11-19 14:00:00", + "2022-11-19 16:00:00", + "2022-11-19 18:00:00", + "2022-11-19 20:00:00", + "2022-11-19 22:00:00", + "2022-11-20 00:00:00", + "2022-11-20 02:00:00", + "2022-11-20 04:00:00", + "2022-11-20 06:00:00", + "2022-11-20 08:00:00", + "2022-11-20 10:00:00", + "2022-11-20 12:00:00", + "2022-11-20 14:00:00", + "2022-11-20 16:00:00", + "2022-11-20 18:00:00", + "2022-11-20 20:00:00", + "2022-11-20 22:00:00", + "2022-11-21 00:00:00", + "2022-11-21 02:00:00", + "2022-11-21 04:00:00", + "2022-11-21 06:00:00", + "2022-11-21 08:00:00", + "2022-11-21 10:00:00", + "2022-11-21 12:00:00", + "2022-11-21 14:00:00", + "2022-11-21 16:00:00", + "2022-11-21 18:00:00", + "2022-11-21 20:00:00", + "2022-11-21 22:00:00", + "2022-11-22 00:00:00", + "2022-11-22 02:00:00", + "2022-11-22 04:00:00", + "2022-11-22 06:00:00", + "2022-11-22 08:00:00", + "2022-11-22 10:00:00", + "2022-11-22 12:00:00", + "2022-11-22 14:00:00", + "2022-11-22 16:00:00", + "2022-11-22 18:00:00", + "2022-11-22 20:00:00", + "2022-11-22 22:00:00", + "2022-11-23 00:00:00", + "2022-11-23 02:00:00", + "2022-11-23 04:00:00", + "2022-11-23 06:00:00", + "2022-11-23 08:00:00", + "2022-11-23 10:00:00", + "2022-11-23 12:00:00", + "2022-11-23 14:00:00", + "2022-11-23 16:00:00", + "2022-11-23 18:00:00", + "2022-11-23 20:00:00", + "2022-11-23 22:00:00", + "2022-11-24 00:00:00", + "2022-11-24 02:00:00", + "2022-11-24 04:00:00", + "2022-11-24 06:00:00", + "2022-11-24 08:00:00", + "2022-11-24 10:00:00", + "2022-11-24 12:00:00", + "2022-11-24 14:00:00", + "2022-11-24 16:00:00", + "2022-11-24 18:00:00", + "2022-11-24 20:00:00", + "2022-11-24 22:00:00", + "2022-11-25 00:00:00", + "2022-11-25 02:00:00", + "2022-11-25 04:00:00", + "2022-11-25 06:00:00", + "2022-11-25 08:00:00", + "2022-11-25 10:00:00", + "2022-11-25 12:00:00", + "2022-11-25 14:00:00", + "2022-11-25 16:00:00", + "2022-11-25 18:00:00", + "2022-11-25 20:00:00", + "2022-11-25 22:00:00", + "2022-11-26 00:00:00", + "2022-11-26 02:00:00", + "2022-11-26 04:00:00", + "2022-11-26 06:00:00", + "2022-11-26 08:00:00", + "2022-11-26 10:00:00", + "2022-11-26 12:00:00", + "2022-11-26 14:00:00", + "2022-11-26 16:00:00", + "2022-11-26 18:00:00", + "2022-11-26 20:00:00", + "2022-11-26 22:00:00", + "2022-11-27 00:00:00", + "2022-11-27 02:00:00", + "2022-11-27 04:00:00", + "2022-11-27 06:00:00", + "2022-11-27 08:00:00", + "2022-11-27 10:00:00", + "2022-11-27 12:00:00", + "2022-11-27 14:00:00", + "2022-11-27 16:00:00", + "2022-11-27 18:00:00", + "2022-11-27 20:00:00", + "2022-11-27 22:00:00", + "2022-11-28 00:00:00", + "2022-11-28 02:00:00", + "2022-11-28 04:00:00", + "2022-11-28 06:00:00", + "2022-11-28 08:00:00", + "2022-11-28 10:00:00", + "2022-11-28 12:00:00", + "2022-11-28 14:00:00", + "2022-11-28 16:00:00", + "2022-11-28 18:00:00", + "2022-11-28 20:00:00", + "2022-11-28 22:00:00", + "2022-11-29 00:00:00", + "2022-11-29 02:00:00", + "2022-11-29 04:00:00", + "2022-11-29 06:00:00", + "2022-11-29 08:00:00", + "2022-11-29 10:00:00", + "2022-11-29 12:00:00", + "2022-11-29 14:00:00", + "2022-11-29 16:00:00", + "2022-11-29 18:00:00", + "2022-11-29 20:00:00", + "2022-11-29 22:00:00", + "2022-11-30 00:00:00", + "2022-11-30 02:00:00", + "2022-11-30 04:00:00", + "2022-11-30 06:00:00", + "2022-11-30 08:00:00", + "2022-11-30 10:00:00", + "2022-11-30 12:00:00", + "2022-11-30 14:00:00", + "2022-11-30 16:00:00", + "2022-11-30 18:00:00", + "2022-11-30 20:00:00", + "2022-11-30 22:00:00", + "2022-12-01 00:00:00", + "2022-12-01 02:00:00", + "2022-12-01 04:00:00", + "2022-12-01 06:00:00", + "2022-12-01 08:00:00", + "2022-12-01 10:00:00", + "2022-12-01 12:00:00", + "2022-12-01 14:00:00", + "2022-12-01 16:00:00", + "2022-12-01 18:00:00", + "2022-12-01 20:00:00", + "2022-12-01 22:00:00", + "2022-12-02 00:00:00", + "2022-12-02 02:00:00", + "2022-12-02 04:00:00", + "2022-12-02 06:00:00", + "2022-12-02 08:00:00", + "2022-12-02 10:00:00", + "2022-12-02 12:00:00", + "2022-12-02 14:00:00", + "2022-12-02 16:00:00", + "2022-12-02 18:00:00", + "2022-12-02 20:00:00", + "2022-12-02 22:00:00", + "2022-12-03 00:00:00", + "2022-12-03 02:00:00", + "2022-12-03 04:00:00", + "2022-12-03 06:00:00", + "2022-12-03 08:00:00", + "2022-12-03 10:00:00", + "2022-12-03 12:00:00", + "2022-12-03 14:00:00", + "2022-12-03 16:00:00", + "2022-12-03 18:00:00", + "2022-12-03 20:00:00", + "2022-12-03 22:00:00", + "2022-12-04 00:00:00", + "2022-12-04 02:00:00", + "2022-12-04 04:00:00", + "2022-12-04 06:00:00", + "2022-12-04 08:00:00", + "2022-12-04 10:00:00", + "2022-12-04 12:00:00", + "2022-12-04 14:00:00", + "2022-12-04 16:00:00", + "2022-12-04 18:00:00", + "2022-12-04 20:00:00", + "2022-12-04 22:00:00", + "2022-12-05 00:00:00", + "2022-12-05 02:00:00", + "2022-12-05 04:00:00", + "2022-12-05 06:00:00", + "2022-12-05 08:00:00", + "2022-12-05 10:00:00", + "2022-12-05 12:00:00", + "2022-12-05 14:00:00", + "2022-12-05 16:00:00", + "2022-12-05 18:00:00", + "2022-12-05 20:00:00", + "2022-12-05 22:00:00", + "2022-12-06 00:00:00", + "2022-12-06 02:00:00", + "2022-12-06 04:00:00", + "2022-12-06 06:00:00", + "2022-12-06 08:00:00", + "2022-12-06 10:00:00", + "2022-12-06 12:00:00", + "2022-12-06 14:00:00", + "2022-12-06 16:00:00", + "2022-12-06 18:00:00", + "2022-12-06 20:00:00", + "2022-12-06 22:00:00", + "2022-12-07 00:00:00", + "2022-12-07 02:00:00", + "2022-12-07 04:00:00", + "2022-12-07 06:00:00", + "2022-12-07 08:00:00", + "2022-12-07 10:00:00", + "2022-12-07 12:00:00", + "2022-12-07 14:00:00", + "2022-12-07 16:00:00", + "2022-12-07 18:00:00", + "2022-12-07 20:00:00", + "2022-12-07 22:00:00", + "2022-12-08 00:00:00", + "2022-12-08 02:00:00", + "2022-12-08 04:00:00", + "2022-12-08 06:00:00", + "2022-12-08 08:00:00", + "2022-12-08 10:00:00", + "2022-12-08 12:00:00", + "2022-12-08 14:00:00", + "2022-12-08 16:00:00", + "2022-12-08 18:00:00", + "2022-12-08 20:00:00", + "2022-12-08 22:00:00", + "2022-12-09 00:00:00", + "2022-12-09 02:00:00", + "2022-12-09 04:00:00", + "2022-12-09 06:00:00", + "2022-12-09 08:00:00", + "2022-12-09 10:00:00", + "2022-12-09 12:00:00", + "2022-12-09 14:00:00", + "2022-12-09 16:00:00", + "2022-12-09 18:00:00", + "2022-12-09 20:00:00", + "2022-12-09 22:00:00", + "2022-12-10 00:00:00", + "2022-12-10 02:00:00", + "2022-12-10 04:00:00", + "2022-12-10 06:00:00", + "2022-12-10 08:00:00", + "2022-12-10 10:00:00", + "2022-12-10 12:00:00", + "2022-12-10 14:00:00", + "2022-12-10 16:00:00", + "2022-12-10 18:00:00", + "2022-12-10 20:00:00", + "2022-12-10 22:00:00", + "2022-12-11 00:00:00", + "2022-12-11 02:00:00", + "2022-12-11 04:00:00", + "2022-12-11 06:00:00", + "2022-12-11 08:00:00", + "2022-12-11 10:00:00", + "2022-12-11 12:00:00", + "2022-12-11 14:00:00", + "2022-12-11 16:00:00", + "2022-12-11 18:00:00", + "2022-12-11 20:00:00", + "2022-12-11 22:00:00", + "2022-12-12 00:00:00", + "2022-12-12 02:00:00", + "2022-12-12 04:00:00", + "2022-12-12 06:00:00", + "2022-12-12 08:00:00", + "2022-12-12 10:00:00", + "2022-12-12 12:00:00", + "2022-12-12 14:00:00", + "2022-12-12 16:00:00", + "2022-12-12 18:00:00", + "2022-12-12 20:00:00", + "2022-12-12 22:00:00", + "2022-12-13 00:00:00", + "2022-12-13 02:00:00", + "2022-12-13 04:00:00", + "2022-12-13 06:00:00", + "2022-12-13 08:00:00", + "2022-12-13 10:00:00", + "2022-12-13 12:00:00", + "2022-12-13 14:00:00", + "2022-12-13 16:00:00", + "2022-12-13 18:00:00", + "2022-12-13 20:00:00", + "2022-12-13 22:00:00", + "2022-12-14 00:00:00", + "2022-12-14 02:00:00", + "2022-12-14 04:00:00", + "2022-12-14 06:00:00", + "2022-12-14 08:00:00", + "2022-12-14 10:00:00", + "2022-12-14 12:00:00", + "2022-12-14 14:00:00", + "2022-12-14 16:00:00", + "2022-12-14 18:00:00", + "2022-12-14 20:00:00", + "2022-12-14 22:00:00", + "2022-12-15 00:00:00", + "2022-12-15 02:00:00", + "2022-12-15 04:00:00", + "2022-12-15 06:00:00", + "2022-12-15 08:00:00", + "2022-12-15 10:00:00", + "2022-12-15 12:00:00", + "2022-12-15 14:00:00", + "2022-12-15 16:00:00", + "2022-12-15 18:00:00", + "2022-12-15 20:00:00", + "2022-12-15 22:00:00", + "2022-12-16 00:00:00", + "2022-12-16 02:00:00", + "2022-12-16 04:00:00", + "2022-12-16 06:00:00", + "2022-12-16 08:00:00", + "2022-12-16 10:00:00", + "2022-12-16 12:00:00", + "2022-12-16 14:00:00", + "2022-12-16 16:00:00", + "2022-12-16 18:00:00", + "2022-12-16 20:00:00", + "2022-12-16 22:00:00", + "2022-12-17 00:00:00", + "2022-12-17 02:00:00", + "2022-12-17 04:00:00", + "2022-12-17 06:00:00", + "2022-12-17 08:00:00", + "2022-12-17 10:00:00", + "2022-12-17 12:00:00", + "2022-12-17 14:00:00", + "2022-12-17 16:00:00", + "2022-12-17 18:00:00", + "2022-12-17 20:00:00", + "2022-12-17 22:00:00", + "2022-12-18 00:00:00", + "2022-12-18 02:00:00", + "2022-12-18 04:00:00", + "2022-12-18 06:00:00", + "2022-12-18 08:00:00", + "2022-12-18 10:00:00", + "2022-12-18 12:00:00", + "2022-12-18 14:00:00", + "2022-12-18 16:00:00", + "2022-12-18 18:00:00", + "2022-12-18 20:00:00", + "2022-12-18 22:00:00", + "2022-12-19 00:00:00", + "2022-12-19 02:00:00", + "2022-12-19 04:00:00", + "2022-12-19 06:00:00", + "2022-12-19 08:00:00", + "2022-12-19 10:00:00", + "2022-12-19 12:00:00", + "2022-12-19 14:00:00", + "2022-12-19 16:00:00", + "2022-12-19 18:00:00", + "2022-12-19 20:00:00", + "2022-12-19 22:00:00", + "2022-12-20 00:00:00", + "2022-12-20 02:00:00", + "2022-12-20 04:00:00", + "2022-12-20 06:00:00", + "2022-12-20 08:00:00", + "2022-12-20 10:00:00", + "2022-12-20 12:00:00", + "2022-12-20 14:00:00", + "2022-12-20 16:00:00", + "2022-12-20 18:00:00", + "2022-12-20 20:00:00", + "2022-12-20 22:00:00", + "2022-12-21 00:00:00", + "2022-12-21 02:00:00", + "2022-12-21 04:00:00", + "2022-12-21 06:00:00", + "2022-12-21 08:00:00", + "2022-12-21 10:00:00", + "2022-12-21 12:00:00", + "2022-12-21 14:00:00", + "2022-12-21 16:00:00", + "2022-12-21 18:00:00", + "2022-12-21 20:00:00", + "2022-12-21 22:00:00", + "2022-12-22 00:00:00", + "2022-12-22 02:00:00", + "2022-12-22 04:00:00", + "2022-12-22 06:00:00", + "2022-12-22 08:00:00", + "2022-12-22 10:00:00", + "2022-12-22 12:00:00", + "2022-12-22 14:00:00", + "2022-12-22 16:00:00", + "2022-12-22 18:00:00", + "2022-12-22 20:00:00", + "2022-12-22 22:00:00", + "2022-12-23 00:00:00", + "2022-12-23 02:00:00", + "2022-12-23 04:00:00", + "2022-12-23 06:00:00", + "2022-12-23 08:00:00", + "2022-12-23 10:00:00", + "2022-12-23 12:00:00", + "2022-12-23 14:00:00", + "2022-12-23 16:00:00", + "2022-12-23 18:00:00", + "2022-12-23 20:00:00", + "2022-12-23 22:00:00", + "2022-12-24 00:00:00", + "2022-12-24 02:00:00", + "2022-12-24 04:00:00", + "2022-12-24 06:00:00", + "2022-12-24 08:00:00", + "2022-12-24 10:00:00", + "2022-12-24 12:00:00", + "2022-12-24 14:00:00", + "2022-12-24 16:00:00", + "2022-12-24 18:00:00", + "2022-12-24 20:00:00", + "2022-12-24 22:00:00", + "2022-12-25 00:00:00", + "2022-12-25 02:00:00", + "2022-12-25 04:00:00", + "2022-12-25 06:00:00", + "2022-12-25 08:00:00", + "2022-12-25 10:00:00", + "2022-12-25 12:00:00", + "2022-12-25 14:00:00", + "2022-12-25 16:00:00", + "2022-12-25 18:00:00", + "2022-12-25 20:00:00", + "2022-12-25 22:00:00", + "2022-12-26 00:00:00", + "2022-12-26 02:00:00", + "2022-12-26 04:00:00", + "2022-12-26 06:00:00", + "2022-12-26 08:00:00", + "2022-12-26 10:00:00", + "2022-12-26 12:00:00", + "2022-12-26 14:00:00", + "2022-12-26 16:00:00", + "2022-12-26 18:00:00", + "2022-12-26 20:00:00", + "2022-12-26 22:00:00", + "2022-12-27 00:00:00", + "2022-12-27 02:00:00", + "2022-12-27 04:00:00", + "2022-12-27 06:00:00", + "2022-12-27 08:00:00", + "2022-12-27 10:00:00", + "2022-12-27 12:00:00", + "2022-12-27 14:00:00", + "2022-12-27 16:00:00", + "2022-12-27 18:00:00", + "2022-12-27 20:00:00", + "2022-12-27 22:00:00", + "2022-12-28 00:00:00", + "2022-12-28 02:00:00", + "2022-12-28 04:00:00", + "2022-12-28 06:00:00", + "2022-12-28 08:00:00", + "2022-12-28 10:00:00", + "2022-12-28 12:00:00", + "2022-12-28 14:00:00", + "2022-12-28 16:00:00", + "2022-12-28 18:00:00", + "2022-12-28 20:00:00", + "2022-12-28 22:00:00", + "2022-12-29 00:00:00", + "2022-12-29 02:00:00", + "2022-12-29 04:00:00", + "2022-12-29 06:00:00", + "2022-12-29 08:00:00", + "2022-12-29 10:00:00", + "2022-12-29 12:00:00", + "2022-12-29 14:00:00", + "2022-12-29 16:00:00", + "2022-12-29 18:00:00", + "2022-12-29 20:00:00", + "2022-12-29 22:00:00", + "2022-12-30 00:00:00", + "2022-12-30 02:00:00", + "2022-12-30 04:00:00", + "2022-12-30 06:00:00", + "2022-12-30 08:00:00", + "2022-12-30 10:00:00", + "2022-12-30 12:00:00", + "2022-12-30 14:00:00", + "2022-12-30 16:00:00", + "2022-12-30 18:00:00", + "2022-12-30 20:00:00", + "2022-12-30 22:00:00", + "2022-12-31 00:00:00", + "2022-12-31 02:00:00", + "2022-12-31 04:00:00", + "2022-12-31 06:00:00", + "2022-12-31 08:00:00", + "2022-12-31 10:00:00", + "2022-12-31 12:00:00", + "2022-12-31 14:00:00", + "2022-12-31 16:00:00", + "2022-12-31 18:00:00", + "2022-12-31 20:00:00", + "2022-12-31 22:00:00", + "2023-01-01 00:00:00", + "2023-01-01 02:00:00", + "2023-01-01 04:00:00", + "2023-01-01 06:00:00", + "2023-01-01 08:00:00", + "2023-01-01 10:00:00", + "2023-01-01 12:00:00", + "2023-01-01 14:00:00", + "2023-01-01 16:00:00", + "2023-01-01 18:00:00", + "2023-01-01 20:00:00", + "2023-01-01 22:00:00", + "2023-01-02 00:00:00", + "2023-01-02 02:00:00", + "2023-01-02 04:00:00", + "2023-01-02 06:00:00", + "2023-01-02 08:00:00", + "2023-01-02 10:00:00", + "2023-01-02 12:00:00", + "2023-01-02 14:00:00", + "2023-01-02 16:00:00", + "2023-01-02 18:00:00", + "2023-01-02 20:00:00", + "2023-01-02 22:00:00", + "2023-01-03 00:00:00", + "2023-01-03 02:00:00", + "2023-01-03 04:00:00", + "2023-01-03 06:00:00", + "2023-01-03 08:00:00", + "2023-01-03 10:00:00", + "2023-01-03 12:00:00", + "2023-01-03 14:00:00", + "2023-01-03 16:00:00", + "2023-01-03 18:00:00", + "2023-01-03 20:00:00", + "2023-01-03 22:00:00", + "2023-01-04 00:00:00", + "2023-01-04 02:00:00", + "2023-01-04 04:00:00", + "2023-01-04 06:00:00", + "2023-01-04 08:00:00", + "2023-01-04 10:00:00", + "2023-01-04 12:00:00", + "2023-01-04 14:00:00", + "2023-01-04 16:00:00", + "2023-01-04 18:00:00", + "2023-01-04 20:00:00", + "2023-01-04 22:00:00", + "2023-01-05 00:00:00", + "2023-01-05 02:00:00", + "2023-01-05 04:00:00", + "2023-01-05 06:00:00", + "2023-01-05 08:00:00", + "2023-01-05 10:00:00", + "2023-01-05 12:00:00", + "2023-01-05 14:00:00", + "2023-01-05 16:00:00", + "2023-01-05 18:00:00", + "2023-01-05 20:00:00", + "2023-01-05 22:00:00", + "2023-01-06 00:00:00", + "2023-01-06 02:00:00", + "2023-01-06 04:00:00", + "2023-01-06 06:00:00", + "2023-01-06 08:00:00", + "2023-01-06 10:00:00", + "2023-01-06 12:00:00", + "2023-01-06 14:00:00", + "2023-01-06 16:00:00", + "2023-01-06 18:00:00", + "2023-01-06 20:00:00", + "2023-01-06 22:00:00", + "2023-01-07 00:00:00", + "2023-01-07 02:00:00", + "2023-01-07 04:00:00", + "2023-01-07 06:00:00", + "2023-01-07 08:00:00", + "2023-01-07 10:00:00", + "2023-01-07 12:00:00", + "2023-01-07 14:00:00", + "2023-01-07 16:00:00", + "2023-01-07 18:00:00", + "2023-01-07 20:00:00", + "2023-01-07 22:00:00", + "2023-01-08 00:00:00", + "2023-01-08 02:00:00", + "2023-01-08 04:00:00", + "2023-01-08 06:00:00", + "2023-01-08 08:00:00", + "2023-01-08 10:00:00", + "2023-01-08 12:00:00", + "2023-01-08 14:00:00", + "2023-01-08 16:00:00", + "2023-01-08 18:00:00", + "2023-01-08 20:00:00", + "2023-01-08 22:00:00", + "2023-01-09 00:00:00", + "2023-01-09 02:00:00", + "2023-01-09 04:00:00", + "2023-01-09 06:00:00", + "2023-01-09 08:00:00", + "2023-01-09 10:00:00", + "2023-01-09 12:00:00", + "2023-01-09 14:00:00", + "2023-01-09 16:00:00", + "2023-01-09 18:00:00", + "2023-01-09 20:00:00", + "2023-01-09 22:00:00", + "2023-01-10 00:00:00" + ], + "y": [ + 28304.0, + 28309.0, + 28268.0, + 28190.0, + 28370.0, + 27909.0, + 27989.0, + 27664.0, + 27527.0, + 27745.0, + 27666.0, + 27751.0, + 27816.0, + 27854.0, + 27895.0, + 27642.0, + 27334.0, + 27381.0, + 27026.0, + 27114.0, + 27209.0, + 27141.0, + 27012.0, + 26810.0, + 26235.0, + 25957.0, + 26317.0, + 26155.0, + 26117.0, + 25984.0, + 26725.0, + 26750.0, + 26040.0, + 26007.0, + 25305.0, + 24576.0, + 24286.0, + 24034.0, + 23681.0, + 22947.0, + 22676.0, + 22646.0, + 22310.0, + 22526.0, + 22270.0, + 22162.0, + 21584.0, + 20091.0, + 21217.0, + 21811.0, + 21855.0, + 21361.0, + 21037.0, + 21473.0, + 21784.0, + 21455.0, + 21325.0, + 20624.0, + 21232.0, + 21211.0, + 20512.0, + 20264.0, + 19795.0, + 19254.0, + 20227.0, + 20638.0, + 20581.0, + 20275.0, + 20686.0, + 21241.0, + 21582.0, + 21426.0, + 21230.0, + 21033.0, + 20938.0, + 20410.0, + 20261.0, + 20111.0, + 19988.0, + 19890.0, + 19765.0, + 19552.0, + 19331.0, + 19796.0, + 19339.0, + 19760.0, + 20052.0, + 19910.0, + 19987.0, + 19811.0, + 19733.0, + 19589.0, + 19525.0, + 19566.0, + 19466.0, + 19442.0, + 19480.0, + 19445.0, + 18364.0, + 18275.0, + 18336.0, + 18292.0, + 18039.0, + 17710.0, + 17188.0, + 17614.0, + 18068.0, + 17558.0, + 17419.0, + 17264.0, + 17431.0, + 18098.0, + 18714.0, + 18280.0, + 18856.0, + 18523.0, + 19162.0, + 19450.0, + 19608.0, + 18851.0, + 18953.0, + 19047.0, + 19075.0, + 19577.0, + 19745.0, + 19489.0, + 19753.0, + 18979.0, + 19097.0, + 19398.0, + 19531.0, + 19583.0, + 19538.0, + 19837.0, + 19995.0, + 20042.0, + 19834.0, + 20475.0, + 20267.0, + 20131.0, + 19827.0, + 19916.0, + 19671.0, + 19415.0, + 19295.0, + 19399.0, + 19126.0, + 19416.0, + 19479.0, + 19637.0, + 18963.0, + 19158.0, + 19042.0, + 18921.0, + 18884.0, + 19288.0, + 19120.0, + 19248.0, + 19481.0, + 19737.0, + 19635.0, + 19389.0, + 19364.0, + 19331.0, + 19853.0, + 19639.0, + 20052.0, + 19962.0, + 19996.0, + 19816.0, + 19870.0, + 19727.0, + 20102.0, + 20109.0, + 19810.0, + 19879.0, + 20118.0, + 20184.0, + 20090.0, + 20182.0, + 20190.0, + 20100.0, + 20386.0, + 20332.0, + 20232.0, + 20063.0, + 19879.0, + 20005.0, + 20091.0, + 20365.0, + 20354.0, + 20279.0, + 20294.0, + 20322.0, + 20278.0, + 20312.0, + 20572.0, + 20305.0, + 20232.0, + 20151.0, + 20181.0, + 20243.0, + 19923.0, + 19962.0, + 20069.0, + 20050.0, + 20149.0, + 20288.0, + 20143.0, + 19599.0, + 19575.0, + 19571.0, + 19709.0, + 19623.0, + 19585.0, + 19476.0, + 19586.0, + 19611.0, + 19729.0, + 19882.0, + 19841.0, + 19980.0, + 19530.0, + 19569.0, + 19236.0, + 19367.0, + 19263.0, + 19324.0, + 19257.0, + 19164.0, + 19082.0, + 19070.0, + 19066.0, + 19143.0, + 19147.0, + 19173.0, + 19334.0, + 19406.0, + 19241.0, + 19158.0, + 19174.0, + 19115.0, + 18594.0, + 18357.0, + 18363.0, + 18107.0, + 18280.0, + 18230.0, + 18039.0, + 17949.0, + 19020.0, + 19466.0, + 18837.0, + 18562.0, + 18725.0, + 18555.0, + 18377.0, + 18722.0, + 18509.0, + 18708.0, + 18565.0, + 18564.0, + 18470.0, + 18435.0, + 18345.0, + 18444.0, + 18339.0, + 18388.0, + 18393.0, + 18466.0, + 18440.0, + 18488.0, + 18478.0, + 18535.0, + 18431.0, + 18396.0, + 18462.0, + 18247.0, + 18341.0, + 18257.0, + 18307.0, + 18191.0, + 18266.0, + 18405.0, + 18693.0, + 18508.0, + 18496.0, + 18380.0, + 18317.0, + 18333.0, + 18314.0, + 18530.0, + 18922.0, + 18668.0, + 18956.0, + 19054.0, + 19004.0, + 19107.0, + 19350.0, + 19407.0, + 19444.0, + 19391.0, + 19445.0, + 19179.0, + 18919.0, + 18888.0, + 19011.0, + 19192.0, + 19825.0, + 19807.0, + 19633.0, + 19342.0, + 19419.0, + 19534.0, + 19630.0, + 19733.0, + 19696.0, + 19857.0, + 19787.0, + 19893.0, + 19923.0, + 19966.0, + 20171.0, + 20129.0, + 20058.0, + 19831.0, + 20045.0, + 20118.0, + 20101.0, + 20133.0, + 20527.0, + 20549.0, + 21473.0, + 21313.0, + 21260.0, + 21709.0, + 21786.0, + 21494.0, + 21548.0, + 21289.0, + 21241.0, + 20951.0, + 21552.0, + 21370.0, + 21400.0, + 21320.0, + 21197.0, + 21120.0, + 21223.0, + 21143.0, + 21247.0, + 21267.0, + 21065.0, + 21189.0, + 21170.0, + 21491.0, + 21238.0, + 21326.0, + 21200.0, + 21014.0, + 20902.0, + 20984.0, + 20963.0, + 20929.0, + 20904.0, + 20690.0, + 20520.0, + 20524.0, + 20545.0, + 20660.0, + 20499.0, + 20252.0, + 20237.0, + 20209.0, + 20200.0, + 20329.0, + 20268.0, + 20230.0, + 20254.0, + 20458.0, + 20381.0, + 20135.0, + 19867.0, + 19808.0, + 19884.0, + 19916.0, + 19702.0, + 19559.0, + 19691.0, + 19659.0, + 19742.0, + 19759.0, + 19340.0, + 19274.0, + 19239.0, + 19365.0, + 19397.0, + 19444.0, + 19640.0, + 19722.0, + 19713.0, + 19222.0, + 19294.0, + 19721.0, + 19532.0, + 19810.0, + 20171.0, + 20215.0, + 20125.0, + 20044.0, + 19905.0, + 19732.0, + 19719.0, + 19815.0, + 20304.0, + 20682.0, + 20550.0, + 20402.0, + 20506.0, + 20533.0, + 20528.0, + 20600.0, + 20749.0, + 20809.0, + 20635.0, + 20773.0, + 20611.0, + 20616.0, + 20979.0, + 20790.0, + 20633.0, + 20539.0, + 20557.0, + 20399.0, + 20383.0, + 20444.0, + 20443.0, + 20688.0, + 20780.0, + 21038.0, + 20982.0, + 21012.0, + 21040.0, + 20948.0, + 21146.0, + 21157.0, + 21282.0, + 21181.0, + 21268.0, + 20953.0, + 21000.0, + 20731.0, + 20856.0, + 20836.0, + 20581.0, + 20745.0, + 21076.0, + 21647.0, + 21912.0, + 21893.0, + 21812.0, + 21780.0, + 22257.0, + 21531.0, + 21301.0, + 21355.0, + 22145.0, + 21788.0, + 21623.0, + 21688.0, + 21249.0, + 21420.0, + 21452.0, + 21789.0, + 22613.0, + 22942.0, + 22924.0, + 23113.0, + 22889.0, + 22731.0, + 22881.0, + 22947.0, + 22864.0, + 22969.0, + 23287.0, + 23280.0, + 23689.0, + 23152.0, + 23261.0, + 23211.0, + 22828.0, + 22786.0, + 22310.0, + 22454.0, + 22477.0, + 22602.0, + 22168.0, + 22252.0, + 22200.0, + 22423.0, + 22713.0, + 22700.0, + 22632.0, + 22661.0, + 22494.0, + 22728.0, + 22807.0, + 23101.0, + 23204.0, + 22921.0, + 22793.0, + 22504.0, + 22136.0, + 22272.0, + 22213.0, + 22313.0, + 22381.0, + 22424.0, + 22304.0, + 22229.0, + 21785.0, + 21912.0, + 21766.0, + 21604.0, + 21844.0, + 21818.0, + 21997.0, + 21945.0, + 21881.0, + 22299.0, + 22250.0, + 22172.0, + 22209.0, + 22101.0, + 22372.0, + 22319.0, + 22238.0, + 22357.0, + 22141.0, + 21797.0, + 21431.0, + 21514.0, + 21569.0, + 21492.0, + 21427.0, + 21400.0, + 21466.0, + 21418.0, + 21424.0, + 21565.0, + 20836.0, + 20588.0, + 20683.0, + 20716.0, + 20624.0, + 20759.0, + 20805.0, + 20669.0, + 20500.0, + 20694.0, + 20692.0, + 20702.0, + 21000.0, + 20869.0, + 20784.0, + 20941.0, + 21070.0, + 20981.0, + 20872.0, + 21178.0, + 21314.0, + 21354.0, + 22290.0, + 22260.0, + 22501.0, + 22319.0, + 22637.0, + 22752.0, + 22443.0, + 22634.0, + 22837.0, + 22528.0, + 23341.0, + 23638.0, + 23349.0, + 23448.0, + 23412.0, + 23418.0, + 23424.0, + 23513.0, + 23401.0, + 23609.0, + 23228.0, + 23332.0, + 23539.0, + 23299.0, + 23375.0, + 23287.0, + 23267.0, + 23384.0, + 23299.0, + 23269.0, + 23364.0, + 23411.0, + 23460.0, + 23956.0, + 23985.0, + 23963.0, + 23421.0, + 23372.0, + 23133.0, + 23227.0, + 23262.0, + 23216.0, + 23233.0, + 23288.0, + 23300.0, + 23250.0, + 23270.0, + 23245.0, + 23347.0, + 23101.0, + 22862.0, + 22908.0, + 22866.0, + 22854.0, + 22814.0, + 22724.0, + 22717.0, + 22672.0, + 22748.0, + 22399.0, + 22395.0, + 22455.0, + 22683.0, + 22408.0, + 22243.0, + 22282.0, + 22418.0, + 22180.0, + 22388.0, + 22353.0, + 22550.0, + 22782.0, + 22613.0, + 22710.0, + 22645.0, + 22440.0, + 22444.0, + 22535.0, + 22591.0, + 22969.0, + 23022.0, + 22951.0, + 23026.0, + 23103.0, + 23066.0, + 22913.0, + 22508.0, + 22768.0, + 22724.0, + 22769.0, + 22579.0, + 22441.0, + 22515.0, + 22630.0, + 22440.0, + 22125.0, + 21937.0, + 21951.0, + 22091.0, + 22390.0, + 22628.0, + 22662.0, + 22665.0, + 22614.0, + 22863.0, + 22670.0, + 22625.0, + 22439.0, + 22526.0, + 22686.0, + 22878.0, + 22787.0, + 22740.0, + 22782.0, + 22797.0, + 22770.0, + 22756.0, + 22792.0, + 22785.0, + 22721.0, + 22796.0, + 22781.0, + 22540.0, + 22508.0, + 22616.0, + 22562.0, + 22623.0, + 22590.0, + 22642.0, + 22768.0, + 22618.0, + 22832.0, + 22759.0, + 22924.0, + 22807.0, + 22818.0, + 22891.0, + 23017.0, + 23335.0, + 23643.0, + 23674.0, + 23700.0, + 23515.0, + 23485.0, + 23496.0, + 23410.0, + 23331.0, + 23303.0, + 23390.0, + 23416.0, + 23393.0, + 22951.0, + 22791.0, + 22555.0, + 22617.0, + 22593.0, + 22617.0, + 22733.0, + 22685.0, + 22432.0, + 22395.0, + 22428.0, + 22490.0, + 22586.0, + 22556.0, + 23265.0, + 23214.0, + 23162.0, + 22928.0, + 23260.0, + 23229.0, + 23728.0, + 23647.0, + 23874.0, + 23656.0, + 23668.0, + 23804.0, + 23868.0, + 23564.0, + 23578.0, + 23442.0, + 23447.0, + 23215.0, + 23229.0, + 23307.0, + 23232.0, + 23282.0, + 23314.0, + 23052.0, + 23197.0, + 23403.0, + 23417.0, + 23588.0, + 23526.0, + 23790.0, + 23926.0, + 24149.0, + 24063.0, + 23915.0, + 23970.0, + 23805.0, + 23856.0, + 23899.0, + 23964.0, + 23812.0, + 23912.0, + 23840.0, + 23966.0, + 23967.0, + 23992.0, + 24256.0, + 24157.0, + 23956.0, + 23901.0, + 23944.0, + 23650.0, + 23692.0, + 23755.0, + 23709.0, + 24022.0, + 24253.0, + 24254.0, + 23500.0, + 23727.0, + 23617.0, + 23718.0, + 23802.0, + 23746.0, + 23604.0, + 23648.0, + 23732.0, + 23768.0, + 23722.0, + 23569.0, + 23686.0, + 23779.0, + 23729.0, + 23507.0, + 23491.0, + 23463.0, + 23518.0, + 23570.0, + 23466.0, + 23527.0, + 23584.0, + 23752.0, + 23406.0, + 23412.0, + 23347.0, + 23052.0, + 23035.0, + 23098.0, + 22856.0, + 22938.0, + 22940.0, + 23055.0, + 23041.0, + 23012.0, + 23042.0, + 23144.0, + 23118.0, + 23165.0, + 23199.0, + 23091.0, + 23155.0, + 23162.0, + 22981.0, + 22600.0, + 22610.0, + 22633.0, + 21729.0, + 21570.0, + 21371.0, + 21272.0, + 21375.0, + 21385.0, + 21264.0, + 21000.0, + 20729.0, + 20899.0, + 21054.0, + 21057.0, + 21249.0, + 21140.0, + 21192.0, + 21246.0, + 21245.0, + 21190.0, + 20890.0, + 21046.0, + 21058.0, + 21175.0, + 21118.0, + 21143.0, + 21161.0, + 21383.0, + 21460.0, + 21326.0, + 21349.0, + 21401.0, + 21432.0, + 21445.0, + 21451.0, + 21394.0, + 21331.0, + 21369.0, + 21098.0, + 21150.0, + 21253.0, + 21362.0, + 21548.0, + 21392.0, + 21177.0, + 21216.0, + 21521.0, + 21430.0, + 21360.0, + 21138.0, + 21454.0, + 21589.0, + 21629.0, + 21555.0, + 21533.0, + 21515.0, + 21600.0, + 21539.0, + 21581.0, + 21364.0, + 21371.0, + 21534.0, + 21420.0, + 21425.0, + 21607.0, + 21610.0, + 21687.0, + 21714.0, + 21771.0, + 21657.0, + 21429.0, + 21614.0, + 21504.0, + 21584.0, + 21743.0, + 21700.0, + 21775.0, + 21791.0, + 21668.0, + 21635.0, + 21661.0, + 21611.0, + 21639.0, + 21609.0, + 21628.0, + 21500.0, + 21500.0, + 21410.0, + 21191.0, + 21624.0, + 20791.0, + 20704.0, + 20727.0, + 20733.0, + 20342.0, + 20383.0, + 20321.0, + 20238.0, + 20384.0, + 20254.0, + 20315.0, + 20276.0, + 20063.0, + 20083.0, + 20117.0, + 19975.0, + 20108.0, + 20105.0, + 20086.0, + 20110.0, + 20140.0, + 20104.0, + 20133.0, + 20039.0, + 20124.0, + 20066.0, + 20069.0, + 20042.0, + 19685.0, + 19809.0, + 20028.0, + 19908.0, + 20013.0, + 19905.0, + 19821.0, + 20055.0, + 20274.0, + 20282.0, + 20090.0, + 20221.0, + 20268.0, + 20194.0, + 20272.0, + 20419.0, + 20379.0, + 20346.0, + 20368.0, + 20226.0, + 19744.0, + 19669.0, + 19907.0, + 19852.0, + 19754.0, + 20187.0, + 20334.0, + 20254.0, + 20244.0, + 20198.0, + 20308.0, + 20303.0, + 20039.0, + 19898.0, + 20124.0, + 20167.0, + 19986.0, + 20064.0, + 19972.0, + 20023.0, + 19828.0, + 19883.0, + 20080.0, + 19973.0, + 19890.0, + 19804.0, + 19959.0, + 20178.0, + 20197.0, + 20095.0, + 20223.0, + 20196.0, + 20117.0, + 20112.0, + 20114.0, + 20254.0, + 20286.0, + 19872.0, + 20010.0, + 20096.0, + 20068.0, + 20061.0, + 20001.0, + 20057.0, + 19896.0, + 19906.0, + 19889.0, + 19960.0, + 19888.0, + 19931.0, + 19803.0, + 19867.0, + 19943.0, + 19896.0, + 19876.0, + 19885.0, + 19770.0, + 19893.0, + 19929.0, + 19818.0, + 19903.0, + 19925.0, + 19988.0, + 20001.0, + 20170.0, + 19994.0, + 20049.0, + 19952.0, + 19934.0, + 19930.0, + 19873.0, + 19884.0, + 19975.0, + 19946.0, + 19835.0, + 19896.0, + 19875.0, + 19819.0, + 19862.0, + 19887.0, + 19966.0, + 20001.0, + 20060.0, + 19973.0, + 20008.0, + 19439.0, + 19023.0, + 19175.0, + 19002.0, + 19002.0, + 18982.0, + 18976.0, + 18968.0, + 18966.0, + 18990.0, + 19043.0, + 19007.0, + 19030.0, + 19000.0, + 19340.0, + 19293.0, + 19210.0, + 19224.0, + 19314.0, + 19206.0, + 19190.0, + 19264.0, + 19287.0, + 19356.0, + 19203.0, + 19365.0, + 19347.0, + 19284.0, + 19250.0, + 19798.0, + 20365.0, + 20426.0, + 20562.0, + 20845.0, + 20898.0, + 21154.0, + 21146.0, + 21164.0, + 21126.0, + 21234.0, + 21157.0, + 21161.0, + 21418.0, + 21177.0, + 21195.0, + 21155.0, + 21050.0, + 21088.0, + 21179.0, + 21450.0, + 21479.0, + 21530.0, + 21486.0, + 21416.0, + 21494.0, + 21500.0, + 21470.0, + 21486.0, + 21411.0, + 21505.0, + 21521.0, + 21471.0, + 21284.0, + 21680.0, + 21825.0, + 21460.0, + 21612.0, + 21799.0, + 21834.0, + 21995.0, + 22134.0, + 21825.0, + 22046.0, + 22161.0, + 22058.0, + 22109.0, + 21947.0, + 21956.0, + 22078.0, + 21955.0, + 22011.0, + 22145.0, + 21090.0, + 20793.0, + 20809.0, + 20358.0, + 20235.0, + 20246.0, + 20356.0, + 20358.0, + 20351.0, + 20269.0, + 20334.0, + 20245.0, + 20343.0, + 20201.0, + 20139.0, + 20014.0, + 20281.0, + 20248.0, + 20244.0, + 20071.0, + 20235.0, + 20245.0, + 20156.0, + 20186.0, + 20125.0, + 19746.0, + 19828.0, + 19809.0, + 19842.0, + 19746.0, + 19734.0, + 19760.0, + 19789.0, + 19824.0, + 19817.0, + 19936.0, + 19581.0, + 19651.0, + 19453.0, + 19610.0, + 19720.0, + 19776.0, + 19975.0, + 19865.0, + 19821.0, + 19809.0, + 19859.0, + 19793.0, + 19873.0, + 19941.0, + 20072.0, + 20004.0, + 20015.0, + 20099.0, + 19968.0, + 19954.0, + 20038.0, + 20037.0, + 19815.0, + 19898.0, + 19931.0, + 19782.0, + 19600.0, + 19696.0, + 19459.0, + 19384.0, + 19434.0, + 18773.0, + 18524.0, + 18501.0, + 18525.0, + 18716.0, + 19149.0, + 19101.0, + 18963.0, + 19476.0, + 19460.0, + 19474.0, + 19429.0, + 19315.0, + 19331.0, + 19293.0, + 19199.0, + 19246.0, + 18942.0, + 19274.0, + 18851.0, + 19033.0, + 18948.0, + 18940.0, + 18960.0, + 19089.0, + 19029.0, + 19110.0, + 19123.0, + 19345.0, + 19464.0, + 19418.0, + 19851.0, + 19279.0, + 18775.0, + 18845.0, + 18861.0, + 19035.0, + 19010.0, + 19226.0, + 19446.0, + 19479.0, + 19222.0, + 19308.0, + 19364.0, + 19609.0, + 19496.0, + 19719.0, + 19657.0, + 19714.0, + 19720.0, + 19650.0, + 19553.0, + 19325.0, + 19142.0, + 19267.0, + 19369.0, + 19407.0, + 19593.0, + 19885.0, + 19702.0, + 19726.0, + 19738.0, + 19595.0, + 19622.0, + 19650.0, + 19708.0, + 19715.0, + 19682.0, + 19707.0, + 19549.0, + 19521.0, + 19569.0, + 19650.0, + 19590.0, + 19699.0, + 19641.0, + 19708.0, + 19522.0, + 19572.0, + 19579.0, + 19520.0, + 19383.0, + 19407.0, + 19539.0, + 19591.0, + 19520.0, + 19541.0, + 19769.0, + 19570.0, + 19838.0, + 19863.0, + 19892.0, + 19972.0, + 19868.0, + 19972.0, + 20520.0, + 20847.0, + 20916.0, + 20899.0, + 20980.0, + 20986.0, + 20968.0, + 20630.0, + 19784.0, + 19885.0, + 19782.0, + 19887.0, + 19880.0, + 19611.0, + 19680.0, + 19605.0, + 19535.0, + 19785.0, + 19909.0, + 20147.0, + 19886.0, + 20065.0, + 20145.0, + 19987.0, + 20111.0, + 20133.0, + 20118.0, + 20043.0, + 20104.0, + 20005.0, + 19498.0, + 19756.0, + 19700.0, + 19807.0, + 19797.0, + 19942.0, + 19879.0, + 19791.0, + 19801.0, + 19906.0, + 19927.0, + 19925.0, + 19914.0, + 20191.0, + 20104.0, + 19900.0, + 19760.0, + 19818.0, + 19819.0, + 19805.0, + 19704.0, + 19712.0, + 19725.0, + 19707.0, + 19737.0, + 19737.0, + 19681.0, + 19667.0, + 19694.0, + 19713.0, + 19704.0, + 19713.0, + 19730.0, + 19691.0, + 19680.0, + 19615.0, + 19570.0, + 19546.0, + 19589.0, + 19683.0, + 19593.0, + 19448.0, + 19580.0, + 19547.0, + 19617.0, + 19561.0, + 19635.0, + 19700.0, + 19639.0, + 19713.0, + 19950.0, + 19892.0, + 19913.0, + 19970.0, + 19902.0, + 19912.0, + 19938.0, + 20224.0, + 20183.0, + 20159.0, + 20245.0, + 20137.0, + 20095.0, + 20262.0, + 20318.0, + 20387.0, + 20294.0, + 20254.0, + 20268.0, + 20366.0, + 20242.0, + 20226.0, + 20177.0, + 20277.0, + 20417.0, + 20352.0, + 20296.0, + 20350.0, + 20546.0, + 20526.0, + 20463.0, + 20413.0, + 20316.0, + 20511.0, + 20458.0, + 20407.0, + 20483.0, + 20441.0, + 20335.0, + 20405.0, + 20424.0, + 20392.0, + 20392.0, + 20331.0, + 20389.0, + 20452.0, + 20110.0, + 20013.0, + 19900.0, + 19997.0, + 20076.0, + 20071.0, + 20136.0, + 20040.0, + 20027.0, + 20033.0, + 20060.0, + 20016.0, + 20012.0, + 20034.0, + 19997.0, + 19855.0, + 19951.0, + 19918.0, + 19907.0, + 19949.0, + 19949.0, + 19942.0, + 20002.0, + 20001.0, + 20067.0, + 20004.0, + 20000.0, + 20003.0, + 19968.0, + 20014.0, + 19993.0, + 19992.0, + 20010.0, + 19909.0, + 19936.0, + 19919.0, + 19878.0, + 19912.0, + 19817.0, + 19846.0, + 19716.0, + 19621.0, + 19666.0, + 19641.0, + 19660.0, + 19660.0, + 19706.0, + 19582.0, + 19623.0, + 19626.0, + 19581.0, + 19587.0, + 19640.0, + 19658.0, + 19654.0, + 19679.0, + 19705.0, + 19764.0, + 19685.0, + 19714.0, + 19736.0, + 19685.0, + 19745.0, + 19762.0, + 19722.0, + 19702.0, + 19665.0, + 19684.0, + 19598.0, + 19541.0, + 19267.0, + 19031.0, + 19488.0, + 19578.0, + 19811.0, + 19844.0, + 19847.0, + 20258.0, + 20243.0, + 20242.0, + 20090.0, + 20183.0, + 20160.0, + 20205.0, + 19870.0, + 19913.0, + 19710.0, + 19658.0, + 19731.0, + 19735.0, + 19756.0, + 19702.0, + 19728.0, + 19668.0, + 19726.0, + 19721.0, + 19683.0, + 19660.0, + 19661.0, + 19630.0, + 19625.0, + 19709.0, + 19674.0, + 19698.0, + 19699.0, + 19705.0, + 19697.0, + 19686.0, + 19690.0, + 19684.0, + 19907.0, + 19692.0, + 19780.0, + 19682.0, + 19699.0, + 19759.0, + 19801.0, + 19820.0, + 19973.0, + 20025.0, + 19852.0, + 19840.0, + 19837.0, + 19828.0, + 19846.0, + 19855.0, + 19859.0, + 19846.0, + 19955.0, + 19841.0, + 19886.0, + 19827.0, + 19679.0, + 19692.0, + 19499.0, + 19562.0, + 19602.0, + 19579.0, + 19590.0, + 19572.0, + 19530.0, + 19621.0, + 19616.0, + 19541.0, + 19696.0, + 19636.0, + 19670.0, + 19628.0, + 19582.0, + 19517.0, + 19510.0, + 19569.0, + 19550.0, + 19605.0, + 19570.0, + 19594.0, + 19592.0, + 19503.0, + 19492.0, + 19480.0, + 19482.0, + 19506.0, + 19496.0, + 19481.0, + 19432.0, + 19514.0, + 19431.0, + 19465.0, + 19464.0, + 19486.0, + 19461.0, + 19427.0, + 19442.0, + 19434.0, + 19436.0, + 19417.0, + 19432.0, + 19431.0, + 19460.0, + 19474.0, + 19519.0, + 19447.0, + 19468.0, + 19490.0, + 19478.0, + 19443.0, + 19479.0, + 19460.0, + 19434.0, + 19469.0, + 19439.0, + 19447.0, + 19473.0, + 19735.0, + 19766.0, + 19774.0, + 19840.0, + 19745.0, + 19696.0, + 19635.0, + 19641.0, + 19718.0, + 19749.0, + 19600.0, + 19565.0, + 19531.0, + 19576.0, + 19601.0, + 19559.0, + 19511.0, + 19566.0, + 19584.0, + 19581.0, + 19537.0, + 19564.0, + 19552.0, + 19823.0, + 20185.0, + 20305.0, + 20290.0, + 20161.0, + 20360.0, + 20354.0, + 20265.0, + 20279.0, + 20534.0, + 20557.0, + 20514.0, + 20697.0, + 20660.0, + 20594.0, + 20567.0, + 20571.0, + 20583.0, + 20616.0, + 20633.0, + 20574.0, + 20529.0, + 20510.0, + 20523.0, + 20602.0, + 20635.0, + 20670.0, + 20481.0, + 20349.0, + 20326.0, + 20311.0, + 20330.0, + 20177.0, + 20281.0, + 20264.0, + 20539.0, + 20619.0, + 20758.0, + 20676.0, + 20655.0, + 20672.0, + 20694.0, + 20819.0, + 20730.0, + 20836.0, + 21015.0, + 20754.0, + 20850.0, + 20981.0, + 20886.0, + 20902.0, + 20920.0, + 20869.0, + 20849.0, + 20840.0, + 20873.0, + 20926.0, + 20774.0, + 20849.0, + 20728.0, + 20738.0, + 20734.0, + 20715.0, + 20785.0, + 20723.0, + 20625.0, + 20599.0, + 20651.0, + 20694.0, + 20813.0, + 20846.0, + 20579.0, + 20641.0, + 20620.0, + 20601.0, + 20633.0, + 20724.0, + 20727.0, + 20693.0, + 20692.0, + 20726.0, + 20731.0, + 20645.0, + 20562.0, + 20714.0, + 20677.0, + 20706.0, + 20692.0, + 20741.0, + 20744.0, + 20746.0, + 20714.0, + 20657.0, + 20669.0, + 20652.0, + 20604.0, + 20660.0, + 20687.0, + 20623.0, + 20525.0, + 20542.0, + 20667.0, + 20669.0, + 20745.0, + 20760.0, + 20830.0, + 20662.0, + 20625.0, + 20735.0, + 20763.0, + 20774.0, + 20775.0, + 20716.0, + 20770.0, + 20803.0, + 20910.0, + 21091.0, + 21044.0, + 20984.0, + 21034.0, + 21079.0, + 20978.0, + 21185.0, + 21265.0, + 21251.0, + 21447.0, + 21518.0, + 21476.0, + 21466.0, + 21366.0, + 21482.0, + 21371.0, + 21393.0, + 21407.0, + 21419.0, + 21419.0, + 21381.0, + 21304.0, + 21332.0, + 21241.0, + 21281.0, + 21332.0, + 21344.0, + 21330.0, + 21340.0, + 21342.0, + 21350.0, + 21313.0, + 21069.0, + 21128.0, + 21019.0, + 20990.0, + 20792.0, + 20735.0, + 20788.0, + 20760.0, + 20780.0, + 20676.0, + 20788.0, + 20653.0, + 20555.0, + 20615.0, + 20142.0, + 19743.0, + 19837.0, + 19789.0, + 19731.0, + 19574.0, + 19404.0, + 19201.0, + 18235.0, + 18745.0, + 18445.0, + 18226.0, + 18215.0, + 18281.0, + 18168.0, + 17688.0, + 17758.0, + 17603.0, + 17099.0, + 16884.0, + 16814.0, + 15744.0, + 15890.0, + 16121.0, + 16321.0, + 16676.0, + 16753.0, + 16725.0, + 16342.0, + 17346.0, + 17234.0, + 16987.0, + 17143.0, + 17462.0, + 17255.0, + 16955.0, + 16719.0, + 16961.0, + 16968.0, + 16909.0, + 16843.0, + 16760.0, + 16307.0, + 16339.0, + 16216.0, + 16198.0, + 16428.0, + 16289.0, + 16309.0, + 16112.0, + 16212.0, + 16273.0, + 16294.0, + 16250.0, + 16300.0, + 16282.0, + 16269.0, + 16202.0, + 16196.0, + 16277.0, + 16300.0, + 16255.0, + 16165.0, + 15940.0, + 16038.0, + 16039.0, + 15932.0, + 15929.0, + 15939.0, + 15808.0, + 15797.0, + 15576.0, + 15613.0, + 15356.0, + 16282.0, + 16206.0, + 16285.0, + 16225.0, + 16052.0, + 16027.0, + 15691.0, + 15886.0, + 16063.0, + 16173.0, + 16279.0, + 16108.0, + 16188.0, + 16116.0, + 16094.0, + 16293.0, + 16382.0, + 16360.0, + 16255.0, + 16325.0, + 16314.0, + 16300.0, + 16382.0, + 16318.0, + 16170.0, + 16049.0, + 16039.0, + 15858.0, + 15785.0, + 15964.0, + 15931.0, + 15924.0, + 16010.0, + 16092.0, + 15950.0, + 15972.0, + 15990.0, + 15947.0, + 16028.0, + 15987.0, + 16018.0, + 16129.0, + 16022.0, + 16092.0, + 16105.0, + 16243.0, + 16239.0, + 16180.0, + 16130.0, + 16109.0, + 16134.0, + 16164.0, + 16101.0, + 16041.0, + 16098.0, + 16129.0, + 16160.0, + 16113.0, + 16081.0, + 16056.0, + 16069.0, + 16087.0, + 16123.0, + 16116.0, + 16095.0, + 16059.0, + 16085.0, + 16138.0, + 16169.0, + 16150.0, + 16150.0, + 16163.0, + 16194.0, + 16108.0, + 16000.0, + 16036.0, + 16034.0, + 16004.0, + 16035.0, + 15756.0, + 15737.0, + 15704.0, + 15585.0, + 15764.0, + 15604.0, + 15708.0, + 15667.0, + 15756.0, + 15725.0, + 15633.0, + 15353.0, + 15272.0, + 15372.0, + 15378.0, + 15431.0, + 15392.0, + 15307.0, + 15251.0, + 15310.0, + 15717.0, + 15764.0, + 15585.0, + 15696.0, + 15658.0, + 15716.0, + 15719.0, + 16027.0, + 15897.0, + 16001.0, + 16016.0, + 16035.0, + 15842.0, + 15819.0, + 15813.0, + 15841.0, + 15854.0, + 15938.0, + 16046.0, + 15987.0, + 15943.0, + 15951.0, + 15900.0, + 15904.0, + 15910.0, + 15900.0, + 15912.0, + 15911.0, + 15885.0, + 15938.0, + 15853.0, + 15829.0, + 15712.0, + 15798.0, + 15822.0, + 15873.0, + 15884.0, + 15841.0, + 15845.0, + 15861.0, + 15851.0, + 15857.0, + 15976.0, + 15964.0, + 15989.0, + 15942.0, + 15951.0, + 15938.0, + 15970.0, + 15882.0, + 15891.0, + 15858.0, + 15869.0, + 15832.0, + 15847.0, + 15898.0, + 15886.0, + 15925.0, + 15893.0, + 15906.0, + 15908.0, + 15917.0, + 15877.0, + 15920.0, + 15967.0, + 15840.0, + 15591.0, + 15631.0, + 15613.0, + 15652.0, + 15528.0, + 15467.0, + 15473.0, + 15519.0, + 15635.0, + 15701.0, + 15675.0, + 15667.0, + 15692.0, + 15692.0, + 15842.0, + 15853.0, + 15917.0, + 15877.0, + 15870.0, + 15809.0, + 15837.0, + 15913.0, + 15925.0, + 15927.0, + 16290.0, + 16251.0, + 16273.0, + 16314.0, + 16291.0, + 16294.0, + 16224.0, + 16354.0, + 16258.0, + 16400.0, + 16427.0, + 16481.0, + 16418.0, + 16436.0, + 16390.0, + 16436.0, + 16404.0, + 16401.0, + 16292.0, + 16194.0, + 16161.0, + 16129.0, + 16106.0, + 16138.0, + 16096.0, + 16055.0, + 16082.0, + 16123.0, + 16130.0, + 16143.0, + 16166.0, + 16195.0, + 16114.0, + 16147.0, + 16165.0, + 16238.0, + 16184.0, + 16179.0, + 16172.0, + 16122.0, + 16132.0, + 16102.0, + 16111.0, + 16126.0, + 16119.0, + 16117.0, + 16095.0, + 16040.0, + 16133.0, + 16120.0, + 16174.0, + 16153.0, + 16166.0, + 16103.0, + 16108.0, + 16170.0, + 16196.0, + 16209.0, + 16249.0, + 16221.0, + 16339.0, + 16252.0, + 16390.0, + 16441.0, + 16401.0, + 16385.0, + 16306.0, + 16240.0, + 16242.0, + 16136.0, + 16187.0, + 16169.0, + 16200.0, + 16222.0, + 16177.0, + 16208.0, + 16185.0, + 16157.0, + 16170.0, + 16165.0, + 16182.0, + 16224.0, + 16223.0, + 16320.0, + 16268.0, + 16261.0, + 16253.0, + 16022.0, + 16081.0, + 16010.0, + 16002.0, + 16036.0, + 15983.0, + 16003.0, + 16031.0, + 16022.0, + 16026.0, + 16028.0, + 16014.0, + 16000.0, + 16002.0, + 16040.0, + 16008.0, + 16047.0, + 16076.0, + 16327.0, + 16263.0, + 16312.0, + 16285.0, + 16258.0, + 16274.0, + 16277.0, + 16321.0, + 16337.0, + 16280.0, + 16285.0, + 16276.0, + 16239.0, + 16229.0, + 16235.0, + 16276.0, + 16267.0, + 16264.0, + 16277.0, + 16265.0, + 16302.0, + 16273.0, + 16320.0, + 16276.0, + 16301.0, + 16267.0, + 16263.0, + 16299.0, + 16280.0, + 16302.0, + 16295.0, + 16306.0, + 16303.0, + 16263.0, + 16292.0, + 16308.0, + 16311.0, + 16247.0, + 16252.0, + 16121.0, + 16084.0, + 16113.0, + 16065.0, + 16070.0, + 16065.0, + 16057.0, + 16172.0, + 16149.0, + 16190.0, + 16288.0, + 16298.0, + 16237.0, + 16279.0, + 16268.0, + 16271.0, + 16483.0, + 16542.0, + 16794.0, + 16677.0, + 16600.0, + 16678.0, + 16707.0, + 16728.0, + 16718.0, + 16739.0, + 16731.0, + 16750.0, + 16706.0, + 16740.0, + 16791.0, + 16953.0, + 16992.0, + 16687.0, + 16683.0, + 16659.0, + 16538.0, + 16647.0, + 16614.0, + 16632.0, + 16671.0, + 16680.0, + 16445.0, + 16363.0, + 16414.0, + 16390.0, + 16353.0, + 16311.0, + 16309.0, + 16353.0, + 16340.0, + 16452.0, + 16044.0, + 16007.0, + 15914.0, + 15968.0, + 15821.0, + 15900.0, + 15874.0, + 15696.0, + 15763.0, + 15764.0, + 15753.0, + 15832.0, + 15759.0, + 15787.0, + 15754.0, + 15778.0, + 15751.0, + 15774.0, + 15788.0, + 15857.0, + 15781.0, + 15820.0, + 15822.0, + 15816.0, + 15779.0, + 15791.0, + 15792.0, + 15760.0, + 15781.0, + 15814.0, + 15809.0, + 15818.0, + 15843.0, + 15743.0, + 15743.0, + 15748.0, + 15757.0, + 15773.0, + 15741.0, + 15734.0, + 15596.0, + 15593.0, + 15627.0, + 15468.0, + 15603.0, + 15748.0, + 15831.0, + 15832.0, + 15801.0, + 15795.0, + 15801.0, + 15906.0, + 15839.0, + 15898.0, + 15877.0, + 15906.0, + 15868.0, + 15858.0, + 15839.0, + 15818.0, + 15901.0, + 15916.0, + 15846.0, + 15870.0, + 15867.0, + 15774.0, + 15837.0, + 15860.0, + 15820.0, + 15832.0, + 15811.0, + 15805.0, + 15828.0, + 15857.0, + 15793.0, + 15692.0, + 15678.0, + 15734.0, + 15843.0, + 15861.0, + 15825.0, + 15859.0, + 15857.0, + 15850.0, + 15866.0, + 15873.0, + 15883.0, + 15863.0, + 15865.0, + 15869.0, + 15839.0, + 15773.0, + 15832.0, + 15847.0, + 15814.0, + 15854.0, + 15854.0, + 15818.0, + 15809.0, + 15845.0, + 15848.0, + 15847.0, + 15834.0, + 15822.0, + 15826.0, + 15823.0, + 15843.0, + 15834.0, + 15854.0, + 15820.0, + 15830.0, + 15819.0, + 15815.0, + 15805.0, + 15842.0, + 15831.0, + 15879.0, + 15912.0, + 15848.0, + 15827.0, + 15837.0, + 15866.0, + 15842.0, + 15811.0, + 15837.0, + 15836.0, + 15815.0, + 15897.0, + 15820.0, + 15824.0, + 15802.0, + 15821.0, + 15807.0, + 15786.0, + 15823.0, + 15755.0, + 15675.0, + 15678.0, + 15700.0, + 15707.0, + 15673.0, + 15658.0, + 15592.0, + 15637.0, + 15631.0, + 15650.0, + 15619.0, + 15585.0, + 15647.0, + 15622.0, + 15550.0, + 15569.0, + 15544.0, + 15560.0, + 15606.0, + 15579.0, + 15578.0, + 15599.0, + 15578.0, + 15561.0, + 15532.0, + 15562.0, + 15565.0, + 15580.0, + 15585.0, + 15581.0, + 15529.0, + 15473.0, + 15501.0, + 15452.0, + 15438.0, + 15523.0, + 15415.0, + 15454.0, + 15497.0, + 15518.0, + 15479.0, + 15451.0, + 15452.0, + 15476.0, + 15445.0, + 15461.0, + 15510.0, + 15504.0, + 15489.0, + 15470.0, + 15444.0, + 15439.0, + 15437.0, + 15433.0, + 15425.0, + 15426.0, + 15439.0, + 15465.0, + 15462.0, + 15442.0, + 15466.0, + 15504.0, + 15516.0, + 15533.0, + 15483.0, + 15569.0, + 15549.0, + 15661.0, + 15653.0, + 15660.0, + 15629.0, + 15692.0, + 15666.0, + 15682.0, + 15682.0, + 15605.0, + 15639.0, + 15621.0, + 15637.0, + 15710.0, + 15859.0, + 15874.0, + 15833.0, + 15790.0, + 15763.0, + 15729.0, + 15770.0, + 15784.0, + 15803.0, + 15929.0, + 15921.0, + 15897.0, + 15869.0, + 15869.0, + 15856.0, + 15889.0, + 15936.0, + 15872.0, + 15849.0, + 15896.0, + 15838.0, + 15866.0, + 15863.0, + 15847.0, + 15797.0, + 15848.0, + 15895.0, + 16001.0, + 15970.0, + 16001.0, + 15992.0, + 16001.0, + 15975.0, + 15991.0, + 15988.0, + 15966.0, + 15953.0, + 15944.0, + 15887.0, + 15871.0, + 15823.0, + 15888.0, + 15891.0, + 15924.0, + 15926.0, + 15922.0, + 15910.0, + 15929.0, + 15888.0, + 15887.0, + 15901.0, + 15926.0, + 15919.0, + 15910.0, + 15904.0, + 15911.0, + 15912.0, + 15921.0, + 15923.0, + 15904.0, + 15911.0, + 15910.0, + 15883.0, + 15962.0, + 15883.0, + 15879.0, + 15918.0, + 16069.0, + 16114.0, + 16126.0, + 16091.0, + 16114.0, + 16156.0, + 16148.0, + 16070.0, + 16073.0, + 16150.0, + 16101.0, + 16016.0, + 16017.0, + 16027.0 + ], + "type": "scatter", + "xaxis": "x3", + "yaxis": "y3" + } + ], + "layout": { + "template": { + "data": { + "histogram2dcontour": [ + { + "type": "histogram2dcontour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "choropleth": [ + { + "type": "choropleth", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "histogram2d": [ + { + "type": "histogram2d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmap": [ + { + "type": "heatmap", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmapgl": [ + { + "type": "heatmapgl", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "contourcarpet": [ + { + "type": "contourcarpet", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "contour": [ + { + "type": "contour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "surface": [ + { + "type": "surface", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "mesh3d": [ + { + "type": "mesh3d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "parcoords": [ + { + "type": "parcoords", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolargl": [ + { + "type": "scatterpolargl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "scattergeo": [ + { + "type": "scattergeo", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolar": [ + { + "type": "scatterpolar", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "scattergl": [ + { + "type": "scattergl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatter3d": [ + { + "type": "scatter3d", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattermapbox": [ + { + "type": "scattermapbox", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterternary": [ + { + "type": "scatterternary", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattercarpet": [ + { + "type": "scattercarpet", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ] + }, + "layout": { + "autotypenumbers": "strict", + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "hovermode": "closest", + "hoverlabel": { + "align": "left" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "bgcolor": "#E5ECF6", + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "ternary": { + "bgcolor": "#E5ECF6", + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ] + }, + "xaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "automargin": true, + "zerolinewidth": 2 + }, + "yaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "automargin": true, + "zerolinewidth": 2 + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "geo": { + "bgcolor": "white", + "landcolor": "#E5ECF6", + "subunitcolor": "white", + "showland": true, + "showlakes": true, + "lakecolor": "white" + }, + "title": { + "x": 0.05 + }, + "mapbox": { + "style": "light" + } + } + }, + "xaxis": { + "anchor": "y", + "domain": [ + 0.0, + 1.0 + ], + "title": { + "text": "Date" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0.68, + 1.0 + ], + "title": { + "text": "Prices down turn" + } + }, + "xaxis2": { + "anchor": "y2", + "domain": [ + 0.0, + 1.0 + ], + "title": { + "text": "Date" + } + }, + "yaxis2": { + "anchor": "x2", + "domain": [ + 0.34, + 0.66 + ], + "title": { + "text": "Prices up turn" + } + }, + "xaxis3": { + "anchor": "y3", + "domain": [ + 0.0, + 1.0 + ], + "title": { + "text": "Date" + } + }, + "yaxis3": { + "anchor": "x3", + "domain": [ + 0.0, + 0.32 + ], + "title": { + "text": "Prices side way" + } + }, + "title": { + "text": "Backtest date range close prices" + }, + "height": 600, + "width": 800 + }, + "config": { + "plotlyServerURL": "https://plot.ly" + } + }, + "text/html": "
" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from investing_algorithm_framework import create_app, BacktestDateRange, CCXTOHLCVMarketDataSource, RESOURCE_DIRECTORY, PortfolioConfiguration\n", + "from plotly import graph_objects as go\n", + "from pandas import DataFrame as PandasDataFrame\n", + "from datetime import datetime\n", + "\n", + "# Define the backtest date ranges\n", + "up_turn_date_range = BacktestDateRange(\n", + " start_date=datetime(2022, 12, 20),\n", + " end_date=datetime(2023, 6, 1),\n", + " name=\"up_turn\"\n", + ")\n", + "sideways_date_range = BacktestDateRange(\n", + " start_date=datetime(2022, 6, 10),\n", + " end_date=datetime(2023, 1, 10),\n", + " name=\"sideways\"\n", + ")\n", + "down_turn_date_range = BacktestDateRange(\n", + " start_date=datetime(2021, 12, 21),\n", + " end_date=datetime(2022, 6, 20),\n", + " name=\"down_turn\"\n", + ")\n", + "\n", + "# Create the app and the champion and challenger algorithms\n", + "app = create_app(config={RESOURCE_DIRECTORY: \"resources_dump\"})\n", + "app.add_portfolio_configuration(PortfolioConfiguration(initial_balance=1000, trading_symbol=\"EUR\", market=\"BITVAVO\"))\n", + "\n", + "champion = create_primary_algorithm(\n", + " name=\"primary\",\n", + " description=\"This is the primary algorithm configured with 21 ema and 50 ema\",\n", + " long_period=50,\n", + " short_period=21\n", + ")\n", + "challenger = create_challenger_algorithm(\n", + " name=\"secondary\",\n", + " description=\"This is the primary algorithm configured with 21 ema and 50 ema\",\n", + " long_period=50,\n", + " short_period=21,\n", + " rsi_period=14,\n", + " rsi_sell_threshold=70,\n", + " rsi_buy_threshold=60\n", + ")\n", + "\n", + "def create_prices_graph(data: PandasDataFrame, name: str = \"Close\", color: str = \"blue\") -> go.Scatter:\n", + " return go.Scatter(\n", + " x=data.index,\n", + " y=data['Close'],\n", + " mode='lines',\n", + " line=dict(color=color, width=1),\n", + " name=name\n", + " )\n", + "\n", + "down_turn_data_source = CCXTOHLCVMarketDataSource(window_size=100, timeframe=\"2h\", market=\"bitvavo\", symbol=\"BTC/EUR\", identifier=\"BTC/EUR_OHLCV\")\n", + "df_down_turn = down_turn_data_source.get_data(start_date=down_turn_date_range.start_date, end_date=down_turn_date_range.end_date).to_pandas()\n", + "df_down_turn.set_index('Datetime', inplace=True)\n", + "up_turn_data_source = CCXTOHLCVMarketDataSource(window_size=100, timeframe=\"2h\", market=\"bitvavo\", symbol=\"BTC/EUR\", identifier=\"BTC/EUR_OHLCV\")\n", + "df_up_turn = up_turn_data_source.get_data(start_date=up_turn_date_range.start_date, end_date=up_turn_date_range.end_date).to_pandas()\n", + "df_up_turn.set_index('Datetime', inplace=True)\n", + "side_way_data_source = CCXTOHLCVMarketDataSource(window_size=100, timeframe=\"2h\", market=\"bitvavo\", symbol=\"BTC/EUR\", identifier=\"BTC/EUR_OHLCV\")\n", + "df_side_way = side_way_data_source.get_data(start_date=sideways_date_range.start_date, end_date=sideways_date_range.end_date).to_pandas()\n", + "df_side_way.set_index('Datetime', inplace=True)\n", + "\n", + "from plotly.subplots import make_subplots\n", + "fig = make_subplots(rows=3, cols=1, shared_xaxes=False, vertical_spacing=0.02)\n", + "fig.add_trace(create_prices_graph(df_down_turn, name=\"Close down turn\", color=\"red\"), row=1, col=1)\n", + "fig.add_trace(create_prices_graph(df_up_turn, name=\"Close up turn\", color=\"green\"), row=2, col=1)\n", + "fig.add_trace(create_prices_graph(df_side_way, name=\"Close side ways\", color=\"blue\"), row=3, col=1)\n", + "\n", + "fig.update_layout(height=600, width=800, title_text=\"Backtest date range close prices\")\n", + "\n", + "# Add titles to each subplot\n", + "fig.update_xaxes(title_text=\"Date\", row=1, col=1)\n", + "fig.update_yaxes(title_text=\"Prices down turn\", row=1, col=1)\n", + "fig.update_xaxes(title_text=\"Date\", row=2, col=1)\n", + "fig.update_yaxes(title_text=\"Prices up turn\", row=2, col=1)\n", + "fig.update_xaxes(title_text=\"Date\", row=3, col=1)\n", + "fig.update_yaxes(title_text=\"Prices side way\", row=3, col=1)\n", + "fig.show()" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 3: Running the backtests for all the date ranges" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[93mRunning backtests for date range:\u001B[0m \u001B[92mdown_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 for a total of 2 algorithms.\u001B[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 41.78it/s]\n", + "Running backtest for algorithm with name primary: 100%|\u001B[32m██████████\u001B[0m| 2173/2173 [00:09<00:00, 230.93it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1036.78it/s]\n", + "Running backtest for algorithm with name secondary: 100%|\u001B[32m██████████\u001B[0m| 2173/2173 [00:09<00:00, 224.02it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[93mRunning backtests for date range:\u001B[0m \u001B[92mup_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 for a total of 2 algorithms.\u001B[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 185.70it/s]\n", + "Running backtest for algorithm with name primary: 100%|\u001B[32m██████████\u001B[0m| 1957/1957 [00:10<00:00, 195.16it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1174.88it/s]\n", + "Running backtest for algorithm with name secondary: 100%|\u001B[32m██████████\u001B[0m| 1957/1957 [00:07<00:00, 270.07it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[93mRunning backtests for date range:\u001B[0m \u001B[92msideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 for a total of 2 algorithms.\u001B[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 91.59it/s]\n", + "Running backtest for algorithm with name primary: 100%|\u001B[32m██████████\u001B[0m| 2569/2569 [00:11<00:00, 219.38it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1236.71it/s]\n", + "Running backtest for algorithm with name secondary: 100%|\u001B[32m██████████\u001B[0m| 2569/2569 [00:09<00:00, 268.31it/s]\n" + ] + } + ], + "source": [ + "reports = app.run_backtests(algorithms=[champion, challenger], date_ranges=[down_turn_date_range, up_turn_date_range, sideways_date_range])" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 4: Analyzing the backtest results" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " :%%%#+- .=*#%%% \u001B[92mBacktest reports evaluation\u001B[0m\n", + " *%%%%%%%+------=*%%%%%%%- \u001B[92m---------------------------\u001B[0m\n", + " *%%%%%%%%%%%%%%%%%%%%%%%- \u001B[93mNumber of reports:\u001B[0m \u001B[92m6 backtest reports\u001B[0m\n", + " .%%%%%%%%%%%%%%%%%%%%%%# \u001B[93mTotal number of date ranges:\u001B[0m\u001B[92m3\u001B[0m\n", + " #%%%####%%%%%%%%**#%%%+ \u001B[93mLargest overall profit:\u001B[0m\u001B[92m\u001B[0m\u001B[92m (Algorithm primary) 121.6183 EUR 12.1618% (up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00)\u001B[0m \n", + " .:-+*%%%%- \u001B[95m-+..#\u001B[0m%%%+.\u001B[95m+- +\u001B[0m%%%#*=-: \u001B[93mLargest overall growth:\u001B[0m\u001B[92m (Algorithm primary) 127.5655 EUR 12.7565% (up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00)\u001B[0m\n", + " .:-=*%%%%. \u001B[95m+=\u001B[0m .%%# \u001B[95m-+.-\u001B[0m%%%%=-:.. \n", + " .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: \n", + " +%%%%%%%%%%%%%%%%%%%= \n", + " :++ .=#%%%%%%%%%%%%%*- \n", + " :++: :+%%%%%%#-. \n", + " :++: .%%%%%#= \n", + " :++: .#%%%%%#*= \n", + " :++- :%%%%%%%%%+= \n", + " .++- -%%%%%%%%%%%+= \n", + " .++- .%%%%%%%%%%%%%+= \n", + " .++- *%%%%%%%%%%%%%*+: \n", + " .++- %%%%%%%%%%%%%%#+= \n", + " =++........:::%%%%%%%%%%%%%%*+- \n", + " .=++++++++++**#%%%%%%%%%%%%%++. \n", + " \n", + "\u001B[93mDate ranges of backtests:\u001B[0m\n", + "\u001B[92mdown_turn: 2021-12-21 00:00:00 - 2022-06-20 00:00:00\u001B[0m\n", + "\u001B[92mup_turn: 2022-12-20 00:00:00 - 2023-06-01 00:00:00\u001B[0m\n", + "\u001B[92msideways: 2022-06-10 00:00:00 - 2023-01-10 00:00:00\u001B[0m\n", + "\n", + "\u001B[93mAll profits ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬─────────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Profit │ Profit percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary │ 121.6183 EUR │ 12.1618% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1127.57 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ secondary │ 70.6731 EUR │ 7.0673% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1075.01 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ secondary │ -3.3966 EUR │ -0.3397% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 941.031 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary │ -8.5178 EUR │ -0.8518% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 997.613 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ secondary │ -50.7186 EUR │ -5.0719% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 949.281 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary │ -57.1643 EUR │ -5.7164% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 942.836 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴─────────────────────────────────────────────────────┴───────────────╯\n", + "\u001B[93mAll growths ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬─────────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Growth │ Growth percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary │ 127.5655 EUR │ 12.7565% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1127.57 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ secondary │ 75.0139 EUR │ 7.5014% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1075.01 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary │ -2.3874 EUR │ -0.2387% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 997.613 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ secondary │ -50.7186 EUR │ -5.0719% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 949.281 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary │ -57.1643 EUR │ -5.7164% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 942.836 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ secondary │ -58.9687 EUR │ -5.8969% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 941.031 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴─────────────────────────────────────────────────────┴───────────────╯\n" + ] + } + ], + "source": [ + "from investing_algorithm_framework import pretty_print_backtest_reports_evaluation, BacktestReportsEvaluation\n", + "\n", + "evaluation = BacktestReportsEvaluation(reports)\n", + "pretty_print_backtest_reports_evaluation(evaluation)" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 5: Highlighting the winning algorithm" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 13, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The winning algorithm is primary\n", + "\n", + " :%%%#+- .=*#%%% \u001B[92mBacktest report\u001B[0m\n", + " *%%%%%%%+------=*%%%%%%%- \u001B[92m---------------------------\u001B[0m\n", + " *%%%%%%%%%%%%%%%%%%%%%%%- \u001B[93mStart date:\u001B[0m\u001B[92m 2022-12-20 00:00:00\u001B[0m\n", + " .%%%%%%%%%%%%%%%%%%%%%%# \u001B[93mEnd date:\u001B[0m\u001B[92m 2023-06-01 00:00:00\u001B[0m\n", + " #%%%####%%%%%%%%**#%%%+ \u001B[93mNumber of days:\u001B[0m\u001B[92m\u001B[0m\u001B[92m 163\u001B[0m \n", + " .:-+*%%%%- \u001B[95m-+..#\u001B[0m%%%+.\u001B[95m+- +\u001B[0m%%%#*=-: \u001B[93mNumber of runs:\u001B[0m\u001B[92m 1957\u001B[0m\n", + " .:-=*%%%%. \u001B[95m+=\u001B[0m .%%# \u001B[95m-+.-\u001B[0m%%%%=-:.. \u001B[93mNumber of orders:\u001B[0m\u001B[92m 39\u001B[0m\n", + " .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: \u001B[93mInitial balance:\u001B[0m\u001B[92m 1000.0\u001B[0m\n", + " +%%%%%%%%%%%%%%%%%%%= \u001B[93mFinal balance:\u001B[0m\u001B[92m 1127.5655\u001B[0m\n", + " :++ .=#%%%%%%%%%%%%%*- \u001B[93mTotal net gain:\u001B[0m\u001B[92m 121.6183 12.16%\u001B[0m\n", + " :++: :+%%%%%%#-. \u001B[93mGrowth:\u001B[0m\u001B[92m 127.5655 12.76%\u001B[0m\n", + " :++: .%%%%%#= \u001B[93mNumber of trades closed:\u001B[0m\u001B[92m 19\u001B[0m\n", + " :++: .#%%%%%#*= \u001B[93mNumber of trades open(end of backtest):\u001B[0m\u001B[92m 1\u001B[0m\n", + " :++- :%%%%%%%%%+= \u001B[93mPercentage positive trades:\u001B[0m\u001B[92m 25.64102564102564%\u001B[0m\n", + " .++- -%%%%%%%%%%%+= \u001B[93mPercentage negative trades:\u001B[0m\u001B[92m 71.7948717948718%\u001B[0m\n", + " .++- .%%%%%%%%%%%%%+= \u001B[93mAverage trade size:\u001B[0m\u001B[92m 275.8284 EUR\u001B[0m\n", + " .++- *%%%%%%%%%%%%%*+: \u001B[93mAverage trade duration:\u001B[0m\u001B[92m 106.10526315789474 hours\u001B[0m\n", + " .++- %%%%%%%%%%%%%%#+= \n", + " =++........:::%%%%%%%%%%%%%%*+- \n", + " .=++++++++++**#%%%%%%%%%%%%%++. \n", + " \n", + "\u001B[93mPositions overview\u001B[0m\n", + "╭────────────┬──────────┬──────────────────────┬───────────────────────┬──────────────┬───────────────┬───────────────────────────┬────────────────┬───────────────╮\n", + "│ Position │ Amount │ Pending buy amount │ Pending sell amount │ Cost (EUR) │ Value (EUR) │ Percentage of portfolio │ Growth (EUR) │ Growth_rate │\n", + "├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤\n", + "│ EUR │ 842.497 │ 0 │ 0 │ 842.497 │ 842.497 │ 74.7183% │ 0 │ 0.0000% │\n", + "├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤\n", + "│ BTC │ 0.0112 │ 0 │ 0 │ 279.121 │ 285.068 │ 25.2817% │ 5.9472 │ 2.1307% │\n", + "╰────────────┴──────────┴──────────────────────┴───────────────────────┴──────────────┴───────────────┴───────────────────────────┴────────────────┴───────────────╯\n", + "\u001B[93mTrades overview\u001B[0m\n", + "╭─────────┬─────────────────────┬─────────────────────┬────────────────────┬──────────────┬──────────────────┬───────────────────────┬────────────────────┬─────────────────────╮\n", + "│ Pair │ Open date │ Close date │ Duration (hours) │ Size (EUR) │ Net gain (EUR) │ Net gain percentage │ Open price (EUR) │ Close price (EUR) │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-05-27 02:00:00 │ │ 8814.81 │ 279.121 │ 0 │ 0.0000% │ 24921.5 │ │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-05-23 04:00:00 │ 2023-05-24 14:00:00 │ 34 │ 281.263 │ -8.1696 │ -2.9046% │ 25339 │ 24603 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-05-20 22:00:00 │ 2023-05-21 18:00:00 │ 20 │ 280.482 │ -1.848 │ -0.6589% │ 25043 │ 24878 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-05-17 20:00:00 │ 2023-05-19 12:00:00 │ 40 │ 282.626 │ -4.0768 │ -1.4425% │ 25234.5 │ 24870.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-05-15 06:00:00 │ 2023-05-17 06:00:00 │ 48 │ 283.002 │ -4.2168 │ -1.4900% │ 25268 │ 24891.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-05-04 08:00:00 │ 2023-05-08 00:00:00 │ 88 │ 284.035 │ -2.8458 │ -1.0019% │ 26299.5 │ 26036 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-04-26 06:00:00 │ 2023-05-01 12:00:00 │ 126 │ 284.224 │ 1.4135 │ 0.4973% │ 25838.5 │ 25967 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-04-18 20:00:00 │ 2023-04-19 12:00:00 │ 16 │ 287.336 │ -8.9492 │ -3.1145% │ 27628.5 │ 26768 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-04-09 22:00:00 │ 2023-04-17 12:00:00 │ 182 │ 283.956 │ 11.0472 │ 3.8904% │ 26051 │ 27064.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-04-05 10:00:00 │ 2023-04-05 16:00:00 │ 6 │ 284.114 │ -2.9212 │ -1.0282% │ 26065.5 │ 25797.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-03-29 14:00:00 │ 2023-04-03 08:00:00 │ 114 │ 285.22 │ -4.7088 │ -1.6509% │ 26167 │ 25735 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-03-26 12:00:00 │ 2023-03-27 16:00:00 │ 28 │ 288.928 │ -9.5016 │ -3.2886% │ 26029.5 │ 25173.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-03-23 14:00:00 │ 2023-03-25 12:00:00 │ 46 │ 289.24 │ -2.7272 │ -0.9429% │ 25825 │ 25581.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-03-13 02:00:00 │ 2023-03-23 14:00:00 │ 252 │ 273.03 │ 58.747 │ 21.5166% │ 20842 │ 25326.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-02-15 08:00:00 │ 2023-02-22 16:00:00 │ 176 │ 268.248 │ 23.491 │ 8.7572% │ 20634.5 │ 22441.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-02-07 22:00:00 │ 2023-02-09 02:00:00 │ 28 │ 268.212 │ -2.5358 │ -0.9454% │ 21630 │ 21425.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-02-01 22:00:00 │ 2023-02-05 20:00:00 │ 94 │ 269.806 │ -4.9563 │ -1.8370% │ 21584.5 │ 21188 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2023-01-02 12:00:00 │ 2023-01-31 06:00:00 │ 690 │ 248.716 │ 85.8918 │ 34.5341% │ 15642.5 │ 21044.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2022-12-26 22:00:00 │ 2022-12-27 06:00:00 │ 8 │ 248.814 │ -0.3689 │ -0.1483% │ 15848 │ 15824.5 │\n", + "├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤\n", + "│ BTC-EUR │ 2022-12-26 02:00:00 │ 2022-12-26 22:00:00 │ 20 │ 249.489 │ -1.1461 │ -0.4594% │ 15891 │ 15818 │\n", + "╰─────────┴─────────────────────┴─────────────────────┴────────────────────┴──────────────┴──────────────────┴───────────────────────┴────────────────────┴─────────────────────╯\n" + ] + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "data": [ + { + "line": { + "color": "blue", + "width": 1 + }, + "mode": "lines", + "name": "Close price up turn", + "x": [ + "2022-12-20T00:00:00", + "2022-12-20T02:00:00", + "2022-12-20T04:00:00", + "2022-12-20T06:00:00", + "2022-12-20T08:00:00", + "2022-12-20T10:00:00", + "2022-12-20T12:00:00", + "2022-12-20T14:00:00", + "2022-12-20T16:00:00", + "2022-12-20T18:00:00", + "2022-12-20T20:00:00", + "2022-12-20T22:00:00", + "2022-12-21T00:00:00", + "2022-12-21T02:00:00", + "2022-12-21T04:00:00", + "2022-12-21T06:00:00", + "2022-12-21T08:00:00", + "2022-12-21T10:00:00", + "2022-12-21T12:00:00", + "2022-12-21T14:00:00", + "2022-12-21T16:00:00", + "2022-12-21T18:00:00", + "2022-12-21T20:00:00", + "2022-12-21T22:00:00", + "2022-12-22T00:00:00", + "2022-12-22T02:00:00", + "2022-12-22T04:00:00", + "2022-12-22T06:00:00", + "2022-12-22T08:00:00", + "2022-12-22T10:00:00", + "2022-12-22T12:00:00", + "2022-12-22T14:00:00", + "2022-12-22T16:00:00", + "2022-12-22T18:00:00", + "2022-12-22T20:00:00", + "2022-12-22T22:00:00", + "2022-12-23T00:00:00", + "2022-12-23T02:00:00", + "2022-12-23T04:00:00", + "2022-12-23T06:00:00", + "2022-12-23T08:00:00", + "2022-12-23T10:00:00", + "2022-12-23T12:00:00", + "2022-12-23T14:00:00", + "2022-12-23T16:00:00", + "2022-12-23T18:00:00", + "2022-12-23T20:00:00", + "2022-12-23T22:00:00", + "2022-12-24T00:00:00", + "2022-12-24T02:00:00", + "2022-12-24T04:00:00", + "2022-12-24T06:00:00", + "2022-12-24T08:00:00", + "2022-12-24T10:00:00", + "2022-12-24T12:00:00", + "2022-12-24T14:00:00", + "2022-12-24T16:00:00", + "2022-12-24T18:00:00", + "2022-12-24T20:00:00", + "2022-12-24T22:00:00", + "2022-12-25T00:00:00", + "2022-12-25T02:00:00", + "2022-12-25T04:00:00", + "2022-12-25T06:00:00", + "2022-12-25T08:00:00", + "2022-12-25T10:00:00", + "2022-12-25T12:00:00", + "2022-12-25T14:00:00", + "2022-12-25T16:00:00", + "2022-12-25T18:00:00", + "2022-12-25T20:00:00", + "2022-12-25T22:00:00", + "2022-12-26T00:00:00", + "2022-12-26T02:00:00", + "2022-12-26T04:00:00", + "2022-12-26T06:00:00", + "2022-12-26T08:00:00", + "2022-12-26T10:00:00", + "2022-12-26T12:00:00", + "2022-12-26T14:00:00", + "2022-12-26T16:00:00", + "2022-12-26T18:00:00", + "2022-12-26T20:00:00", + "2022-12-26T22:00:00", + "2022-12-27T00:00:00", + "2022-12-27T02:00:00", + "2022-12-27T04:00:00", + "2022-12-27T06:00:00", + "2022-12-27T08:00:00", + "2022-12-27T10:00:00", + "2022-12-27T12:00:00", + "2022-12-27T14:00:00", + "2022-12-27T16:00:00", + "2022-12-27T18:00:00", + "2022-12-27T20:00:00", + "2022-12-27T22:00:00", + "2022-12-28T00:00:00", + "2022-12-28T02:00:00", + "2022-12-28T04:00:00", + "2022-12-28T06:00:00", + "2022-12-28T08:00:00", + "2022-12-28T10:00:00", + "2022-12-28T12:00:00", + "2022-12-28T14:00:00", + "2022-12-28T16:00:00", + "2022-12-28T18:00:00", + "2022-12-28T20:00:00", + "2022-12-28T22:00:00", + "2022-12-29T00:00:00", + "2022-12-29T02:00:00", + "2022-12-29T04:00:00", + "2022-12-29T06:00:00", + "2022-12-29T08:00:00", + "2022-12-29T10:00:00", + "2022-12-29T12:00:00", + "2022-12-29T14:00:00", + "2022-12-29T16:00:00", + "2022-12-29T18:00:00", + "2022-12-29T20:00:00", + "2022-12-29T22:00:00", + "2022-12-30T00:00:00", + "2022-12-30T02:00:00", + "2022-12-30T04:00:00", + "2022-12-30T06:00:00", + "2022-12-30T08:00:00", + "2022-12-30T10:00:00", + "2022-12-30T12:00:00", + "2022-12-30T14:00:00", + "2022-12-30T16:00:00", + "2022-12-30T18:00:00", + "2022-12-30T20:00:00", + "2022-12-30T22:00:00", + "2022-12-31T00:00:00", + "2022-12-31T02:00:00", + "2022-12-31T04:00:00", + "2022-12-31T06:00:00", + "2022-12-31T08:00:00", + "2022-12-31T10:00:00", + "2022-12-31T12:00:00", + "2022-12-31T14:00:00", + "2022-12-31T16:00:00", + "2022-12-31T18:00:00", + "2022-12-31T20:00:00", + "2022-12-31T22:00:00", + "2023-01-01T00:00:00", + "2023-01-01T02:00:00", + "2023-01-01T04:00:00", + "2023-01-01T06:00:00", + "2023-01-01T08:00:00", + "2023-01-01T10:00:00", + "2023-01-01T12:00:00", + "2023-01-01T14:00:00", + "2023-01-01T16:00:00", + "2023-01-01T18:00:00", + "2023-01-01T20:00:00", + "2023-01-01T22:00:00", + "2023-01-02T00:00:00", + "2023-01-02T02:00:00", + "2023-01-02T04:00:00", + "2023-01-02T06:00:00", + "2023-01-02T08:00:00", + "2023-01-02T10:00:00", + "2023-01-02T12:00:00", + "2023-01-02T14:00:00", + "2023-01-02T16:00:00", + "2023-01-02T18:00:00", + "2023-01-02T20:00:00", + "2023-01-02T22:00:00", + "2023-01-03T00:00:00", + "2023-01-03T02:00:00", + "2023-01-03T04:00:00", + "2023-01-03T06:00:00", + "2023-01-03T08:00:00", + "2023-01-03T10:00:00", + "2023-01-03T12:00:00", + "2023-01-03T14:00:00", + "2023-01-03T16:00:00", + "2023-01-03T18:00:00", + "2023-01-03T20:00:00", + "2023-01-03T22:00:00", + "2023-01-04T00:00:00", + "2023-01-04T02:00:00", + "2023-01-04T04:00:00", + "2023-01-04T06:00:00", + "2023-01-04T08:00:00", + "2023-01-04T10:00:00", + "2023-01-04T12:00:00", + "2023-01-04T14:00:00", + "2023-01-04T16:00:00", + "2023-01-04T18:00:00", + "2023-01-04T20:00:00", + "2023-01-04T22:00:00", + "2023-01-05T00:00:00", + "2023-01-05T02:00:00", + "2023-01-05T04:00:00", + "2023-01-05T06:00:00", + "2023-01-05T08:00:00", + "2023-01-05T10:00:00", + "2023-01-05T12:00:00", + "2023-01-05T14:00:00", + "2023-01-05T16:00:00", + "2023-01-05T18:00:00", + "2023-01-05T20:00:00", + "2023-01-05T22:00:00", + "2023-01-06T00:00:00", + "2023-01-06T02:00:00", + "2023-01-06T04:00:00", + "2023-01-06T06:00:00", + "2023-01-06T08:00:00", + "2023-01-06T10:00:00", + "2023-01-06T12:00:00", + "2023-01-06T14:00:00", + "2023-01-06T16:00:00", + "2023-01-06T18:00:00", + "2023-01-06T20:00:00", + "2023-01-06T22:00:00", + "2023-01-07T00:00:00", + "2023-01-07T02:00:00", + "2023-01-07T04:00:00", + "2023-01-07T06:00:00", + "2023-01-07T08:00:00", + "2023-01-07T10:00:00", + "2023-01-07T12:00:00", + "2023-01-07T14:00:00", + "2023-01-07T16:00:00", + "2023-01-07T18:00:00", + "2023-01-07T20:00:00", + "2023-01-07T22:00:00", + "2023-01-08T00:00:00", + "2023-01-08T02:00:00", + "2023-01-08T04:00:00", + "2023-01-08T06:00:00", + "2023-01-08T08:00:00", + "2023-01-08T10:00:00", + "2023-01-08T12:00:00", + "2023-01-08T14:00:00", + "2023-01-08T16:00:00", + "2023-01-08T18:00:00", + "2023-01-08T20:00:00", + "2023-01-08T22:00:00", + "2023-01-09T00:00:00", + "2023-01-09T02:00:00", + "2023-01-09T04:00:00", + "2023-01-09T06:00:00", + "2023-01-09T08:00:00", + "2023-01-09T10:00:00", + "2023-01-09T12:00:00", + "2023-01-09T14:00:00", + "2023-01-09T16:00:00", + "2023-01-09T18:00:00", + "2023-01-09T20:00:00", + "2023-01-09T22:00:00", + "2023-01-10T00:00:00", + "2023-01-10T02:00:00", + "2023-01-10T04:00:00", + "2023-01-10T06:00:00", + "2023-01-10T08:00:00", + "2023-01-10T10:00:00", + "2023-01-10T12:00:00", + "2023-01-10T14:00:00", + "2023-01-10T16:00:00", + "2023-01-10T18:00:00", + "2023-01-10T20:00:00", + "2023-01-10T22:00:00", + "2023-01-11T00:00:00", + "2023-01-11T02:00:00", + "2023-01-11T04:00:00", + "2023-01-11T06:00:00", + "2023-01-11T08:00:00", + "2023-01-11T10:00:00", + "2023-01-11T12:00:00", + "2023-01-11T14:00:00", + "2023-01-11T16:00:00", + "2023-01-11T18:00:00", + "2023-01-11T20:00:00", + "2023-01-11T22:00:00", + "2023-01-12T00:00:00", + "2023-01-12T02:00:00", + "2023-01-12T04:00:00", + "2023-01-12T06:00:00", + "2023-01-12T08:00:00", + "2023-01-12T10:00:00", + "2023-01-12T12:00:00", + "2023-01-12T14:00:00", + "2023-01-12T16:00:00", + "2023-01-12T18:00:00", + "2023-01-12T20:00:00", + "2023-01-12T22:00:00", + "2023-01-13T00:00:00", + "2023-01-13T02:00:00", + "2023-01-13T04:00:00", + "2023-01-13T06:00:00", + "2023-01-13T08:00:00", + "2023-01-13T10:00:00", + "2023-01-13T12:00:00", + "2023-01-13T14:00:00", + "2023-01-13T16:00:00", + "2023-01-13T18:00:00", + "2023-01-13T20:00:00", + "2023-01-13T22:00:00", + "2023-01-14T00:00:00", + "2023-01-14T02:00:00", + "2023-01-14T04:00:00", + "2023-01-14T06:00:00", + "2023-01-14T08:00:00", + "2023-01-14T10:00:00", + "2023-01-14T12:00:00", + "2023-01-14T14:00:00", + "2023-01-14T16:00:00", + "2023-01-14T18:00:00", + "2023-01-14T20:00:00", + "2023-01-14T22:00:00", + "2023-01-15T00:00:00", + "2023-01-15T02:00:00", + "2023-01-15T04:00:00", + "2023-01-15T06:00:00", + "2023-01-15T08:00:00", + "2023-01-15T10:00:00", + "2023-01-15T12:00:00", + "2023-01-15T14:00:00", + "2023-01-15T16:00:00", + "2023-01-15T18:00:00", + "2023-01-15T20:00:00", + "2023-01-15T22:00:00", + "2023-01-16T00:00:00", + "2023-01-16T02:00:00", + "2023-01-16T04:00:00", + "2023-01-16T06:00:00", + "2023-01-16T08:00:00", + "2023-01-16T10:00:00", + "2023-01-16T12:00:00", + "2023-01-16T14:00:00", + "2023-01-16T16:00:00", + "2023-01-16T18:00:00", + "2023-01-16T20:00:00", + "2023-01-16T22:00:00", + "2023-01-17T00:00:00", + "2023-01-17T02:00:00", + "2023-01-17T04:00:00", + "2023-01-17T06:00:00", + "2023-01-17T08:00:00", + "2023-01-17T10:00:00", + "2023-01-17T12:00:00", + "2023-01-17T14:00:00", + "2023-01-17T16:00:00", + "2023-01-17T18:00:00", + "2023-01-17T20:00:00", + "2023-01-17T22:00:00", + "2023-01-18T00:00:00", + "2023-01-18T02:00:00", + "2023-01-18T04:00:00", + "2023-01-18T06:00:00", + "2023-01-18T08:00:00", + "2023-01-18T10:00:00", + "2023-01-18T12:00:00", + "2023-01-18T14:00:00", + "2023-01-18T16:00:00", + "2023-01-18T18:00:00", + "2023-01-18T20:00:00", + "2023-01-18T22:00:00", + "2023-01-19T00:00:00", + "2023-01-19T02:00:00", + "2023-01-19T04:00:00", + "2023-01-19T06:00:00", + "2023-01-19T08:00:00", + "2023-01-19T10:00:00", + "2023-01-19T12:00:00", + "2023-01-19T14:00:00", + "2023-01-19T16:00:00", + "2023-01-19T18:00:00", + "2023-01-19T20:00:00", + "2023-01-19T22:00:00", + "2023-01-20T00:00:00", + "2023-01-20T02:00:00", + "2023-01-20T04:00:00", + "2023-01-20T06:00:00", + "2023-01-20T08:00:00", + "2023-01-20T10:00:00", + "2023-01-20T12:00:00", + "2023-01-20T14:00:00", + "2023-01-20T16:00:00", + "2023-01-20T18:00:00", + "2023-01-20T20:00:00", + "2023-01-20T22:00:00", + "2023-01-21T00:00:00", + "2023-01-21T02:00:00", + "2023-01-21T04:00:00", + "2023-01-21T06:00:00", + "2023-01-21T08:00:00", + "2023-01-21T10:00:00", + "2023-01-21T12:00:00", + "2023-01-21T14:00:00", + "2023-01-21T16:00:00", + "2023-01-21T18:00:00", + "2023-01-21T20:00:00", + "2023-01-21T22:00:00", + "2023-01-22T00:00:00", + "2023-01-22T02:00:00", + "2023-01-22T04:00:00", + "2023-01-22T06:00:00", + "2023-01-22T08:00:00", + "2023-01-22T10:00:00", + "2023-01-22T12:00:00", + "2023-01-22T14:00:00", + "2023-01-22T16:00:00", + "2023-01-22T18:00:00", + "2023-01-22T20:00:00", + "2023-01-22T22:00:00", + "2023-01-23T00:00:00", + "2023-01-23T02:00:00", + "2023-01-23T04:00:00", + "2023-01-23T06:00:00", + "2023-01-23T08:00:00", + "2023-01-23T10:00:00", + "2023-01-23T12:00:00", + "2023-01-23T14:00:00", + "2023-01-23T16:00:00", + "2023-01-23T18:00:00", + "2023-01-23T20:00:00", + "2023-01-23T22:00:00", + "2023-01-24T00:00:00", + "2023-01-24T02:00:00", + "2023-01-24T04:00:00", + "2023-01-24T06:00:00", + "2023-01-24T08:00:00", + "2023-01-24T10:00:00", + "2023-01-24T12:00:00", + "2023-01-24T14:00:00", + "2023-01-24T16:00:00", + "2023-01-24T18:00:00", + "2023-01-24T20:00:00", + "2023-01-24T22:00:00", + "2023-01-25T00:00:00", + "2023-01-25T02:00:00", + "2023-01-25T04:00:00", + "2023-01-25T06:00:00", + "2023-01-25T08:00:00", + "2023-01-25T10:00:00", + "2023-01-25T12:00:00", + "2023-01-25T14:00:00", + "2023-01-25T16:00:00", + "2023-01-25T18:00:00", + "2023-01-25T20:00:00", + "2023-01-25T22:00:00", + "2023-01-26T00:00:00", + "2023-01-26T02:00:00", + "2023-01-26T04:00:00", + "2023-01-26T06:00:00", + "2023-01-26T08:00:00", + "2023-01-26T10:00:00", + "2023-01-26T12:00:00", + "2023-01-26T14:00:00", + "2023-01-26T16:00:00", + "2023-01-26T18:00:00", + "2023-01-26T20:00:00", + "2023-01-26T22:00:00", + "2023-01-27T00:00:00", + "2023-01-27T02:00:00", + "2023-01-27T04:00:00", + "2023-01-27T06:00:00", + "2023-01-27T08:00:00", + "2023-01-27T10:00:00", + "2023-01-27T12:00:00", + "2023-01-27T14:00:00", + "2023-01-27T16:00:00", + "2023-01-27T18:00:00", + "2023-01-27T20:00:00", + "2023-01-27T22:00:00", + "2023-01-28T00:00:00", + "2023-01-28T02:00:00", + "2023-01-28T04:00:00", + "2023-01-28T06:00:00", + "2023-01-28T08:00:00", + "2023-01-28T10:00:00", + "2023-01-28T12:00:00", + "2023-01-28T14:00:00", + "2023-01-28T16:00:00", + "2023-01-28T18:00:00", + "2023-01-28T20:00:00", + "2023-01-28T22:00:00", + "2023-01-29T00:00:00", + "2023-01-29T02:00:00", + "2023-01-29T04:00:00", + "2023-01-29T06:00:00", + "2023-01-29T08:00:00", + "2023-01-29T10:00:00", + "2023-01-29T12:00:00", + "2023-01-29T14:00:00", + "2023-01-29T16:00:00", + "2023-01-29T18:00:00", + "2023-01-29T20:00:00", + "2023-01-29T22:00:00", + "2023-01-30T00:00:00", + "2023-01-30T02:00:00", + "2023-01-30T04:00:00", + "2023-01-30T06:00:00", + "2023-01-30T08:00:00", + "2023-01-30T10:00:00", + "2023-01-30T12:00:00", + "2023-01-30T14:00:00", + "2023-01-30T16:00:00", + "2023-01-30T18:00:00", + "2023-01-30T20:00:00", + "2023-01-30T22:00:00", + "2023-01-31T00:00:00", + "2023-01-31T02:00:00", + "2023-01-31T04:00:00", + "2023-01-31T06:00:00", + "2023-01-31T08:00:00", + "2023-01-31T10:00:00", + "2023-01-31T12:00:00", + "2023-01-31T14:00:00", + "2023-01-31T16:00:00", + "2023-01-31T18:00:00", + "2023-01-31T20:00:00", + "2023-01-31T22:00:00", + "2023-02-01T00:00:00", + "2023-02-01T02:00:00", + "2023-02-01T04:00:00", + "2023-02-01T06:00:00", + "2023-02-01T08:00:00", + "2023-02-01T10:00:00", + "2023-02-01T12:00:00", + "2023-02-01T14:00:00", + "2023-02-01T16:00:00", + "2023-02-01T18:00:00", + "2023-02-01T20:00:00", + "2023-02-01T22:00:00", + "2023-02-02T00:00:00", + "2023-02-02T02:00:00", + "2023-02-02T04:00:00", + "2023-02-02T06:00:00", + "2023-02-02T08:00:00", + "2023-02-02T10:00:00", + "2023-02-02T12:00:00", + "2023-02-02T14:00:00", + "2023-02-02T16:00:00", + "2023-02-02T18:00:00", + "2023-02-02T20:00:00", + "2023-02-02T22:00:00", + "2023-02-03T00:00:00", + "2023-02-03T02:00:00", + "2023-02-03T04:00:00", + "2023-02-03T06:00:00", + "2023-02-03T08:00:00", + "2023-02-03T10:00:00", + "2023-02-03T12:00:00", + "2023-02-03T14:00:00", + "2023-02-03T16:00:00", + "2023-02-03T18:00:00", + "2023-02-03T20:00:00", + "2023-02-03T22:00:00", + "2023-02-04T00:00:00", + "2023-02-04T02:00:00", + "2023-02-04T04:00:00", + "2023-02-04T06:00:00", + "2023-02-04T08:00:00", + "2023-02-04T10:00:00", + "2023-02-04T12:00:00", + "2023-02-04T14:00:00", + "2023-02-04T16:00:00", + "2023-02-04T18:00:00", + "2023-02-04T20:00:00", + "2023-02-04T22:00:00", + "2023-02-05T00:00:00", + "2023-02-05T02:00:00", + "2023-02-05T04:00:00", + "2023-02-05T06:00:00", + "2023-02-05T08:00:00", + "2023-02-05T10:00:00", + "2023-02-05T12:00:00", + "2023-02-05T14:00:00", + "2023-02-05T16:00:00", + "2023-02-05T18:00:00", + "2023-02-05T20:00:00", + "2023-02-05T22:00:00", + "2023-02-06T00:00:00", + "2023-02-06T02:00:00", + "2023-02-06T04:00:00", + "2023-02-06T06:00:00", + "2023-02-06T08:00:00", + "2023-02-06T10:00:00", + "2023-02-06T12:00:00", + "2023-02-06T14:00:00", + "2023-02-06T16:00:00", + "2023-02-06T18:00:00", + "2023-02-06T20:00:00", + "2023-02-06T22:00:00", + "2023-02-07T00:00:00", + "2023-02-07T02:00:00", + "2023-02-07T04:00:00", + "2023-02-07T06:00:00", + "2023-02-07T08:00:00", + "2023-02-07T10:00:00", + "2023-02-07T12:00:00", + "2023-02-07T14:00:00", + "2023-02-07T16:00:00", + "2023-02-07T18:00:00", + "2023-02-07T20:00:00", + "2023-02-07T22:00:00", + "2023-02-08T00:00:00", + "2023-02-08T02:00:00", + "2023-02-08T04:00:00", + "2023-02-08T06:00:00", + "2023-02-08T08:00:00", + "2023-02-08T10:00:00", + "2023-02-08T12:00:00", + "2023-02-08T14:00:00", + "2023-02-08T16:00:00", + "2023-02-08T18:00:00", + "2023-02-08T20:00:00", + "2023-02-08T22:00:00", + "2023-02-09T00:00:00", + "2023-02-09T02:00:00", + "2023-02-09T04:00:00", + "2023-02-09T06:00:00", + "2023-02-09T08:00:00", + "2023-02-09T10:00:00", + "2023-02-09T12:00:00", + "2023-02-09T14:00:00", + "2023-02-09T16:00:00", + "2023-02-09T18:00:00", + "2023-02-09T20:00:00", + "2023-02-09T22:00:00", + "2023-02-10T00:00:00", + "2023-02-10T02:00:00", + "2023-02-10T04:00:00", + "2023-02-10T06:00:00", + "2023-02-10T08:00:00", + "2023-02-10T10:00:00", + "2023-02-10T12:00:00", + "2023-02-10T14:00:00", + "2023-02-10T16:00:00", + "2023-02-10T18:00:00", + "2023-02-10T20:00:00", + "2023-02-10T22:00:00", + "2023-02-11T00:00:00", + "2023-02-11T02:00:00", + "2023-02-11T04:00:00", + "2023-02-11T06:00:00", + "2023-02-11T08:00:00", + "2023-02-11T10:00:00", + "2023-02-11T12:00:00", + "2023-02-11T14:00:00", + "2023-02-11T16:00:00", + "2023-02-11T18:00:00", + "2023-02-11T20:00:00", + "2023-02-11T22:00:00", + "2023-02-12T00:00:00", + "2023-02-12T02:00:00", + "2023-02-12T04:00:00", + "2023-02-12T06:00:00", + "2023-02-12T08:00:00", + "2023-02-12T10:00:00", + "2023-02-12T12:00:00", + "2023-02-12T14:00:00", + "2023-02-12T16:00:00", + "2023-02-12T18:00:00", + "2023-02-12T20:00:00", + "2023-02-12T22:00:00", + "2023-02-13T00:00:00", + "2023-02-13T02:00:00", + "2023-02-13T04:00:00", + "2023-02-13T06:00:00", + "2023-02-13T08:00:00", + "2023-02-13T10:00:00", + "2023-02-13T12:00:00", + "2023-02-13T14:00:00", + "2023-02-13T16:00:00", + "2023-02-13T18:00:00", + "2023-02-13T20:00:00", + "2023-02-13T22:00:00", + "2023-02-14T00:00:00", + "2023-02-14T02:00:00", + "2023-02-14T04:00:00", + "2023-02-14T06:00:00", + "2023-02-14T08:00:00", + "2023-02-14T10:00:00", + "2023-02-14T12:00:00", + "2023-02-14T14:00:00", + "2023-02-14T16:00:00", + "2023-02-14T18:00:00", + "2023-02-14T20:00:00", + "2023-02-14T22:00:00", + "2023-02-15T00:00:00", + "2023-02-15T02:00:00", + "2023-02-15T04:00:00", + "2023-02-15T06:00:00", + "2023-02-15T08:00:00", + "2023-02-15T10:00:00", + "2023-02-15T12:00:00", + "2023-02-15T14:00:00", + "2023-02-15T16:00:00", + "2023-02-15T18:00:00", + "2023-02-15T20:00:00", + "2023-02-15T22:00:00", + "2023-02-16T00:00:00", + "2023-02-16T02:00:00", + "2023-02-16T04:00:00", + "2023-02-16T06:00:00", + "2023-02-16T08:00:00", + "2023-02-16T10:00:00", + "2023-02-16T12:00:00", + "2023-02-16T14:00:00", + "2023-02-16T16:00:00", + "2023-02-16T18:00:00", + "2023-02-16T20:00:00", + "2023-02-16T22:00:00", + "2023-02-17T00:00:00", + "2023-02-17T02:00:00", + "2023-02-17T04:00:00", + "2023-02-17T06:00:00", + "2023-02-17T08:00:00", + "2023-02-17T10:00:00", + "2023-02-17T12:00:00", + "2023-02-17T14:00:00", + "2023-02-17T16:00:00", + "2023-02-17T18:00:00", + "2023-02-17T20:00:00", + "2023-02-17T22:00:00", + "2023-02-18T00:00:00", + "2023-02-18T02:00:00", + "2023-02-18T04:00:00", + "2023-02-18T06:00:00", + "2023-02-18T08:00:00", + "2023-02-18T10:00:00", + "2023-02-18T12:00:00", + "2023-02-18T14:00:00", + "2023-02-18T16:00:00", + "2023-02-18T18:00:00", + "2023-02-18T20:00:00", + "2023-02-18T22:00:00", + "2023-02-19T00:00:00", + "2023-02-19T02:00:00", + "2023-02-19T04:00:00", + "2023-02-19T06:00:00", + "2023-02-19T08:00:00", + "2023-02-19T10:00:00", + "2023-02-19T12:00:00", + "2023-02-19T14:00:00", + "2023-02-19T16:00:00", + "2023-02-19T18:00:00", + "2023-02-19T20:00:00", + "2023-02-19T22:00:00", + "2023-02-20T00:00:00", + "2023-02-20T02:00:00", + "2023-02-20T04:00:00", + "2023-02-20T06:00:00", + "2023-02-20T08:00:00", + "2023-02-20T10:00:00", + "2023-02-20T12:00:00", + "2023-02-20T14:00:00", + "2023-02-20T16:00:00", + "2023-02-20T18:00:00", + "2023-02-20T20:00:00", + "2023-02-20T22:00:00", + "2023-02-21T00:00:00", + "2023-02-21T02:00:00", + "2023-02-21T04:00:00", + "2023-02-21T06:00:00", + "2023-02-21T08:00:00", + "2023-02-21T10:00:00", + "2023-02-21T12:00:00", + "2023-02-21T14:00:00", + "2023-02-21T16:00:00", + "2023-02-21T18:00:00", + "2023-02-21T20:00:00", + "2023-02-21T22:00:00", + "2023-02-22T00:00:00", + "2023-02-22T02:00:00", + "2023-02-22T04:00:00", + "2023-02-22T06:00:00", + "2023-02-22T08:00:00", + "2023-02-22T10:00:00", + "2023-02-22T12:00:00", + "2023-02-22T14:00:00", + "2023-02-22T16:00:00", + "2023-02-22T18:00:00", + "2023-02-22T20:00:00", + "2023-02-22T22:00:00", + "2023-02-23T00:00:00", + "2023-02-23T02:00:00", + "2023-02-23T04:00:00", + "2023-02-23T06:00:00", + "2023-02-23T08:00:00", + "2023-02-23T10:00:00", + "2023-02-23T12:00:00", + "2023-02-23T14:00:00", + "2023-02-23T16:00:00", + "2023-02-23T18:00:00", + "2023-02-23T20:00:00", + "2023-02-23T22:00:00", + "2023-02-24T00:00:00", + "2023-02-24T02:00:00", + "2023-02-24T04:00:00", + "2023-02-24T06:00:00", + "2023-02-24T08:00:00", + "2023-02-24T10:00:00", + "2023-02-24T12:00:00", + "2023-02-24T14:00:00", + "2023-02-24T16:00:00", + "2023-02-24T18:00:00", + "2023-02-24T20:00:00", + "2023-02-24T22:00:00", + "2023-02-25T00:00:00", + "2023-02-25T02:00:00", + "2023-02-25T04:00:00", + "2023-02-25T06:00:00", + "2023-02-25T08:00:00", + "2023-02-25T10:00:00", + "2023-02-25T12:00:00", + "2023-02-25T14:00:00", + "2023-02-25T16:00:00", + "2023-02-25T18:00:00", + "2023-02-25T20:00:00", + "2023-02-25T22:00:00", + "2023-02-26T00:00:00", + "2023-02-26T02:00:00", + "2023-02-26T04:00:00", + "2023-02-26T06:00:00", + "2023-02-26T08:00:00", + "2023-02-26T10:00:00", + "2023-02-26T12:00:00", + "2023-02-26T14:00:00", + "2023-02-26T16:00:00", + "2023-02-26T18:00:00", + "2023-02-26T20:00:00", + "2023-02-26T22:00:00", + "2023-02-27T00:00:00", + "2023-02-27T02:00:00", + "2023-02-27T04:00:00", + "2023-02-27T06:00:00", + "2023-02-27T08:00:00", + "2023-02-27T10:00:00", + "2023-02-27T12:00:00", + "2023-02-27T14:00:00", + "2023-02-27T16:00:00", + "2023-02-27T18:00:00", + "2023-02-27T20:00:00", + "2023-02-27T22:00:00", + "2023-02-28T00:00:00", + "2023-02-28T02:00:00", + "2023-02-28T04:00:00", + "2023-02-28T06:00:00", + "2023-02-28T08:00:00", + "2023-02-28T10:00:00", + "2023-02-28T12:00:00", + "2023-02-28T14:00:00", + "2023-02-28T16:00:00", + "2023-02-28T18:00:00", + "2023-02-28T20:00:00", + "2023-02-28T22:00:00", + "2023-03-01T00:00:00", + "2023-03-01T02:00:00", + "2023-03-01T04:00:00", + "2023-03-01T06:00:00", + "2023-03-01T08:00:00", + "2023-03-01T10:00:00", + "2023-03-01T12:00:00", + "2023-03-01T14:00:00", + "2023-03-01T16:00:00", + "2023-03-01T18:00:00", + "2023-03-01T20:00:00", + "2023-03-01T22:00:00", + "2023-03-02T00:00:00", + "2023-03-02T02:00:00", + "2023-03-02T04:00:00", + "2023-03-02T06:00:00", + "2023-03-02T08:00:00", + "2023-03-02T10:00:00", + "2023-03-02T12:00:00", + "2023-03-02T14:00:00", + "2023-03-02T16:00:00", + "2023-03-02T18:00:00", + "2023-03-02T20:00:00", + "2023-03-02T22:00:00", + "2023-03-03T00:00:00", + "2023-03-03T02:00:00", + "2023-03-03T04:00:00", + "2023-03-03T06:00:00", + "2023-03-03T08:00:00", + "2023-03-03T10:00:00", + "2023-03-03T12:00:00", + "2023-03-03T14:00:00", + "2023-03-03T16:00:00", + "2023-03-03T18:00:00", + "2023-03-03T20:00:00", + "2023-03-03T22:00:00", + "2023-03-04T00:00:00", + "2023-03-04T02:00:00", + "2023-03-04T04:00:00", + "2023-03-04T06:00:00", + "2023-03-04T08:00:00", + "2023-03-04T10:00:00", + "2023-03-04T12:00:00", + "2023-03-04T14:00:00", + "2023-03-04T16:00:00", + "2023-03-04T18:00:00", + "2023-03-04T20:00:00", + "2023-03-04T22:00:00", + "2023-03-05T00:00:00", + "2023-03-05T02:00:00", + "2023-03-05T04:00:00", + "2023-03-05T06:00:00", + "2023-03-05T08:00:00", + "2023-03-05T10:00:00", + "2023-03-05T12:00:00", + "2023-03-05T14:00:00", + "2023-03-05T16:00:00", + "2023-03-05T18:00:00", + "2023-03-05T20:00:00", + "2023-03-05T22:00:00", + "2023-03-06T00:00:00", + "2023-03-06T02:00:00", + "2023-03-06T04:00:00", + "2023-03-06T06:00:00", + "2023-03-06T08:00:00", + "2023-03-06T10:00:00", + "2023-03-06T12:00:00", + "2023-03-06T14:00:00", + "2023-03-06T16:00:00", + "2023-03-06T18:00:00", + "2023-03-06T20:00:00", + "2023-03-06T22:00:00", + "2023-03-07T00:00:00", + "2023-03-07T02:00:00", + "2023-03-07T04:00:00", + "2023-03-07T06:00:00", + "2023-03-07T08:00:00", + "2023-03-07T10:00:00", + "2023-03-07T12:00:00", + "2023-03-07T14:00:00", + "2023-03-07T16:00:00", + "2023-03-07T18:00:00", + "2023-03-07T20:00:00", + "2023-03-07T22:00:00", + "2023-03-08T00:00:00", + "2023-03-08T02:00:00", + "2023-03-08T04:00:00", + "2023-03-08T06:00:00", + "2023-03-08T08:00:00", + "2023-03-08T10:00:00", + "2023-03-08T12:00:00", + "2023-03-08T14:00:00", + "2023-03-08T16:00:00", + "2023-03-08T18:00:00", + "2023-03-08T20:00:00", + "2023-03-08T22:00:00", + "2023-03-09T00:00:00", + "2023-03-09T02:00:00", + "2023-03-09T04:00:00", + "2023-03-09T06:00:00", + "2023-03-09T08:00:00", + "2023-03-09T10:00:00", + "2023-03-09T12:00:00", + "2023-03-09T14:00:00", + "2023-03-09T16:00:00", + "2023-03-09T18:00:00", + "2023-03-09T20:00:00", + "2023-03-09T22:00:00", + "2023-03-10T00:00:00", + "2023-03-10T02:00:00", + "2023-03-10T04:00:00", + "2023-03-10T06:00:00", + "2023-03-10T08:00:00", + "2023-03-10T10:00:00", + "2023-03-10T12:00:00", + "2023-03-10T14:00:00", + "2023-03-10T16:00:00", + "2023-03-10T18:00:00", + "2023-03-10T20:00:00", + "2023-03-10T22:00:00", + "2023-03-11T00:00:00", + "2023-03-11T02:00:00", + "2023-03-11T04:00:00", + "2023-03-11T06:00:00", + "2023-03-11T08:00:00", + "2023-03-11T10:00:00", + "2023-03-11T12:00:00", + "2023-03-11T14:00:00", + "2023-03-11T16:00:00", + "2023-03-11T18:00:00", + "2023-03-11T20:00:00", + "2023-03-11T22:00:00", + "2023-03-12T00:00:00", + "2023-03-12T02:00:00", + "2023-03-12T04:00:00", + "2023-03-12T06:00:00", + "2023-03-12T08:00:00", + "2023-03-12T10:00:00", + "2023-03-12T12:00:00", + "2023-03-12T14:00:00", + "2023-03-12T16:00:00", + "2023-03-12T18:00:00", + "2023-03-12T20:00:00", + "2023-03-12T22:00:00", + "2023-03-13T00:00:00", + "2023-03-13T02:00:00", + "2023-03-13T04:00:00", + "2023-03-13T06:00:00", + "2023-03-13T08:00:00", + "2023-03-13T10:00:00", + "2023-03-13T12:00:00", + "2023-03-13T14:00:00", + "2023-03-13T16:00:00", + "2023-03-13T18:00:00", + "2023-03-13T20:00:00", + "2023-03-13T22:00:00", + "2023-03-14T00:00:00", + "2023-03-14T02:00:00", + "2023-03-14T04:00:00", + "2023-03-14T06:00:00", + "2023-03-14T08:00:00", + "2023-03-14T10:00:00", + "2023-03-14T12:00:00", + "2023-03-14T14:00:00", + "2023-03-14T16:00:00", + "2023-03-14T18:00:00", + "2023-03-14T20:00:00", + "2023-03-14T22:00:00", + "2023-03-15T00:00:00", + "2023-03-15T02:00:00", + "2023-03-15T04:00:00", + "2023-03-15T06:00:00", + "2023-03-15T08:00:00", + "2023-03-15T10:00:00", + "2023-03-15T12:00:00", + "2023-03-15T14:00:00", + "2023-03-15T16:00:00", + "2023-03-15T18:00:00", + "2023-03-15T20:00:00", + "2023-03-15T22:00:00", + "2023-03-16T00:00:00", + "2023-03-16T02:00:00", + "2023-03-16T04:00:00", + "2023-03-16T06:00:00", + "2023-03-16T08:00:00", + "2023-03-16T10:00:00", + "2023-03-16T12:00:00", + "2023-03-16T14:00:00", + "2023-03-16T16:00:00", + "2023-03-16T18:00:00", + "2023-03-16T20:00:00", + "2023-03-16T22:00:00", + "2023-03-17T00:00:00", + "2023-03-17T02:00:00", + "2023-03-17T04:00:00", + "2023-03-17T06:00:00", + "2023-03-17T08:00:00", + "2023-03-17T10:00:00", + "2023-03-17T12:00:00", + "2023-03-17T14:00:00", + "2023-03-17T16:00:00", + "2023-03-17T18:00:00", + "2023-03-17T20:00:00", + "2023-03-17T22:00:00", + "2023-03-18T00:00:00", + "2023-03-18T02:00:00", + "2023-03-18T04:00:00", + "2023-03-18T06:00:00", + "2023-03-18T08:00:00", + "2023-03-18T10:00:00", + "2023-03-18T12:00:00", + "2023-03-18T14:00:00", + "2023-03-18T16:00:00", + "2023-03-18T18:00:00", + "2023-03-18T20:00:00", + "2023-03-18T22:00:00", + "2023-03-19T00:00:00", + "2023-03-19T02:00:00", + "2023-03-19T04:00:00", + "2023-03-19T06:00:00", + "2023-03-19T08:00:00", + "2023-03-19T10:00:00", + "2023-03-19T12:00:00", + "2023-03-19T14:00:00", + "2023-03-19T16:00:00", + "2023-03-19T18:00:00", + "2023-03-19T20:00:00", + "2023-03-19T22:00:00", + "2023-03-20T00:00:00", + "2023-03-20T02:00:00", + "2023-03-20T04:00:00", + "2023-03-20T06:00:00", + "2023-03-20T08:00:00", + "2023-03-20T10:00:00", + "2023-03-20T12:00:00", + "2023-03-20T14:00:00", + "2023-03-20T16:00:00", + "2023-03-20T18:00:00", + "2023-03-20T20:00:00", + "2023-03-20T22:00:00", + "2023-03-21T00:00:00", + "2023-03-21T02:00:00", + "2023-03-21T04:00:00", + "2023-03-21T06:00:00", + "2023-03-21T08:00:00", + "2023-03-21T10:00:00", + "2023-03-21T12:00:00", + "2023-03-21T14:00:00", + "2023-03-21T16:00:00", + "2023-03-21T18:00:00", + "2023-03-21T20:00:00", + "2023-03-21T22:00:00", + "2023-03-22T00:00:00", + "2023-03-22T02:00:00", + "2023-03-22T04:00:00", + "2023-03-22T06:00:00", + "2023-03-22T08:00:00", + "2023-03-22T10:00:00", + "2023-03-22T12:00:00", + "2023-03-22T14:00:00", + "2023-03-22T16:00:00", + "2023-03-22T18:00:00", + "2023-03-22T20:00:00", + "2023-03-22T22:00:00", + "2023-03-23T00:00:00", + "2023-03-23T02:00:00", + "2023-03-23T04:00:00", + "2023-03-23T06:00:00", + "2023-03-23T08:00:00", + "2023-03-23T10:00:00", + "2023-03-23T12:00:00", + "2023-03-23T14:00:00", + "2023-03-23T16:00:00", + "2023-03-23T18:00:00", + "2023-03-23T20:00:00", + "2023-03-23T22:00:00", + "2023-03-24T00:00:00", + "2023-03-24T02:00:00", + "2023-03-24T04:00:00", + "2023-03-24T06:00:00", + "2023-03-24T08:00:00", + "2023-03-24T10:00:00", + "2023-03-24T12:00:00", + "2023-03-24T14:00:00", + "2023-03-24T16:00:00", + "2023-03-24T18:00:00", + "2023-03-24T20:00:00", + "2023-03-24T22:00:00", + "2023-03-25T00:00:00", + "2023-03-25T02:00:00", + "2023-03-25T04:00:00", + "2023-03-25T06:00:00", + "2023-03-25T08:00:00", + "2023-03-25T10:00:00", + "2023-03-25T12:00:00", + "2023-03-25T14:00:00", + "2023-03-25T16:00:00", + "2023-03-25T18:00:00", + "2023-03-25T20:00:00", + "2023-03-25T22:00:00", + "2023-03-26T00:00:00", + "2023-03-26T02:00:00", + "2023-03-26T04:00:00", + "2023-03-26T06:00:00", + "2023-03-26T08:00:00", + "2023-03-26T10:00:00", + "2023-03-26T12:00:00", + "2023-03-26T14:00:00", + "2023-03-26T16:00:00", + "2023-03-26T18:00:00", + "2023-03-26T20:00:00", + "2023-03-26T22:00:00", + "2023-03-27T00:00:00", + "2023-03-27T02:00:00", + "2023-03-27T04:00:00", + "2023-03-27T06:00:00", + "2023-03-27T08:00:00", + "2023-03-27T10:00:00", + "2023-03-27T12:00:00", + "2023-03-27T14:00:00", + "2023-03-27T16:00:00", + "2023-03-27T18:00:00", + "2023-03-27T20:00:00", + "2023-03-27T22:00:00", + "2023-03-28T00:00:00", + "2023-03-28T02:00:00", + "2023-03-28T04:00:00", + "2023-03-28T06:00:00", + "2023-03-28T08:00:00", + "2023-03-28T10:00:00", + "2023-03-28T12:00:00", + "2023-03-28T14:00:00", + "2023-03-28T16:00:00", + "2023-03-28T18:00:00", + "2023-03-28T20:00:00", + "2023-03-28T22:00:00", + "2023-03-29T00:00:00", + "2023-03-29T02:00:00", + "2023-03-29T04:00:00", + "2023-03-29T06:00:00", + "2023-03-29T08:00:00", + "2023-03-29T10:00:00", + "2023-03-29T12:00:00", + "2023-03-29T14:00:00", + "2023-03-29T16:00:00", + "2023-03-29T18:00:00", + "2023-03-29T20:00:00", + "2023-03-29T22:00:00", + "2023-03-30T00:00:00", + "2023-03-30T02:00:00", + "2023-03-30T04:00:00", + "2023-03-30T06:00:00", + "2023-03-30T08:00:00", + "2023-03-30T10:00:00", + "2023-03-30T12:00:00", + "2023-03-30T14:00:00", + "2023-03-30T16:00:00", + "2023-03-30T18:00:00", + "2023-03-30T20:00:00", + "2023-03-30T22:00:00", + "2023-03-31T00:00:00", + "2023-03-31T02:00:00", + "2023-03-31T04:00:00", + "2023-03-31T06:00:00", + "2023-03-31T08:00:00", + "2023-03-31T10:00:00", + "2023-03-31T12:00:00", + "2023-03-31T14:00:00", + "2023-03-31T16:00:00", + "2023-03-31T18:00:00", + "2023-03-31T20:00:00", + "2023-03-31T22:00:00", + "2023-04-01T00:00:00", + "2023-04-01T02:00:00", + "2023-04-01T04:00:00", + "2023-04-01T06:00:00", + "2023-04-01T08:00:00", + "2023-04-01T10:00:00", + "2023-04-01T12:00:00", + "2023-04-01T14:00:00", + "2023-04-01T16:00:00", + "2023-04-01T18:00:00", + "2023-04-01T20:00:00", + "2023-04-01T22:00:00", + "2023-04-02T00:00:00", + "2023-04-02T02:00:00", + "2023-04-02T04:00:00", + "2023-04-02T06:00:00", + "2023-04-02T08:00:00", + "2023-04-02T10:00:00", + "2023-04-02T12:00:00", + "2023-04-02T14:00:00", + "2023-04-02T16:00:00", + "2023-04-02T18:00:00", + "2023-04-02T20:00:00", + "2023-04-02T22:00:00", + "2023-04-03T00:00:00", + "2023-04-03T02:00:00", + "2023-04-03T04:00:00", + "2023-04-03T06:00:00", + "2023-04-03T08:00:00", + "2023-04-03T10:00:00", + "2023-04-03T12:00:00", + "2023-04-03T14:00:00", + "2023-04-03T16:00:00", + "2023-04-03T18:00:00", + "2023-04-03T20:00:00", + "2023-04-03T22:00:00", + "2023-04-04T00:00:00", + "2023-04-04T02:00:00", + "2023-04-04T04:00:00", + "2023-04-04T06:00:00", + "2023-04-04T08:00:00", + "2023-04-04T10:00:00", + "2023-04-04T12:00:00", + "2023-04-04T14:00:00", + "2023-04-04T16:00:00", + "2023-04-04T18:00:00", + "2023-04-04T20:00:00", + "2023-04-04T22:00:00", + "2023-04-05T00:00:00", + "2023-04-05T02:00:00", + "2023-04-05T04:00:00", + "2023-04-05T06:00:00", + "2023-04-05T08:00:00", + "2023-04-05T10:00:00", + "2023-04-05T12:00:00", + "2023-04-05T14:00:00", + "2023-04-05T16:00:00", + "2023-04-05T18:00:00", + "2023-04-05T20:00:00", + "2023-04-05T22:00:00", + "2023-04-06T00:00:00", + "2023-04-06T02:00:00", + "2023-04-06T04:00:00", + "2023-04-06T06:00:00", + "2023-04-06T08:00:00", + "2023-04-06T10:00:00", + "2023-04-06T12:00:00", + "2023-04-06T14:00:00", + "2023-04-06T16:00:00", + "2023-04-06T18:00:00", + "2023-04-06T20:00:00", + "2023-04-06T22:00:00", + "2023-04-07T00:00:00", + "2023-04-07T02:00:00", + "2023-04-07T04:00:00", + "2023-04-07T06:00:00", + "2023-04-07T08:00:00", + "2023-04-07T10:00:00", + "2023-04-07T12:00:00", + "2023-04-07T14:00:00", + "2023-04-07T16:00:00", + "2023-04-07T18:00:00", + "2023-04-07T20:00:00", + "2023-04-07T22:00:00", + "2023-04-08T00:00:00", + "2023-04-08T02:00:00", + "2023-04-08T04:00:00", + "2023-04-08T06:00:00", + "2023-04-08T08:00:00", + "2023-04-08T10:00:00", + "2023-04-08T12:00:00", + "2023-04-08T14:00:00", + "2023-04-08T16:00:00", + "2023-04-08T18:00:00", + "2023-04-08T20:00:00", + "2023-04-08T22:00:00", + "2023-04-09T00:00:00", + "2023-04-09T02:00:00", + "2023-04-09T04:00:00", + "2023-04-09T06:00:00", + "2023-04-09T08:00:00", + "2023-04-09T10:00:00", + "2023-04-09T12:00:00", + "2023-04-09T14:00:00", + "2023-04-09T16:00:00", + "2023-04-09T18:00:00", + "2023-04-09T20:00:00", + "2023-04-09T22:00:00", + "2023-04-10T00:00:00", + "2023-04-10T02:00:00", + "2023-04-10T04:00:00", + "2023-04-10T06:00:00", + "2023-04-10T08:00:00", + "2023-04-10T10:00:00", + "2023-04-10T12:00:00", + "2023-04-10T14:00:00", + "2023-04-10T16:00:00", + "2023-04-10T18:00:00", + "2023-04-10T20:00:00", + "2023-04-10T22:00:00", + "2023-04-11T00:00:00", + "2023-04-11T02:00:00", + "2023-04-11T04:00:00", + "2023-04-11T06:00:00", + "2023-04-11T08:00:00", + "2023-04-11T10:00:00", + "2023-04-11T12:00:00", + "2023-04-11T14:00:00", + "2023-04-11T16:00:00", + "2023-04-11T18:00:00", + "2023-04-11T20:00:00", + "2023-04-11T22:00:00", + "2023-04-12T00:00:00", + "2023-04-12T02:00:00", + "2023-04-12T04:00:00", + "2023-04-12T06:00:00", + "2023-04-12T08:00:00", + "2023-04-12T10:00:00", + "2023-04-12T12:00:00", + "2023-04-12T14:00:00", + "2023-04-12T16:00:00", + "2023-04-12T18:00:00", + "2023-04-12T20:00:00", + "2023-04-12T22:00:00", + "2023-04-13T00:00:00", + "2023-04-13T02:00:00", + "2023-04-13T04:00:00", + "2023-04-13T06:00:00", + "2023-04-13T08:00:00", + "2023-04-13T10:00:00", + "2023-04-13T12:00:00", + "2023-04-13T14:00:00", + "2023-04-13T16:00:00", + "2023-04-13T18:00:00", + "2023-04-13T20:00:00", + "2023-04-13T22:00:00", + "2023-04-14T00:00:00", + "2023-04-14T02:00:00", + "2023-04-14T04:00:00", + "2023-04-14T06:00:00", + "2023-04-14T08:00:00", + "2023-04-14T10:00:00", + "2023-04-14T12:00:00", + "2023-04-14T14:00:00", + "2023-04-14T16:00:00", + "2023-04-14T18:00:00", + "2023-04-14T20:00:00", + "2023-04-14T22:00:00", + "2023-04-15T00:00:00", + "2023-04-15T02:00:00", + "2023-04-15T04:00:00", + "2023-04-15T06:00:00", + "2023-04-15T08:00:00", + "2023-04-15T10:00:00", + "2023-04-15T12:00:00", + "2023-04-15T14:00:00", + "2023-04-15T16:00:00", + "2023-04-15T18:00:00", + "2023-04-15T20:00:00", + "2023-04-15T22:00:00", + "2023-04-16T00:00:00", + "2023-04-16T04:00:00", + "2023-04-16T06:00:00", + "2023-04-16T08:00:00", + "2023-04-16T10:00:00", + "2023-04-16T12:00:00", + "2023-04-16T14:00:00", + "2023-04-16T16:00:00", + "2023-04-16T18:00:00", + "2023-04-16T20:00:00", + "2023-04-16T22:00:00", + "2023-04-17T00:00:00", + "2023-04-17T02:00:00", + "2023-04-17T04:00:00", + "2023-04-17T06:00:00", + "2023-04-17T08:00:00", + "2023-04-17T10:00:00", + "2023-04-17T12:00:00", + "2023-04-17T14:00:00", + "2023-04-17T16:00:00", + "2023-04-17T18:00:00", + "2023-04-17T20:00:00", + "2023-04-17T22:00:00", + "2023-04-18T00:00:00", + "2023-04-18T02:00:00", + "2023-04-18T04:00:00", + "2023-04-18T06:00:00", + "2023-04-18T08:00:00", + "2023-04-18T10:00:00", + "2023-04-18T12:00:00", + "2023-04-18T14:00:00", + "2023-04-18T16:00:00", + "2023-04-18T18:00:00", + "2023-04-18T20:00:00", + "2023-04-18T22:00:00", + "2023-04-19T00:00:00", + "2023-04-19T02:00:00", + "2023-04-19T04:00:00", + "2023-04-19T06:00:00", + "2023-04-19T08:00:00", + "2023-04-19T10:00:00", + "2023-04-19T12:00:00", + "2023-04-19T14:00:00", + "2023-04-19T16:00:00", + "2023-04-19T18:00:00", + "2023-04-19T20:00:00", + "2023-04-19T22:00:00", + "2023-04-20T00:00:00", + "2023-04-20T02:00:00", + "2023-04-20T04:00:00", + "2023-04-20T06:00:00", + "2023-04-20T08:00:00", + "2023-04-20T10:00:00", + "2023-04-20T12:00:00", + "2023-04-20T14:00:00", + "2023-04-20T16:00:00", + "2023-04-20T18:00:00", + "2023-04-20T20:00:00", + "2023-04-20T22:00:00", + "2023-04-21T00:00:00", + "2023-04-21T02:00:00", + "2023-04-21T04:00:00", + "2023-04-21T06:00:00", + "2023-04-21T08:00:00", + "2023-04-21T10:00:00", + "2023-04-21T12:00:00", + "2023-04-21T14:00:00", + "2023-04-21T16:00:00", + "2023-04-21T18:00:00", + "2023-04-21T20:00:00", + "2023-04-21T22:00:00", + "2023-04-22T00:00:00", + "2023-04-22T02:00:00", + "2023-04-22T04:00:00", + "2023-04-22T06:00:00", + "2023-04-22T08:00:00", + "2023-04-22T10:00:00", + "2023-04-22T12:00:00", + "2023-04-22T14:00:00", + "2023-04-22T16:00:00", + "2023-04-22T18:00:00", + "2023-04-22T20:00:00", + "2023-04-22T22:00:00", + "2023-04-23T00:00:00", + "2023-04-23T02:00:00", + "2023-04-23T04:00:00", + "2023-04-23T06:00:00", + "2023-04-23T08:00:00", + "2023-04-23T10:00:00", + "2023-04-23T12:00:00", + "2023-04-23T14:00:00", + "2023-04-23T16:00:00", + "2023-04-23T18:00:00", + "2023-04-23T20:00:00", + "2023-04-23T22:00:00", + "2023-04-24T00:00:00", + "2023-04-24T02:00:00", + "2023-04-24T04:00:00", + "2023-04-24T06:00:00", + "2023-04-24T08:00:00", + "2023-04-24T10:00:00", + "2023-04-24T12:00:00", + "2023-04-24T14:00:00", + "2023-04-24T16:00:00", + "2023-04-24T18:00:00", + "2023-04-24T20:00:00", + "2023-04-24T22:00:00", + "2023-04-25T00:00:00", + "2023-04-25T02:00:00", + "2023-04-25T04:00:00", + "2023-04-25T06:00:00", + "2023-04-25T08:00:00", + "2023-04-25T10:00:00", + "2023-04-25T12:00:00", + "2023-04-25T14:00:00", + "2023-04-25T16:00:00", + "2023-04-25T18:00:00", + "2023-04-25T20:00:00", + "2023-04-25T22:00:00", + "2023-04-26T00:00:00", + "2023-04-26T02:00:00", + "2023-04-26T04:00:00", + "2023-04-26T06:00:00", + "2023-04-26T08:00:00", + "2023-04-26T10:00:00", + "2023-04-26T12:00:00", + "2023-04-26T14:00:00", + "2023-04-26T16:00:00", + "2023-04-26T18:00:00", + "2023-04-26T20:00:00", + "2023-04-26T22:00:00", + "2023-04-27T00:00:00", + "2023-04-27T02:00:00", + "2023-04-27T04:00:00", + "2023-04-27T06:00:00", + "2023-04-27T08:00:00", + "2023-04-27T10:00:00", + "2023-04-27T12:00:00", + "2023-04-27T14:00:00", + "2023-04-27T16:00:00", + "2023-04-27T18:00:00", + "2023-04-27T20:00:00", + "2023-04-27T22:00:00", + "2023-04-28T00:00:00", + "2023-04-28T02:00:00", + "2023-04-28T04:00:00", + "2023-04-28T06:00:00", + "2023-04-28T08:00:00", + "2023-04-28T10:00:00", + "2023-04-28T12:00:00", + "2023-04-28T14:00:00", + "2023-04-28T16:00:00", + "2023-04-28T18:00:00", + "2023-04-28T20:00:00", + "2023-04-28T22:00:00", + "2023-04-29T00:00:00", + "2023-04-29T02:00:00", + "2023-04-29T04:00:00", + "2023-04-29T06:00:00", + "2023-04-29T08:00:00", + "2023-04-29T10:00:00", + "2023-04-29T12:00:00", + "2023-04-29T14:00:00", + "2023-04-29T16:00:00", + "2023-04-29T18:00:00", + "2023-04-29T20:00:00", + "2023-04-29T22:00:00", + "2023-04-30T00:00:00", + "2023-04-30T02:00:00", + "2023-04-30T04:00:00", + "2023-04-30T06:00:00", + "2023-04-30T08:00:00", + "2023-04-30T10:00:00", + "2023-04-30T12:00:00", + "2023-04-30T14:00:00", + "2023-04-30T16:00:00", + "2023-04-30T18:00:00", + "2023-04-30T20:00:00", + "2023-04-30T22:00:00", + "2023-05-01T00:00:00", + "2023-05-01T02:00:00", + "2023-05-01T04:00:00", + "2023-05-01T06:00:00", + "2023-05-01T08:00:00", + "2023-05-01T10:00:00", + "2023-05-01T12:00:00", + "2023-05-01T14:00:00", + "2023-05-01T16:00:00", + "2023-05-01T18:00:00", + "2023-05-01T20:00:00", + "2023-05-01T22:00:00", + "2023-05-02T00:00:00", + "2023-05-02T02:00:00", + "2023-05-02T04:00:00", + "2023-05-02T06:00:00", + "2023-05-02T08:00:00", + "2023-05-02T10:00:00", + "2023-05-02T12:00:00", + "2023-05-02T14:00:00", + "2023-05-02T16:00:00", + "2023-05-02T18:00:00", + "2023-05-02T20:00:00", + "2023-05-02T22:00:00", + "2023-05-03T00:00:00", + "2023-05-03T02:00:00", + "2023-05-03T04:00:00", + "2023-05-03T06:00:00", + "2023-05-03T08:00:00", + "2023-05-03T10:00:00", + "2023-05-03T12:00:00", + "2023-05-03T14:00:00", + "2023-05-03T16:00:00", + "2023-05-03T18:00:00", + "2023-05-03T20:00:00", + "2023-05-03T22:00:00", + "2023-05-04T00:00:00", + "2023-05-04T02:00:00", + "2023-05-04T04:00:00", + "2023-05-04T06:00:00", + "2023-05-04T08:00:00", + "2023-05-04T10:00:00", + "2023-05-04T12:00:00", + "2023-05-04T14:00:00", + "2023-05-04T16:00:00", + "2023-05-04T18:00:00", + "2023-05-04T20:00:00", + "2023-05-04T22:00:00", + "2023-05-05T00:00:00", + "2023-05-05T02:00:00", + "2023-05-05T04:00:00", + "2023-05-05T06:00:00", + "2023-05-05T08:00:00", + "2023-05-05T10:00:00", + "2023-05-05T12:00:00", + "2023-05-05T14:00:00", + "2023-05-05T16:00:00", + "2023-05-05T18:00:00", + "2023-05-05T20:00:00", + "2023-05-05T22:00:00", + "2023-05-06T00:00:00", + "2023-05-06T02:00:00", + "2023-05-06T04:00:00", + "2023-05-06T06:00:00", + "2023-05-06T08:00:00", + "2023-05-06T10:00:00", + "2023-05-06T12:00:00", + "2023-05-06T14:00:00", + "2023-05-06T16:00:00", + "2023-05-06T18:00:00", + "2023-05-06T20:00:00", + "2023-05-06T22:00:00", + "2023-05-07T00:00:00", + "2023-05-07T02:00:00", + "2023-05-07T04:00:00", + "2023-05-07T06:00:00", + "2023-05-07T08:00:00", + "2023-05-07T10:00:00", + "2023-05-07T12:00:00", + "2023-05-07T14:00:00", + "2023-05-07T16:00:00", + "2023-05-07T18:00:00", + "2023-05-07T20:00:00", + "2023-05-07T22:00:00", + "2023-05-08T00:00:00", + "2023-05-08T02:00:00", + "2023-05-08T04:00:00", + "2023-05-08T06:00:00", + "2023-05-08T08:00:00", + "2023-05-08T10:00:00", + "2023-05-08T12:00:00", + "2023-05-08T14:00:00", + "2023-05-08T16:00:00", + "2023-05-08T18:00:00", + "2023-05-08T20:00:00", + "2023-05-08T22:00:00", + "2023-05-09T00:00:00", + "2023-05-09T02:00:00", + "2023-05-09T04:00:00", + "2023-05-09T06:00:00", + "2023-05-09T08:00:00", + "2023-05-09T10:00:00", + "2023-05-09T12:00:00", + "2023-05-09T14:00:00", + "2023-05-09T16:00:00", + "2023-05-09T18:00:00", + "2023-05-09T20:00:00", + "2023-05-09T22:00:00", + "2023-05-10T00:00:00", + "2023-05-10T02:00:00", + "2023-05-10T04:00:00", + "2023-05-10T06:00:00", + "2023-05-10T08:00:00", + "2023-05-10T10:00:00", + "2023-05-10T12:00:00", + "2023-05-10T14:00:00", + "2023-05-10T16:00:00", + "2023-05-10T18:00:00", + "2023-05-10T20:00:00", + "2023-05-10T22:00:00", + "2023-05-11T00:00:00", + "2023-05-11T02:00:00", + "2023-05-11T04:00:00", + "2023-05-11T06:00:00", + "2023-05-11T08:00:00", + "2023-05-11T10:00:00", + "2023-05-11T12:00:00", + "2023-05-11T14:00:00", + "2023-05-11T16:00:00", + "2023-05-11T18:00:00", + "2023-05-11T20:00:00", + "2023-05-11T22:00:00", + "2023-05-12T00:00:00", + "2023-05-12T02:00:00", + "2023-05-12T04:00:00", + "2023-05-12T06:00:00", + "2023-05-12T08:00:00", + "2023-05-12T10:00:00", + "2023-05-12T12:00:00", + "2023-05-12T14:00:00", + "2023-05-12T16:00:00", + "2023-05-12T18:00:00", + "2023-05-12T20:00:00", + "2023-05-12T22:00:00", + "2023-05-13T00:00:00", + "2023-05-13T02:00:00", + "2023-05-13T04:00:00", + "2023-05-13T06:00:00", + "2023-05-13T08:00:00", + "2023-05-13T10:00:00", + "2023-05-13T12:00:00", + "2023-05-13T14:00:00", + "2023-05-13T16:00:00", + "2023-05-13T18:00:00", + "2023-05-13T20:00:00", + "2023-05-13T22:00:00", + "2023-05-14T00:00:00", + "2023-05-14T02:00:00", + "2023-05-14T04:00:00", + "2023-05-14T06:00:00", + "2023-05-14T08:00:00", + "2023-05-14T10:00:00", + "2023-05-14T12:00:00", + "2023-05-14T14:00:00", + "2023-05-14T16:00:00", + "2023-05-14T18:00:00", + "2023-05-14T20:00:00", + "2023-05-14T22:00:00", + "2023-05-15T00:00:00", + "2023-05-15T02:00:00", + "2023-05-15T04:00:00", + "2023-05-15T06:00:00", + "2023-05-15T08:00:00", + "2023-05-15T10:00:00", + "2023-05-15T12:00:00", + "2023-05-15T14:00:00", + "2023-05-15T16:00:00", + "2023-05-15T18:00:00", + "2023-05-15T20:00:00", + "2023-05-15T22:00:00", + "2023-05-16T00:00:00", + "2023-05-16T02:00:00", + "2023-05-16T04:00:00", + "2023-05-16T06:00:00", + "2023-05-16T08:00:00", + "2023-05-16T10:00:00", + "2023-05-16T12:00:00", + "2023-05-16T14:00:00", + "2023-05-16T16:00:00", + "2023-05-16T18:00:00", + "2023-05-16T20:00:00", + "2023-05-16T22:00:00", + "2023-05-17T00:00:00", + "2023-05-17T02:00:00", + "2023-05-17T04:00:00", + "2023-05-17T06:00:00", + "2023-05-17T08:00:00", + "2023-05-17T10:00:00", + "2023-05-17T12:00:00", + "2023-05-17T14:00:00", + "2023-05-17T16:00:00", + "2023-05-17T18:00:00", + "2023-05-17T20:00:00", + "2023-05-17T22:00:00", + "2023-05-18T00:00:00", + "2023-05-18T02:00:00", + "2023-05-18T04:00:00", + "2023-05-18T06:00:00", + "2023-05-18T08:00:00", + "2023-05-18T10:00:00", + "2023-05-18T12:00:00", + "2023-05-18T14:00:00", + "2023-05-18T16:00:00", + "2023-05-18T18:00:00", + "2023-05-18T20:00:00", + "2023-05-18T22:00:00", + "2023-05-19T00:00:00", + "2023-05-19T02:00:00", + "2023-05-19T04:00:00", + "2023-05-19T06:00:00", + "2023-05-19T08:00:00", + "2023-05-19T10:00:00", + "2023-05-19T12:00:00", + "2023-05-19T14:00:00", + "2023-05-19T16:00:00", + "2023-05-19T18:00:00", + "2023-05-19T20:00:00", + "2023-05-19T22:00:00", + "2023-05-20T00:00:00", + "2023-05-20T02:00:00", + "2023-05-20T04:00:00", + "2023-05-20T06:00:00", + "2023-05-20T08:00:00", + "2023-05-20T10:00:00", + "2023-05-20T12:00:00", + "2023-05-20T14:00:00", + "2023-05-20T16:00:00", + "2023-05-20T18:00:00", + "2023-05-20T20:00:00", + "2023-05-20T22:00:00", + "2023-05-21T00:00:00", + "2023-05-21T02:00:00", + "2023-05-21T04:00:00", + "2023-05-21T06:00:00", + "2023-05-21T08:00:00", + "2023-05-21T10:00:00", + "2023-05-21T12:00:00", + "2023-05-21T14:00:00", + "2023-05-21T16:00:00", + "2023-05-21T18:00:00", + "2023-05-21T20:00:00", + "2023-05-21T22:00:00", + "2023-05-22T00:00:00", + "2023-05-22T02:00:00", + "2023-05-22T04:00:00", + "2023-05-22T06:00:00", + "2023-05-22T08:00:00", + "2023-05-22T10:00:00", + "2023-05-22T12:00:00", + "2023-05-22T14:00:00", + "2023-05-22T16:00:00", + "2023-05-22T18:00:00", + "2023-05-22T20:00:00", + "2023-05-22T22:00:00", + "2023-05-23T00:00:00", + "2023-05-23T02:00:00", + "2023-05-23T04:00:00", + "2023-05-23T06:00:00", + "2023-05-23T08:00:00", + "2023-05-23T10:00:00", + "2023-05-23T12:00:00", + "2023-05-23T14:00:00", + "2023-05-23T16:00:00", + "2023-05-23T18:00:00", + "2023-05-23T20:00:00", + "2023-05-23T22:00:00", + "2023-05-24T00:00:00", + "2023-05-24T02:00:00", + "2023-05-24T04:00:00", + "2023-05-24T06:00:00", + "2023-05-24T08:00:00", + "2023-05-24T10:00:00", + "2023-05-24T12:00:00", + "2023-05-24T14:00:00", + "2023-05-24T16:00:00", + "2023-05-24T18:00:00", + "2023-05-24T20:00:00", + "2023-05-24T22:00:00", + "2023-05-25T00:00:00", + "2023-05-25T02:00:00", + "2023-05-25T04:00:00", + "2023-05-25T06:00:00", + "2023-05-25T08:00:00", + "2023-05-25T10:00:00", + "2023-05-25T12:00:00", + "2023-05-25T14:00:00", + "2023-05-25T16:00:00", + "2023-05-25T18:00:00", + "2023-05-25T20:00:00", + "2023-05-25T22:00:00", + "2023-05-26T00:00:00", + "2023-05-26T02:00:00", + "2023-05-26T04:00:00", + "2023-05-26T06:00:00", + "2023-05-26T08:00:00", + "2023-05-26T10:00:00", + "2023-05-26T12:00:00", + "2023-05-26T14:00:00", + "2023-05-26T16:00:00", + "2023-05-26T18:00:00", + "2023-05-26T20:00:00", + "2023-05-26T22:00:00", + "2023-05-27T00:00:00", + "2023-05-27T02:00:00", + "2023-05-27T04:00:00", + "2023-05-27T06:00:00", + "2023-05-27T08:00:00", + "2023-05-27T10:00:00", + "2023-05-27T12:00:00", + "2023-05-27T14:00:00", + "2023-05-27T16:00:00", + "2023-05-27T18:00:00", + "2023-05-27T20:00:00", + "2023-05-27T22:00:00", + "2023-05-28T00:00:00", + "2023-05-28T02:00:00", + "2023-05-28T04:00:00", + "2023-05-28T06:00:00", + "2023-05-28T08:00:00", + "2023-05-28T10:00:00", + "2023-05-28T12:00:00", + "2023-05-28T14:00:00", + "2023-05-28T16:00:00", + "2023-05-28T18:00:00", + "2023-05-28T20:00:00", + "2023-05-28T22:00:00", + "2023-05-29T00:00:00", + "2023-05-29T02:00:00", + "2023-05-29T04:00:00", + "2023-05-29T06:00:00", + "2023-05-29T08:00:00", + "2023-05-29T10:00:00", + "2023-05-29T12:00:00", + "2023-05-29T14:00:00", + "2023-05-29T16:00:00", + "2023-05-29T18:00:00", + "2023-05-29T20:00:00", + "2023-05-29T22:00:00", + "2023-05-30T00:00:00", + "2023-05-30T02:00:00", + "2023-05-30T04:00:00", + "2023-05-30T06:00:00", + "2023-05-30T08:00:00", + "2023-05-30T10:00:00", + "2023-05-30T12:00:00", + "2023-05-30T14:00:00", + "2023-05-30T16:00:00", + "2023-05-30T18:00:00", + "2023-05-30T20:00:00", + "2023-05-30T22:00:00", + "2023-05-31T00:00:00", + "2023-05-31T02:00:00", + "2023-05-31T04:00:00", + "2023-05-31T06:00:00", + "2023-05-31T08:00:00", + "2023-05-31T10:00:00", + "2023-05-31T12:00:00", + "2023-05-31T14:00:00", + "2023-05-31T16:00:00", + "2023-05-31T18:00:00", + "2023-05-31T20:00:00", + "2023-05-31T22:00:00", + "2023-06-01T00:00:00" + ], + "y": [ + 15603.0, + 15748.0, + 15831.0, + 15832.0, + 15801.0, + 15795.0, + 15801.0, + 15906.0, + 15839.0, + 15898.0, + 15877.0, + 15906.0, + 15868.0, + 15858.0, + 15839.0, + 15818.0, + 15901.0, + 15916.0, + 15846.0, + 15870.0, + 15867.0, + 15774.0, + 15837.0, + 15860.0, + 15820.0, + 15832.0, + 15811.0, + 15805.0, + 15828.0, + 15857.0, + 15793.0, + 15692.0, + 15678.0, + 15734.0, + 15843.0, + 15861.0, + 15825.0, + 15859.0, + 15857.0, + 15850.0, + 15866.0, + 15873.0, + 15883.0, + 15863.0, + 15865.0, + 15869.0, + 15839.0, + 15773.0, + 15832.0, + 15847.0, + 15814.0, + 15854.0, + 15854.0, + 15818.0, + 15809.0, + 15845.0, + 15848.0, + 15847.0, + 15834.0, + 15822.0, + 15826.0, + 15823.0, + 15843.0, + 15834.0, + 15854.0, + 15820.0, + 15830.0, + 15819.0, + 15815.0, + 15805.0, + 15842.0, + 15831.0, + 15879.0, + 15912.0, + 15848.0, + 15827.0, + 15837.0, + 15866.0, + 15842.0, + 15811.0, + 15837.0, + 15836.0, + 15815.0, + 15897.0, + 15820.0, + 15824.0, + 15802.0, + 15821.0, + 15807.0, + 15786.0, + 15823.0, + 15755.0, + 15675.0, + 15678.0, + 15700.0, + 15707.0, + 15673.0, + 15658.0, + 15592.0, + 15637.0, + 15631.0, + 15650.0, + 15619.0, + 15585.0, + 15647.0, + 15622.0, + 15550.0, + 15569.0, + 15544.0, + 15560.0, + 15606.0, + 15579.0, + 15578.0, + 15599.0, + 15578.0, + 15561.0, + 15532.0, + 15562.0, + 15565.0, + 15580.0, + 15585.0, + 15581.0, + 15529.0, + 15473.0, + 15501.0, + 15452.0, + 15438.0, + 15523.0, + 15415.0, + 15454.0, + 15497.0, + 15518.0, + 15479.0, + 15451.0, + 15452.0, + 15476.0, + 15445.0, + 15461.0, + 15510.0, + 15504.0, + 15489.0, + 15470.0, + 15444.0, + 15439.0, + 15437.0, + 15433.0, + 15425.0, + 15426.0, + 15439.0, + 15465.0, + 15462.0, + 15442.0, + 15466.0, + 15504.0, + 15516.0, + 15533.0, + 15483.0, + 15569.0, + 15549.0, + 15661.0, + 15653.0, + 15660.0, + 15629.0, + 15692.0, + 15666.0, + 15682.0, + 15682.0, + 15605.0, + 15639.0, + 15621.0, + 15637.0, + 15710.0, + 15859.0, + 15874.0, + 15833.0, + 15790.0, + 15763.0, + 15729.0, + 15770.0, + 15784.0, + 15803.0, + 15929.0, + 15921.0, + 15897.0, + 15869.0, + 15869.0, + 15856.0, + 15889.0, + 15936.0, + 15872.0, + 15849.0, + 15896.0, + 15838.0, + 15866.0, + 15863.0, + 15847.0, + 15797.0, + 15848.0, + 15895.0, + 16001.0, + 15970.0, + 16001.0, + 15992.0, + 16001.0, + 15975.0, + 15991.0, + 15988.0, + 15966.0, + 15953.0, + 15944.0, + 15887.0, + 15871.0, + 15823.0, + 15888.0, + 15891.0, + 15924.0, + 15926.0, + 15922.0, + 15910.0, + 15929.0, + 15888.0, + 15887.0, + 15901.0, + 15926.0, + 15919.0, + 15910.0, + 15904.0, + 15911.0, + 15912.0, + 15921.0, + 15923.0, + 15904.0, + 15911.0, + 15910.0, + 15883.0, + 15962.0, + 15883.0, + 15879.0, + 15918.0, + 16069.0, + 16114.0, + 16126.0, + 16091.0, + 16114.0, + 16156.0, + 16148.0, + 16070.0, + 16073.0, + 16150.0, + 16101.0, + 16016.0, + 16017.0, + 16027.0, + 16035.0, + 16043.0, + 16010.0, + 16050.0, + 16065.0, + 16074.0, + 16144.0, + 16135.0, + 16222.0, + 16287.0, + 16235.0, + 16282.0, + 16240.0, + 16171.0, + 16238.0, + 16245.0, + 16230.0, + 16210.0, + 16124.0, + 16171.0, + 16299.0, + 16307.0, + 16635.0, + 16923.0, + 16922.0, + 16795.0, + 16836.0, + 16875.0, + 16914.0, + 16896.0, + 16736.0, + 17360.0, + 17430.0, + 17350.0, + 17374.0, + 17297.0, + 17389.0, + 17342.0, + 17347.0, + 17462.0, + 17515.0, + 17482.0, + 17816.0, + 17800.0, + 17880.0, + 18281.0, + 18384.0, + 19320.0, + 19309.0, + 19211.0, + 19301.0, + 18935.0, + 19122.0, + 19328.0, + 19164.0, + 19137.0, + 19170.0, + 19260.0, + 19347.0, + 19157.0, + 19081.0, + 19129.0, + 19092.0, + 19136.0, + 19102.0, + 19068.0, + 19281.0, + 19301.0, + 19243.0, + 19301.0, + 19277.0, + 19496.0, + 19412.0, + 19533.0, + 19500.0, + 19244.0, + 19237.0, + 19251.0, + 19381.0, + 19524.0, + 19700.0, + 19510.0, + 19566.0, + 19466.0, + 19529.0, + 19541.0, + 19536.0, + 19595.0, + 19579.0, + 19606.0, + 19628.0, + 19694.0, + 19763.0, + 19751.0, + 19610.0, + 19675.0, + 19759.0, + 19783.0, + 19696.0, + 19548.0, + 19616.0, + 19722.0, + 19436.0, + 19338.0, + 19347.0, + 19225.0, + 19133.0, + 19171.0, + 19185.0, + 19278.0, + 19224.0, + 19205.0, + 19131.0, + 19233.0, + 19337.0, + 19265.0, + 19488.0, + 19338.0, + 19447.0, + 19499.0, + 19465.0, + 19367.0, + 19339.0, + 19365.0, + 19340.0, + 19487.0, + 19540.0, + 19678.0, + 19797.0, + 20531.0, + 20858.0, + 20779.0, + 20757.0, + 20790.0, + 20848.0, + 21235.0, + 21113.0, + 21118.0, + 21186.0, + 21426.0, + 21469.0, + 21376.0, + 20990.0, + 21030.0, + 20981.0, + 21108.0, + 21128.0, + 21088.0, + 20985.0, + 21121.0, + 20997.0, + 21131.0, + 20936.0, + 20794.0, + 20912.0, + 20868.0, + 20793.0, + 20876.0, + 20813.0, + 20884.0, + 21062.0, + 21005.0, + 21046.0, + 21230.0, + 21003.0, + 21145.0, + 21078.0, + 21242.0, + 21234.0, + 21262.0, + 21160.0, + 21053.0, + 21089.0, + 21054.0, + 21068.0, + 21032.0, + 21147.0, + 21054.0, + 20799.0, + 20665.0, + 20764.0, + 20817.0, + 20897.0, + 20777.0, + 20784.0, + 20771.0, + 20693.0, + 20707.0, + 20854.0, + 21615.0, + 21126.0, + 21217.0, + 21176.0, + 21226.0, + 21045.0, + 21070.0, + 21108.0, + 21216.0, + 21151.0, + 21136.0, + 21173.0, + 21196.0, + 21112.0, + 20772.0, + 20957.0, + 21162.0, + 21206.0, + 21083.0, + 21110.0, + 21078.0, + 21188.0, + 21365.0, + 21389.0, + 21248.0, + 21257.0, + 21241.0, + 21304.0, + 21243.0, + 21182.0, + 21160.0, + 21168.0, + 21169.0, + 21194.0, + 21176.0, + 21224.0, + 21172.0, + 21212.0, + 21380.0, + 21337.0, + 21400.0, + 21369.0, + 21421.0, + 21540.0, + 21665.0, + 21628.0, + 21693.0, + 21988.0, + 21913.0, + 21840.0, + 21766.0, + 21810.0, + 21835.0, + 21785.0, + 21251.0, + 21191.0, + 21176.0, + 21341.0, + 21296.0, + 21000.0, + 20977.0, + 21067.0, + 21050.0, + 21062.0, + 21000.0, + 21206.0, + 21138.0, + 21112.0, + 21308.0, + 21303.0, + 21318.0, + 21317.0, + 21132.0, + 21311.0, + 21282.0, + 21293.0, + 21270.0, + 21213.0, + 21141.0, + 21172.0, + 21180.0, + 21058.0, + 21092.0, + 21321.0, + 21550.0, + 21550.0, + 21752.0, + 21632.0, + 21611.0, + 21625.0, + 21646.0, + 21646.0, + 21714.0, + 21812.0, + 21909.0, + 21827.0, + 21507.0, + 21532.0, + 21638.0, + 21600.0, + 21578.0, + 21532.0, + 21445.0, + 21554.0, + 21553.0, + 21730.0, + 21731.0, + 21562.0, + 21671.0, + 21687.0, + 21659.0, + 21600.0, + 21601.0, + 21622.0, + 21634.0, + 21655.0, + 21758.0, + 21695.0, + 21729.0, + 21711.0, + 21671.0, + 21626.0, + 21616.0, + 21623.0, + 21656.0, + 21680.0, + 21661.0, + 21654.0, + 21491.0, + 21398.0, + 21169.0, + 21216.0, + 21248.0, + 21269.0, + 21301.0, + 21229.0, + 21099.0, + 21250.0, + 21227.0, + 21239.0, + 21209.0, + 21459.0, + 21499.0, + 21453.0, + 21369.0, + 21216.0, + 21248.0, + 21298.0, + 21341.0, + 21354.0, + 21481.0, + 21462.0, + 21495.0, + 21400.0, + 21616.0, + 21546.0, + 21604.0, + 21661.0, + 21673.0, + 21670.0, + 21630.0, + 21576.0, + 21552.0, + 21570.0, + 21525.0, + 21332.0, + 21435.0, + 21339.0, + 21425.0, + 21445.0, + 21378.0, + 20992.0, + 21073.0, + 21137.0, + 21130.0, + 21081.0, + 21059.0, + 21012.0, + 20974.0, + 20522.0, + 20348.0, + 20303.0, + 20406.0, + 20349.0, + 20329.0, + 20400.0, + 20400.0, + 20318.0, + 20371.0, + 20296.0, + 20346.0, + 20392.0, + 20180.0, + 20275.0, + 20275.0, + 20320.0, + 20318.0, + 20333.0, + 20334.0, + 20334.0, + 20392.0, + 20350.0, + 20322.0, + 20312.0, + 20468.0, + 20505.0, + 20446.0, + 20409.0, + 20437.0, + 20428.0, + 20551.0, + 20522.0, + 20475.0, + 20573.0, + 20623.0, + 20651.0, + 20385.0, + 20421.0, + 20342.0, + 20470.0, + 20471.0, + 20493.0, + 20240.0, + 20231.0, + 20200.0, + 20139.0, + 20040.0, + 20160.0, + 20148.0, + 20302.0, + 20223.0, + 20225.0, + 20251.0, + 20304.0, + 20281.0, + 20294.0, + 20199.0, + 20595.0, + 20547.0, + 20704.0, + 20709.0, + 20690.0, + 20597.0, + 20601.0, + 20668.0, + 20629.0, + 20679.0, + 20950.0, + 21220.0, + 21370.0, + 21370.0, + 21799.0, + 22596.0, + 22714.0, + 22969.0, + 23072.0, + 23014.0, + 22929.0, + 22992.0, + 22947.0, + 22852.0, + 23500.0, + 23268.0, + 23264.0, + 22982.0, + 22043.0, + 22395.0, + 22378.0, + 22286.0, + 22224.0, + 22334.0, + 22393.0, + 22360.0, + 22653.0, + 22754.0, + 22936.0, + 22861.0, + 22970.0, + 23068.0, + 22987.0, + 23049.0, + 22925.0, + 22971.0, + 22913.0, + 22971.0, + 23065.0, + 23082.0, + 23022.0, + 23018.0, + 23029.0, + 23108.0, + 23049.0, + 23127.0, + 22982.0, + 22981.0, + 23083.0, + 23089.0, + 23265.0, + 22780.0, + 22951.0, + 22961.0, + 22724.0, + 22715.0, + 22867.0, + 22921.0, + 22905.0, + 23265.0, + 23277.0, + 23242.0, + 23315.0, + 23221.0, + 23243.0, + 23186.0, + 23250.0, + 23299.0, + 23369.0, + 23363.0, + 23436.0, + 23261.0, + 23066.0, + 23075.0, + 23000.0, + 23156.0, + 23126.0, + 22748.0, + 22974.0, + 22715.0, + 22721.0, + 22634.0, + 22582.0, + 22674.0, + 22746.0, + 22669.0, + 22338.0, + 22352.0, + 22463.0, + 22440.0, + 22816.0, + 22787.0, + 23028.0, + 22950.0, + 22936.0, + 22929.0, + 22467.0, + 22644.0, + 22590.0, + 22537.0, + 22650.0, + 22556.0, + 22602.0, + 22652.0, + 22628.0, + 22573.0, + 22530.0, + 22543.0, + 22586.0, + 22526.0, + 22176.0, + 21906.0, + 21965.0, + 21936.0, + 22009.0, + 22016.0, + 21904.0, + 21881.0, + 21943.0, + 21899.0, + 21801.0, + 21812.0, + 21857.0, + 21875.0, + 21808.0, + 21822.0, + 22067.0, + 21989.0, + 22103.0, + 22000.0, + 22046.0, + 22178.0, + 22130.0, + 22082.0, + 22146.0, + 22085.0, + 22362.0, + 22389.0, + 22335.0, + 22333.0, + 22334.0, + 22194.0, + 22209.0, + 22143.0, + 22198.0, + 22416.0, + 22247.0, + 22034.0, + 21967.0, + 22035.0, + 22142.0, + 22153.0, + 22167.0, + 22104.0, + 21937.0, + 21953.0, + 22068.0, + 22030.0, + 22180.0, + 22181.0, + 21991.0, + 21895.0, + 21885.0, + 21986.0, + 22143.0, + 22357.0, + 22269.0, + 22330.0, + 22249.0, + 22205.0, + 22210.0, + 22237.0, + 21929.0, + 22089.0, + 22163.0, + 22089.0, + 22090.0, + 22036.0, + 21980.0, + 22042.0, + 22030.0, + 22028.0, + 22010.0, + 21992.0, + 22135.0, + 22102.0, + 22115.0, + 20961.0, + 21075.0, + 21086.0, + 21121.0, + 21104.0, + 21076.0, + 21116.0, + 21098.0, + 21104.0, + 21035.0, + 20917.0, + 21031.0, + 21026.0, + 21039.0, + 21017.0, + 21034.0, + 21007.0, + 21043.0, + 21047.0, + 20998.0, + 20979.0, + 20931.0, + 20864.0, + 21008.0, + 21256.0, + 21051.0, + 21092.0, + 21071.0, + 21052.0, + 21066.0, + 21148.0, + 21124.0, + 21094.0, + 21093.0, + 21171.0, + 21126.0, + 21073.0, + 21046.0, + 21009.0, + 21030.0, + 21079.0, + 21010.0, + 21056.0, + 21139.0, + 21049.0, + 20971.0, + 20972.0, + 20962.0, + 21051.0, + 21000.0, + 21022.0, + 20977.0, + 20996.0, + 20965.0, + 20996.0, + 21065.0, + 21112.0, + 20968.0, + 20913.0, + 21042.0, + 21019.0, + 21024.0, + 20849.0, + 20812.0, + 20887.0, + 20948.0, + 20859.0, + 20983.0, + 20895.0, + 20853.0, + 20845.0, + 20587.0, + 20593.0, + 20641.0, + 20577.0, + 20520.0, + 20475.0, + 20482.0, + 20518.0, + 20446.0, + 20269.0, + 19683.0, + 19145.0, + 19257.0, + 18984.0, + 18946.0, + 18903.0, + 18843.0, + 18779.0, + 18673.0, + 19026.0, + 18760.0, + 18697.0, + 18844.0, + 18902.0, + 18989.0, + 19567.0, + 19342.0, + 19277.0, + 18786.0, + 18949.0, + 19034.0, + 18942.0, + 18888.0, + 19017.0, + 19050.0, + 19155.0, + 19219.0, + 19217.0, + 19181.0, + 19200.0, + 19195.0, + 19216.0, + 19237.0, + 19209.0, + 19257.0, + 19638.0, + 19577.0, + 19974.0, + 20665.0, + 20993.0, + 20775.0, + 20880.0, + 20891.0, + 20562.0, + 20616.0, + 21000.0, + 22323.0, + 22407.0, + 22505.0, + 22192.0, + 22338.0, + 22600.0, + 22678.0, + 22547.0, + 22488.0, + 22613.0, + 23072.0, + 23972.0, + 24160.0, + 23810.0, + 23275.0, + 22855.0, + 23000.0, + 23137.0, + 22987.0, + 23006.0, + 23194.0, + 22994.0, + 23422.0, + 23514.0, + 23244.0, + 23036.0, + 23052.0, + 23163.0, + 22973.0, + 22982.0, + 22945.0, + 23000.0, + 23212.0, + 23257.0, + 23469.0, + 23433.0, + 23475.0, + 23324.0, + 23590.0, + 23523.0, + 23605.0, + 24196.0, + 24237.0, + 24200.0, + 24511.0, + 24721.0, + 25360.0, + 24911.0, + 24863.0, + 24884.0, + 25192.0, + 25426.0, + 25656.0, + 25591.0, + 25620.0, + 25879.0, + 25699.0, + 25708.0, + 25765.0, + 25732.0, + 25518.0, + 25591.0, + 25678.0, + 25568.0, + 25245.0, + 25419.0, + 25539.0, + 25411.0, + 25280.0, + 25350.0, + 25492.0, + 25506.0, + 25854.0, + 26222.0, + 26549.0, + 26259.0, + 26264.0, + 25987.0, + 25661.0, + 25882.0, + 26519.0, + 26484.0, + 26441.0, + 26025.0, + 25908.0, + 25882.0, + 25967.0, + 26166.0, + 25952.0, + 26091.0, + 25968.0, + 26048.0, + 25756.0, + 26098.0, + 26103.0, + 26100.0, + 26100.0, + 26055.0, + 26200.0, + 26083.0, + 26173.0, + 26158.0, + 26200.0, + 26279.0, + 26160.0, + 26119.0, + 26132.0, + 26340.0, + 26535.0, + 26451.0, + 24551.0, + 25010.0, + 25158.0, + 25005.0, + 25207.0, + 25443.0, + 25420.0, + 25450.0, + 25447.0, + 25207.0, + 26296.0, + 26075.0, + 26216.0, + 26042.0, + 26145.0, + 26121.0, + 26102.0, + 26157.0, + 26130.0, + 26149.0, + 25769.0, + 25967.0, + 26064.0, + 25672.0, + 25921.0, + 25508.0, + 25596.0, + 25615.0, + 25686.0, + 25588.0, + 25622.0, + 25596.0, + 25581.0, + 25679.0, + 25719.0, + 25604.0, + 25323.0, + 25562.0, + 25570.0, + 25708.0, + 25618.0, + 25631.0, + 25619.0, + 25740.0, + 25940.0, + 26165.0, + 25902.0, + 25922.0, + 25908.0, + 25911.0, + 25968.0, + 25864.0, + 25901.0, + 25725.0, + 25873.0, + 25956.0, + 25886.0, + 25697.0, + 24973.0, + 25000.0, + 25003.0, + 25180.0, + 25140.0, + 25062.0, + 24966.0, + 24972.0, + 24920.0, + 24880.0, + 25012.0, + 24832.0, + 24911.0, + 24798.0, + 25268.0, + 25063.0, + 25187.0, + 25230.0, + 25256.0, + 25449.0, + 25892.0, + 26044.0, + 26073.0, + 26175.0, + 26240.0, + 26018.0, + 26198.0, + 26089.0, + 26155.0, + 26185.0, + 26256.0, + 26394.0, + 26493.0, + 26341.0, + 26343.0, + 26122.0, + 25999.0, + 25579.0, + 25686.0, + 25775.0, + 25760.0, + 25833.0, + 25871.0, + 25757.0, + 25510.0, + 25596.0, + 25714.0, + 26017.0, + 26194.0, + 26113.0, + 26237.0, + 26269.0, + 26233.0, + 26388.0, + 26302.0, + 26327.0, + 26207.0, + 26231.0, + 26200.0, + 26205.0, + 26212.0, + 26192.0, + 26161.0, + 26296.0, + 26234.0, + 26211.0, + 26245.0, + 26259.0, + 26195.0, + 26216.0, + 26156.0, + 26103.0, + 25979.0, + 26061.0, + 25837.0, + 25868.0, + 26082.0, + 25668.0, + 25756.0, + 25701.0, + 25796.0, + 26128.0, + 25984.0, + 25986.0, + 25810.0, + 25745.0, + 25793.0, + 25448.0, + 25507.0, + 25520.0, + 25656.0, + 25644.0, + 25662.0, + 25828.0, + 25942.0, + 25753.0, + 25622.0, + 25790.0, + 25746.0, + 25782.0, + 25711.0, + 26066.0, + 26029.0, + 26100.0, + 26041.0, + 26044.0, + 26108.0, + 25987.0, + 25718.0, + 25755.0, + 25926.0, + 25856.0, + 25857.0, + 25780.0, + 25855.0, + 25766.0, + 25615.0, + 25593.0, + 25630.0, + 25624.0, + 25717.0, + 25674.0, + 25714.0, + 25678.0, + 25715.0, + 25735.0, + 25722.0, + 25672.0, + 25535.0, + 25571.0, + 25534.0, + 25673.0, + 25662.0, + 25632.0, + 25622.0, + 25600.0, + 25629.0, + 25638.0, + 25731.0, + 25818.0, + 25812.0, + 25741.0, + 25754.0, + 25742.0, + 25722.0, + 25689.0, + 25634.0, + 25658.0, + 25685.0, + 25821.0, + 25787.0, + 25750.0, + 25650.0, + 25651.0, + 25677.0, + 25665.0, + 25650.0, + 25644.0, + 25811.0, + 26090.0, + 25952.0, + 25970.0, + 25961.0, + 25989.0, + 25967.0, + 25980.0, + 26034.0, + 26011.0, + 26236.0, + 26837.0, + 26853.0, + 26889.0, + 27264.0, + 27668.0, + 27647.0, + 27387.0, + 27615.0, + 27545.0, + 27537.0, + 27687.0, + 27700.0, + 27678.0, + 27620.0, + 27692.0, + 27652.0, + 27649.0, + 27414.0, + 27382.0, + 27452.0, + 27490.0, + 27503.0, + 27405.0, + 27317.0, + 27316.0, + 27102.0, + 27258.0, + 27179.0, + 27357.0, + 27379.0, + 27419.0, + 27368.0, + 27413.0, + 27410.0, + 27334.0, + 27567.0, + 27580.0, + 27513.0, + 27451.0, + 27541.0, + 27842.0, + 27730.0, + 27847.0, + 27799.0, + 27854.0, + 27905.0, + 27890.0, + 27554.0, + 27586.0, + 27617.0, + 27730.0, + 27706.0, + 27639.0, + 27639.0, + 27696.0, + 27717.0, + 27748.0, + 27665.0, + 27640.0, + 27610.0, + 27570.0, + 27621.0, + 27576.0, + 27577.0, + 27544.0, + 27611.0, + 27652.0, + 27583.0, + 27548.0, + 27541.0, + 27616.0, + 27585.0, + 27594.0, + 27659.0, + 27625.0, + 27336.0, + 27340.0, + 27321.0, + 27134.0, + 27243.0, + 26973.0, + 26894.0, + 26923.0, + 27003.0, + 27039.0, + 27020.0, + 26978.0, + 26955.0, + 26998.0, + 27100.0, + 27212.0, + 27258.0, + 27680.0, + 27715.0, + 27550.0, + 27389.0, + 27583.0, + 27689.0, + 27691.0, + 27575.0, + 27552.0, + 27635.0, + 27457.0, + 26751.0, + 26844.0, + 26801.0, + 26747.0, + 26790.0, + 26703.0, + 26641.0, + 26343.0, + 26409.0, + 26364.0, + 26383.0, + 26358.0, + 26342.0, + 26113.0, + 26275.0, + 25972.0, + 25955.0, + 25644.0, + 25750.0, + 25757.0, + 25734.0, + 25831.0, + 25681.0, + 25693.0, + 25630.0, + 25552.0, + 25657.0, + 25557.0, + 25403.0, + 24834.0, + 24833.0, + 24793.0, + 24831.0, + 24842.0, + 24951.0, + 24860.0, + 24829.0, + 24880.0, + 24895.0, + 25104.0, + 25341.0, + 25250.0, + 25330.0, + 25503.0, + 25182.0, + 25148.0, + 25238.0, + 25399.0, + 25320.0, + 25280.0, + 25267.0, + 25084.0, + 25131.0, + 25092.0, + 25063.0, + 25136.0, + 25267.0, + 25326.0, + 25247.0, + 24979.0, + 24839.0, + 25034.0, + 25067.0, + 24732.0, + 24800.0, + 24810.0, + 24824.0, + 24876.0, + 24792.0, + 24727.0, + 24794.0, + 24712.0, + 24763.0, + 24869.0, + 24859.0, + 24937.0, + 25203.0, + 25197.0, + 25782.0, + 25795.0, + 25844.0, + 25800.0, + 25868.0, + 25763.0, + 26157.0, + 26188.0, + 26910.0, + 26986.0, + 26920.0, + 25365.0, + 25999.0, + 25735.0, + 26034.0, + 26162.0, + 26324.0, + 26180.0, + 26239.0, + 26238.0, + 26273.0, + 26463.0, + 26576.0, + 26888.0, + 26879.0, + 26735.0, + 26777.0, + 26686.0, + 26781.0, + 26792.0, + 26587.0, + 26678.0, + 26404.0, + 26426.0, + 26547.0, + 26617.0, + 26620.0, + 26588.0, + 26576.0, + 26646.0, + 26659.0, + 26657.0, + 26586.0, + 26619.0, + 26701.0, + 26595.0, + 26486.0, + 26561.0, + 26546.0, + 26529.0, + 26425.0, + 26481.0, + 26568.0, + 26579.0, + 26556.0, + 26514.0, + 26580.0, + 26920.0, + 26887.0, + 26667.0, + 26703.0, + 26526.0, + 25946.0, + 25963.0, + 25913.0, + 26039.0, + 25944.0, + 25948.0, + 25865.0, + 25717.0, + 25801.0, + 25397.0, + 25548.0, + 25603.0, + 25503.0, + 25586.0, + 25521.0, + 25538.0, + 25559.0, + 25630.0, + 25583.0, + 25980.0, + 26003.0, + 26062.0, + 26053.0, + 26032.0, + 25883.0, + 25869.0, + 25860.0, + 25981.0, + 25971.0, + 25874.0, + 25732.0, + 25645.0, + 25847.0, + 25656.0, + 26152.0, + 26182.0, + 26226.0, + 26246.0, + 26373.0, + 26262.0, + 26316.0, + 26338.0, + 26102.0, + 26257.0, + 26161.0, + 26241.0, + 26207.0, + 26161.0, + 26548.0, + 26434.0, + 26453.0, + 26344.0, + 26396.0, + 26462.0, + 26565.0, + 26642.0, + 26763.0, + 26817.0, + 26762.0, + 26783.0, + 26837.0, + 26658.0, + 26631.0, + 26673.0, + 26626.0, + 26609.0, + 26316.0, + 26007.0, + 26198.0, + 26253.0, + 26220.0, + 26256.0, + 26236.0, + 26211.0, + 26233.0, + 26308.0, + 26205.0, + 26229.0, + 26275.0, + 26322.0, + 26291.0, + 26322.0, + 26137.0, + 25868.0, + 25639.0, + 25606.0, + 25659.0, + 25382.0, + 25359.0, + 25358.0, + 25264.0, + 25340.0, + 25106.0, + 24889.0, + 25039.0, + 25197.0, + 25263.0, + 25174.0, + 25067.0, + 25221.0, + 25121.0, + 25272.0, + 25223.0, + 25045.0, + 25213.0, + 25280.0, + 25189.0, + 25217.0, + 25265.0, + 25238.0, + 25255.0, + 25137.0, + 25159.0, + 25275.0, + 25666.0, + 25683.0, + 25093.0, + 25231.0, + 25082.0, + 25156.0, + 25094.0, + 25024.0, + 25106.0, + 25130.0, + 25106.0, + 25080.0, + 24931.0, + 24904.0, + 24687.0, + 24600.0, + 24729.0, + 24748.0, + 24606.0, + 24327.0, + 24084.0, + 24127.0, + 24202.0, + 24214.0, + 24309.0, + 24254.0, + 24234.0, + 24397.0, + 24691.0, + 24695.0, + 24743.0, + 24725.0, + 24662.0, + 24689.0, + 24759.0, + 24731.0, + 24741.0, + 24746.0, + 24745.0, + 24782.0, + 24797.0, + 24708.0, + 24614.0, + 24784.0, + 24746.0, + 24748.0, + 24767.0, + 24714.0, + 24817.0, + 24959.0, + 24847.0, + 24777.0, + 24790.0, + 24825.0, + 25053.0, + 25082.0, + 25170.0, + 25208.0, + 25223.0, + 25152.0, + 25175.0, + 25200.0, + 25284.0, + 25209.0, + 25173.0, + 24984.0, + 24835.0, + 24945.0, + 24893.0, + 25048.0, + 24865.0, + 24854.0, + 24810.0, + 24886.0, + 24923.0, + 24802.0, + 24857.0, + 24888.0, + 24991.0, + 24912.0, + 24851.0, + 24781.0, + 24817.0, + 24600.0, + 24623.0, + 24753.0, + 25009.0, + 25263.0, + 25228.0, + 25260.0, + 25182.0, + 25225.0, + 25119.0, + 25317.0, + 25332.0, + 25322.0, + 25285.0, + 25115.0, + 24611.0, + 24827.0, + 24977.0, + 24893.0, + 24909.0, + 24925.0, + 24942.0, + 24921.0, + 24855.0, + 24865.0, + 24903.0, + 24864.0, + 24875.0, + 24849.0, + 24910.0, + 24878.0, + 24870.0, + 24869.0, + 24876.0, + 24864.0, + 24899.0, + 24893.0, + 24889.0, + 24954.0, + 25120.0, + 25044.0, + 25024.0, + 25089.0, + 25114.0, + 25151.0, + 25077.0, + 25022.0, + 25028.0, + 24836.0, + 24873.0, + 24889.0, + 24858.0, + 24901.0, + 24763.0, + 24711.0, + 24589.0, + 24635.0, + 24762.0, + 24845.0, + 24821.0, + 24798.0, + 24977.0, + 24880.0, + 24831.0, + 24820.0, + 24884.0, + 24842.0, + 24970.0, + 25304.0, + 25360.0, + 25258.0, + 25282.0, + 25359.0, + 25253.0, + 25352.0, + 25229.0, + 25251.0, + 25225.0, + 25274.0, + 25203.0, + 24840.0, + 24837.0, + 24742.0, + 24829.0, + 24819.0, + 24579.0, + 24458.0, + 24438.0, + 24407.0, + 24537.0, + 24500.0, + 24311.0, + 24435.0, + 24525.0, + 24399.0, + 24500.0, + 24518.0, + 24589.0, + 24441.0, + 24566.0, + 24675.0, + 24689.0, + 24695.0, + 24615.0, + 24631.0, + 24545.0, + 24674.0, + 24652.0, + 24619.0, + 24734.0, + 24965.0, + 24909.0, + 24954.0, + 24911.0, + 24910.0, + 24894.0, + 24957.0, + 24909.0, + 24926.0, + 24910.0, + 24908.0, + 24844.0, + 24893.0, + 24945.0, + 24933.0, + 24953.0, + 25047.0, + 25238.0, + 25322.0, + 25309.0, + 25346.0, + 25292.0, + 25300.0, + 25301.0, + 25402.0, + 25470.0, + 25627.0, + 25948.0, + 26162.0, + 26245.0, + 26038.0, + 26053.0, + 26006.0, + 26053.0, + 26056.0, + 26035.0, + 25780.0, + 25856.0, + 25800.0, + 25837.0, + 25915.0, + 25893.0, + 25973.0, + 25960.0, + 25951.0, + 26001.0, + 26092.0, + 25921.0, + 25811.0, + 25866.0, + 25956.0, + 25835.0, + 25820.0, + 25904.0, + 25850.0, + 25332.0, + 25452.0, + 25431.0, + 25389.0, + 25380.0, + 25278.0, + 25388.0, + 25292.0, + 25350.0, + 25469.0, + 25358.0 + ], + "type": "scatter", + "xaxis": "x", + "yaxis": "y" + }, + { + "marker": { + "color": "green", + "symbol": "arrow-up" + }, + "mode": "markers", + "name": "Buy", + "x": [ + "2022-12-20T00:00:00", + "2022-12-20T02:00:00", + "2022-12-20T04:00:00", + "2022-12-20T06:00:00", + "2022-12-20T08:00:00", + "2022-12-20T10:00:00", + "2022-12-20T12:00:00", + "2022-12-20T14:00:00", + "2022-12-20T16:00:00", + "2022-12-20T18:00:00", + "2022-12-20T20:00:00", + "2022-12-20T22:00:00", + "2022-12-21T00:00:00", + "2022-12-21T02:00:00", + "2022-12-21T04:00:00", + "2022-12-21T06:00:00", + "2022-12-21T08:00:00", + "2022-12-21T10:00:00", + "2022-12-21T12:00:00", + "2022-12-21T14:00:00", + "2022-12-21T16:00:00", + "2022-12-21T18:00:00", + "2022-12-21T20:00:00", + "2022-12-21T22:00:00", + "2022-12-22T00:00:00", + "2022-12-22T02:00:00", + "2022-12-22T04:00:00", + "2022-12-22T06:00:00", + "2022-12-22T08:00:00", + "2022-12-22T10:00:00", + "2022-12-22T12:00:00", + "2022-12-22T14:00:00", + "2022-12-22T16:00:00", + "2022-12-22T18:00:00", + "2022-12-22T20:00:00", + "2022-12-22T22:00:00", + "2022-12-23T00:00:00", + "2022-12-23T02:00:00", + "2022-12-23T04:00:00", + "2022-12-23T06:00:00", + "2022-12-23T08:00:00", + "2022-12-23T10:00:00", + "2022-12-23T12:00:00", + "2022-12-23T14:00:00", + "2022-12-23T16:00:00", + "2022-12-23T18:00:00", + "2022-12-23T20:00:00", + "2022-12-23T22:00:00", + "2022-12-24T00:00:00", + "2022-12-24T02:00:00", + "2022-12-24T04:00:00", + "2022-12-24T06:00:00", + "2022-12-24T08:00:00", + "2022-12-24T10:00:00", + "2022-12-24T12:00:00", + "2022-12-24T14:00:00", + "2022-12-24T16:00:00", + "2022-12-24T18:00:00", + "2022-12-24T20:00:00", + "2022-12-24T22:00:00", + "2022-12-25T00:00:00", + "2022-12-25T02:00:00", + "2022-12-25T04:00:00", + "2022-12-25T06:00:00", + "2022-12-25T08:00:00", + "2022-12-25T10:00:00", + "2022-12-25T12:00:00", + "2022-12-25T14:00:00", + "2022-12-25T16:00:00", + "2022-12-25T18:00:00", + "2022-12-25T20:00:00", + "2022-12-25T22:00:00", + "2022-12-26T00:00:00", + "2022-12-26T02:00:00", + "2022-12-26T04:00:00", + "2022-12-26T06:00:00", + "2022-12-26T08:00:00", + "2022-12-26T10:00:00", + "2022-12-26T12:00:00", + "2022-12-26T14:00:00", + "2022-12-26T16:00:00", + "2022-12-26T18:00:00", + "2022-12-26T20:00:00", + "2022-12-26T22:00:00", + "2022-12-27T00:00:00", + "2022-12-27T02:00:00", + "2022-12-27T04:00:00", + "2022-12-27T06:00:00", + "2022-12-27T08:00:00", + "2022-12-27T10:00:00", + "2022-12-27T12:00:00", + "2022-12-27T14:00:00", + "2022-12-27T16:00:00", + "2022-12-27T18:00:00", + "2022-12-27T20:00:00", + "2022-12-27T22:00:00", + "2022-12-28T00:00:00", + "2022-12-28T02:00:00", + "2022-12-28T04:00:00", + "2022-12-28T06:00:00", + "2022-12-28T08:00:00", + "2022-12-28T10:00:00", + "2022-12-28T12:00:00", + "2022-12-28T14:00:00", + "2022-12-28T16:00:00", + "2022-12-28T18:00:00", + "2022-12-28T20:00:00", + "2022-12-28T22:00:00", + "2022-12-29T00:00:00", + "2022-12-29T02:00:00", + "2022-12-29T04:00:00", + "2022-12-29T06:00:00", + "2022-12-29T08:00:00", + "2022-12-29T10:00:00", + "2022-12-29T12:00:00", + "2022-12-29T14:00:00", + "2022-12-29T16:00:00", + "2022-12-29T18:00:00", + "2022-12-29T20:00:00", + "2022-12-29T22:00:00", + "2022-12-30T00:00:00", + "2022-12-30T02:00:00", + "2022-12-30T04:00:00", + "2022-12-30T06:00:00", + "2022-12-30T08:00:00", + "2022-12-30T10:00:00", + "2022-12-30T12:00:00", + "2022-12-30T14:00:00", + "2022-12-30T16:00:00", + "2022-12-30T18:00:00", + "2022-12-30T20:00:00", + "2022-12-30T22:00:00", + "2022-12-31T00:00:00", + "2022-12-31T02:00:00", + "2022-12-31T04:00:00", + "2022-12-31T06:00:00", + "2022-12-31T08:00:00", + "2022-12-31T10:00:00", + "2022-12-31T12:00:00", + "2022-12-31T14:00:00", + "2022-12-31T16:00:00", + "2022-12-31T18:00:00", + "2022-12-31T20:00:00", + "2022-12-31T22:00:00", + "2023-01-01T00:00:00", + "2023-01-01T02:00:00", + "2023-01-01T04:00:00", + "2023-01-01T06:00:00", + "2023-01-01T08:00:00", + "2023-01-01T10:00:00", + "2023-01-01T12:00:00", + "2023-01-01T14:00:00", + "2023-01-01T16:00:00", + "2023-01-01T18:00:00", + "2023-01-01T20:00:00", + "2023-01-01T22:00:00", + "2023-01-02T00:00:00", + "2023-01-02T02:00:00", + "2023-01-02T04:00:00", + "2023-01-02T06:00:00", + "2023-01-02T08:00:00", + "2023-01-02T10:00:00", + "2023-01-02T12:00:00", + "2023-01-02T14:00:00", + "2023-01-02T16:00:00", + "2023-01-02T18:00:00", + "2023-01-02T20:00:00", + "2023-01-02T22:00:00", + "2023-01-03T00:00:00", + "2023-01-03T02:00:00", + "2023-01-03T04:00:00", + "2023-01-03T06:00:00", + "2023-01-03T08:00:00", + "2023-01-03T10:00:00", + "2023-01-03T12:00:00", + "2023-01-03T14:00:00", + "2023-01-03T16:00:00", + "2023-01-03T18:00:00", + "2023-01-03T20:00:00", + "2023-01-03T22:00:00", + "2023-01-04T00:00:00", + "2023-01-04T02:00:00", + "2023-01-04T04:00:00", + "2023-01-04T06:00:00", + "2023-01-04T08:00:00", + "2023-01-04T10:00:00", + "2023-01-04T12:00:00", + "2023-01-04T14:00:00", + "2023-01-04T16:00:00", + "2023-01-04T18:00:00", + "2023-01-04T20:00:00", + "2023-01-04T22:00:00", + "2023-01-05T00:00:00", + "2023-01-05T02:00:00", + "2023-01-05T04:00:00", + "2023-01-05T06:00:00", + "2023-01-05T08:00:00", + "2023-01-05T10:00:00", + "2023-01-05T12:00:00", + "2023-01-05T14:00:00", + "2023-01-05T16:00:00", + "2023-01-05T18:00:00", + "2023-01-05T20:00:00", + "2023-01-05T22:00:00", + "2023-01-06T00:00:00", + "2023-01-06T02:00:00", + "2023-01-06T04:00:00", + "2023-01-06T06:00:00", + "2023-01-06T08:00:00", + "2023-01-06T10:00:00", + "2023-01-06T12:00:00", + "2023-01-06T14:00:00", + "2023-01-06T16:00:00", + "2023-01-06T18:00:00", + "2023-01-06T20:00:00", + "2023-01-06T22:00:00", + "2023-01-07T00:00:00", + "2023-01-07T02:00:00", + "2023-01-07T04:00:00", + "2023-01-07T06:00:00", + "2023-01-07T08:00:00", + "2023-01-07T10:00:00", + "2023-01-07T12:00:00", + "2023-01-07T14:00:00", + "2023-01-07T16:00:00", + "2023-01-07T18:00:00", + "2023-01-07T20:00:00", + "2023-01-07T22:00:00", + "2023-01-08T00:00:00", + "2023-01-08T02:00:00", + "2023-01-08T04:00:00", + "2023-01-08T06:00:00", + "2023-01-08T08:00:00", + "2023-01-08T10:00:00", + "2023-01-08T12:00:00", + "2023-01-08T14:00:00", + "2023-01-08T16:00:00", + "2023-01-08T18:00:00", + "2023-01-08T20:00:00", + "2023-01-08T22:00:00", + "2023-01-09T00:00:00", + "2023-01-09T02:00:00", + "2023-01-09T04:00:00", + "2023-01-09T06:00:00", + "2023-01-09T08:00:00", + "2023-01-09T10:00:00", + "2023-01-09T12:00:00", + "2023-01-09T14:00:00", + "2023-01-09T16:00:00", + "2023-01-09T18:00:00", + "2023-01-09T20:00:00", + "2023-01-09T22:00:00", + "2023-01-10T00:00:00", + "2023-01-10T02:00:00", + "2023-01-10T04:00:00", + "2023-01-10T06:00:00", + "2023-01-10T08:00:00", + "2023-01-10T10:00:00", + "2023-01-10T12:00:00", + "2023-01-10T14:00:00", + "2023-01-10T16:00:00", + "2023-01-10T18:00:00", + "2023-01-10T20:00:00", + "2023-01-10T22:00:00", + "2023-01-11T00:00:00", + "2023-01-11T02:00:00", + "2023-01-11T04:00:00", + "2023-01-11T06:00:00", + "2023-01-11T08:00:00", + "2023-01-11T10:00:00", + "2023-01-11T12:00:00", + "2023-01-11T14:00:00", + "2023-01-11T16:00:00", + "2023-01-11T18:00:00", + "2023-01-11T20:00:00", + "2023-01-11T22:00:00", + "2023-01-12T00:00:00", + "2023-01-12T02:00:00", + "2023-01-12T04:00:00", + "2023-01-12T06:00:00", + "2023-01-12T08:00:00", + "2023-01-12T10:00:00", + "2023-01-12T12:00:00", + "2023-01-12T14:00:00", + "2023-01-12T16:00:00", + "2023-01-12T18:00:00", + "2023-01-12T20:00:00", + "2023-01-12T22:00:00", + "2023-01-13T00:00:00", + "2023-01-13T02:00:00", + "2023-01-13T04:00:00", + "2023-01-13T06:00:00", + "2023-01-13T08:00:00", + "2023-01-13T10:00:00", + "2023-01-13T12:00:00", + "2023-01-13T14:00:00", + "2023-01-13T16:00:00", + "2023-01-13T18:00:00", + "2023-01-13T20:00:00", + "2023-01-13T22:00:00", + "2023-01-14T00:00:00", + "2023-01-14T02:00:00", + "2023-01-14T04:00:00", + "2023-01-14T06:00:00", + "2023-01-14T08:00:00", + "2023-01-14T10:00:00", + "2023-01-14T12:00:00", + "2023-01-14T14:00:00", + "2023-01-14T16:00:00", + "2023-01-14T18:00:00", + "2023-01-14T20:00:00", + "2023-01-14T22:00:00", + "2023-01-15T00:00:00", + "2023-01-15T02:00:00", + "2023-01-15T04:00:00", + "2023-01-15T06:00:00", + "2023-01-15T08:00:00", + "2023-01-15T10:00:00", + "2023-01-15T12:00:00", + "2023-01-15T14:00:00", + "2023-01-15T16:00:00", + "2023-01-15T18:00:00", + "2023-01-15T20:00:00", + "2023-01-15T22:00:00", + "2023-01-16T00:00:00", + "2023-01-16T02:00:00", + "2023-01-16T04:00:00", + "2023-01-16T06:00:00", + "2023-01-16T08:00:00", + "2023-01-16T10:00:00", + "2023-01-16T12:00:00", + "2023-01-16T14:00:00", + "2023-01-16T16:00:00", + "2023-01-16T18:00:00", + "2023-01-16T20:00:00", + "2023-01-16T22:00:00", + "2023-01-17T00:00:00", + "2023-01-17T02:00:00", + "2023-01-17T04:00:00", + "2023-01-17T06:00:00", + "2023-01-17T08:00:00", + "2023-01-17T10:00:00", + "2023-01-17T12:00:00", + "2023-01-17T14:00:00", + "2023-01-17T16:00:00", + "2023-01-17T18:00:00", + "2023-01-17T20:00:00", + "2023-01-17T22:00:00", + "2023-01-18T00:00:00", + "2023-01-18T02:00:00", + "2023-01-18T04:00:00", + "2023-01-18T06:00:00", + "2023-01-18T08:00:00", + "2023-01-18T10:00:00", + "2023-01-18T12:00:00", + "2023-01-18T14:00:00", + "2023-01-18T16:00:00", + "2023-01-18T18:00:00", + "2023-01-18T20:00:00", + "2023-01-18T22:00:00", + "2023-01-19T00:00:00", + "2023-01-19T02:00:00", + "2023-01-19T04:00:00", + "2023-01-19T06:00:00", + "2023-01-19T08:00:00", + "2023-01-19T10:00:00", + "2023-01-19T12:00:00", + "2023-01-19T14:00:00", + "2023-01-19T16:00:00", + "2023-01-19T18:00:00", + "2023-01-19T20:00:00", + "2023-01-19T22:00:00", + "2023-01-20T00:00:00", + "2023-01-20T02:00:00", + "2023-01-20T04:00:00", + "2023-01-20T06:00:00", + "2023-01-20T08:00:00", + "2023-01-20T10:00:00", + "2023-01-20T12:00:00", + "2023-01-20T14:00:00", + "2023-01-20T16:00:00", + "2023-01-20T18:00:00", + "2023-01-20T20:00:00", + "2023-01-20T22:00:00", + "2023-01-21T00:00:00", + "2023-01-21T02:00:00", + "2023-01-21T04:00:00", + "2023-01-21T06:00:00", + "2023-01-21T08:00:00", + "2023-01-21T10:00:00", + "2023-01-21T12:00:00", + "2023-01-21T14:00:00", + "2023-01-21T16:00:00", + "2023-01-21T18:00:00", + "2023-01-21T20:00:00", + "2023-01-21T22:00:00", + "2023-01-22T00:00:00", + "2023-01-22T02:00:00", + "2023-01-22T04:00:00", + "2023-01-22T06:00:00", + "2023-01-22T08:00:00", + "2023-01-22T10:00:00", + "2023-01-22T12:00:00", + "2023-01-22T14:00:00", + "2023-01-22T16:00:00", + "2023-01-22T18:00:00", + "2023-01-22T20:00:00", + "2023-01-22T22:00:00", + "2023-01-23T00:00:00", + "2023-01-23T02:00:00", + "2023-01-23T04:00:00", + "2023-01-23T06:00:00", + "2023-01-23T08:00:00", + "2023-01-23T10:00:00", + "2023-01-23T12:00:00", + "2023-01-23T14:00:00", + "2023-01-23T16:00:00", + "2023-01-23T18:00:00", + "2023-01-23T20:00:00", + "2023-01-23T22:00:00", + "2023-01-24T00:00:00", + "2023-01-24T02:00:00", + "2023-01-24T04:00:00", + "2023-01-24T06:00:00", + "2023-01-24T08:00:00", + "2023-01-24T10:00:00", + "2023-01-24T12:00:00", + "2023-01-24T14:00:00", + "2023-01-24T16:00:00", + "2023-01-24T18:00:00", + "2023-01-24T20:00:00", + "2023-01-24T22:00:00", + "2023-01-25T00:00:00", + "2023-01-25T02:00:00", + "2023-01-25T04:00:00", + "2023-01-25T06:00:00", + "2023-01-25T08:00:00", + "2023-01-25T10:00:00", + "2023-01-25T12:00:00", + "2023-01-25T14:00:00", + "2023-01-25T16:00:00", + "2023-01-25T18:00:00", + "2023-01-25T20:00:00", + "2023-01-25T22:00:00", + "2023-01-26T00:00:00", + "2023-01-26T02:00:00", + "2023-01-26T04:00:00", + "2023-01-26T06:00:00", + "2023-01-26T08:00:00", + "2023-01-26T10:00:00", + "2023-01-26T12:00:00", + "2023-01-26T14:00:00", + "2023-01-26T16:00:00", + "2023-01-26T18:00:00", + "2023-01-26T20:00:00", + "2023-01-26T22:00:00", + "2023-01-27T00:00:00", + "2023-01-27T02:00:00", + "2023-01-27T04:00:00", + "2023-01-27T06:00:00", + "2023-01-27T08:00:00", + "2023-01-27T10:00:00", + "2023-01-27T12:00:00", + "2023-01-27T14:00:00", + "2023-01-27T16:00:00", + "2023-01-27T18:00:00", + "2023-01-27T20:00:00", + "2023-01-27T22:00:00", + "2023-01-28T00:00:00", + "2023-01-28T02:00:00", + "2023-01-28T04:00:00", + "2023-01-28T06:00:00", + "2023-01-28T08:00:00", + "2023-01-28T10:00:00", + "2023-01-28T12:00:00", + "2023-01-28T14:00:00", + "2023-01-28T16:00:00", + "2023-01-28T18:00:00", + "2023-01-28T20:00:00", + "2023-01-28T22:00:00", + "2023-01-29T00:00:00", + "2023-01-29T02:00:00", + "2023-01-29T04:00:00", + "2023-01-29T06:00:00", + "2023-01-29T08:00:00", + "2023-01-29T10:00:00", + "2023-01-29T12:00:00", + "2023-01-29T14:00:00", + "2023-01-29T16:00:00", + "2023-01-29T18:00:00", + "2023-01-29T20:00:00", + "2023-01-29T22:00:00", + "2023-01-30T00:00:00", + "2023-01-30T02:00:00", + "2023-01-30T04:00:00", + "2023-01-30T06:00:00", + "2023-01-30T08:00:00", + "2023-01-30T10:00:00", + "2023-01-30T12:00:00", + "2023-01-30T14:00:00", + "2023-01-30T16:00:00", + "2023-01-30T18:00:00", + "2023-01-30T20:00:00", + "2023-01-30T22:00:00", + "2023-01-31T00:00:00", + "2023-01-31T02:00:00", + "2023-01-31T04:00:00", + "2023-01-31T06:00:00", + "2023-01-31T08:00:00", + "2023-01-31T10:00:00", + "2023-01-31T12:00:00", + "2023-01-31T14:00:00", + "2023-01-31T16:00:00", + "2023-01-31T18:00:00", + "2023-01-31T20:00:00", + "2023-01-31T22:00:00", + "2023-02-01T00:00:00", + "2023-02-01T02:00:00", + "2023-02-01T04:00:00", + "2023-02-01T06:00:00", + "2023-02-01T08:00:00", + "2023-02-01T10:00:00", + "2023-02-01T12:00:00", + "2023-02-01T14:00:00", + "2023-02-01T16:00:00", + "2023-02-01T18:00:00", + "2023-02-01T20:00:00", + "2023-02-01T22:00:00", + "2023-02-02T00:00:00", + "2023-02-02T02:00:00", + "2023-02-02T04:00:00", + "2023-02-02T06:00:00", + "2023-02-02T08:00:00", + "2023-02-02T10:00:00", + "2023-02-02T12:00:00", + "2023-02-02T14:00:00", + "2023-02-02T16:00:00", + "2023-02-02T18:00:00", + "2023-02-02T20:00:00", + "2023-02-02T22:00:00", + "2023-02-03T00:00:00", + "2023-02-03T02:00:00", + "2023-02-03T04:00:00", + "2023-02-03T06:00:00", + "2023-02-03T08:00:00", + "2023-02-03T10:00:00", + "2023-02-03T12:00:00", + "2023-02-03T14:00:00", + "2023-02-03T16:00:00", + "2023-02-03T18:00:00", + "2023-02-03T20:00:00", + "2023-02-03T22:00:00", + "2023-02-04T00:00:00", + "2023-02-04T02:00:00", + "2023-02-04T04:00:00", + "2023-02-04T06:00:00", + "2023-02-04T08:00:00", + "2023-02-04T10:00:00", + "2023-02-04T12:00:00", + "2023-02-04T14:00:00", + "2023-02-04T16:00:00", + "2023-02-04T18:00:00", + "2023-02-04T20:00:00", + "2023-02-04T22:00:00", + "2023-02-05T00:00:00", + "2023-02-05T02:00:00", + "2023-02-05T04:00:00", + "2023-02-05T06:00:00", + "2023-02-05T08:00:00", + "2023-02-05T10:00:00", + "2023-02-05T12:00:00", + "2023-02-05T14:00:00", + "2023-02-05T16:00:00", + "2023-02-05T18:00:00", + "2023-02-05T20:00:00", + "2023-02-05T22:00:00", + "2023-02-06T00:00:00", + "2023-02-06T02:00:00", + "2023-02-06T04:00:00", + "2023-02-06T06:00:00", + "2023-02-06T08:00:00", + "2023-02-06T10:00:00", + "2023-02-06T12:00:00", + "2023-02-06T14:00:00", + "2023-02-06T16:00:00", + "2023-02-06T18:00:00", + "2023-02-06T20:00:00", + "2023-02-06T22:00:00", + "2023-02-07T00:00:00", + "2023-02-07T02:00:00", + "2023-02-07T04:00:00", + "2023-02-07T06:00:00", + "2023-02-07T08:00:00", + "2023-02-07T10:00:00", + "2023-02-07T12:00:00", + "2023-02-07T14:00:00", + "2023-02-07T16:00:00", + "2023-02-07T18:00:00", + "2023-02-07T20:00:00", + "2023-02-07T22:00:00", + "2023-02-08T00:00:00", + "2023-02-08T02:00:00", + "2023-02-08T04:00:00", + "2023-02-08T06:00:00", + "2023-02-08T08:00:00", + "2023-02-08T10:00:00", + "2023-02-08T12:00:00", + "2023-02-08T14:00:00", + "2023-02-08T16:00:00", + "2023-02-08T18:00:00", + "2023-02-08T20:00:00", + "2023-02-08T22:00:00", + "2023-02-09T00:00:00", + "2023-02-09T02:00:00", + "2023-02-09T04:00:00", + "2023-02-09T06:00:00", + "2023-02-09T08:00:00", + "2023-02-09T10:00:00", + "2023-02-09T12:00:00", + "2023-02-09T14:00:00", + "2023-02-09T16:00:00", + "2023-02-09T18:00:00", + "2023-02-09T20:00:00", + "2023-02-09T22:00:00", + "2023-02-10T00:00:00", + "2023-02-10T02:00:00", + "2023-02-10T04:00:00", + "2023-02-10T06:00:00", + "2023-02-10T08:00:00", + "2023-02-10T10:00:00", + "2023-02-10T12:00:00", + "2023-02-10T14:00:00", + "2023-02-10T16:00:00", + "2023-02-10T18:00:00", + "2023-02-10T20:00:00", + "2023-02-10T22:00:00", + "2023-02-11T00:00:00", + "2023-02-11T02:00:00", + "2023-02-11T04:00:00", + "2023-02-11T06:00:00", + "2023-02-11T08:00:00", + "2023-02-11T10:00:00", + "2023-02-11T12:00:00", + "2023-02-11T14:00:00", + "2023-02-11T16:00:00", + "2023-02-11T18:00:00", + "2023-02-11T20:00:00", + "2023-02-11T22:00:00", + "2023-02-12T00:00:00", + "2023-02-12T02:00:00", + "2023-02-12T04:00:00", + "2023-02-12T06:00:00", + "2023-02-12T08:00:00", + "2023-02-12T10:00:00", + "2023-02-12T12:00:00", + "2023-02-12T14:00:00", + "2023-02-12T16:00:00", + "2023-02-12T18:00:00", + "2023-02-12T20:00:00", + "2023-02-12T22:00:00", + "2023-02-13T00:00:00", + "2023-02-13T02:00:00", + "2023-02-13T04:00:00", + "2023-02-13T06:00:00", + "2023-02-13T08:00:00", + "2023-02-13T10:00:00", + "2023-02-13T12:00:00", + "2023-02-13T14:00:00", + "2023-02-13T16:00:00", + "2023-02-13T18:00:00", + "2023-02-13T20:00:00", + "2023-02-13T22:00:00", + "2023-02-14T00:00:00", + "2023-02-14T02:00:00", + "2023-02-14T04:00:00", + "2023-02-14T06:00:00", + "2023-02-14T08:00:00", + "2023-02-14T10:00:00", + "2023-02-14T12:00:00", + "2023-02-14T14:00:00", + "2023-02-14T16:00:00", + "2023-02-14T18:00:00", + "2023-02-14T20:00:00", + "2023-02-14T22:00:00", + "2023-02-15T00:00:00", + "2023-02-15T02:00:00", + "2023-02-15T04:00:00", + "2023-02-15T06:00:00", + "2023-02-15T08:00:00", + "2023-02-15T10:00:00", + "2023-02-15T12:00:00", + "2023-02-15T14:00:00", + "2023-02-15T16:00:00", + "2023-02-15T18:00:00", + "2023-02-15T20:00:00", + "2023-02-15T22:00:00", + "2023-02-16T00:00:00", + "2023-02-16T02:00:00", + "2023-02-16T04:00:00", + "2023-02-16T06:00:00", + "2023-02-16T08:00:00", + "2023-02-16T10:00:00", + "2023-02-16T12:00:00", + "2023-02-16T14:00:00", + "2023-02-16T16:00:00", + "2023-02-16T18:00:00", + "2023-02-16T20:00:00", + "2023-02-16T22:00:00", + "2023-02-17T00:00:00", + "2023-02-17T02:00:00", + "2023-02-17T04:00:00", + "2023-02-17T06:00:00", + "2023-02-17T08:00:00", + "2023-02-17T10:00:00", + "2023-02-17T12:00:00", + "2023-02-17T14:00:00", + "2023-02-17T16:00:00", + "2023-02-17T18:00:00", + "2023-02-17T20:00:00", + "2023-02-17T22:00:00", + "2023-02-18T00:00:00", + "2023-02-18T02:00:00", + "2023-02-18T04:00:00", + "2023-02-18T06:00:00", + "2023-02-18T08:00:00", + "2023-02-18T10:00:00", + "2023-02-18T12:00:00", + "2023-02-18T14:00:00", + "2023-02-18T16:00:00", + "2023-02-18T18:00:00", + "2023-02-18T20:00:00", + "2023-02-18T22:00:00", + "2023-02-19T00:00:00", + "2023-02-19T02:00:00", + "2023-02-19T04:00:00", + "2023-02-19T06:00:00", + "2023-02-19T08:00:00", + "2023-02-19T10:00:00", + "2023-02-19T12:00:00", + "2023-02-19T14:00:00", + "2023-02-19T16:00:00", + "2023-02-19T18:00:00", + "2023-02-19T20:00:00", + "2023-02-19T22:00:00", + "2023-02-20T00:00:00", + "2023-02-20T02:00:00", + "2023-02-20T04:00:00", + "2023-02-20T06:00:00", + "2023-02-20T08:00:00", + "2023-02-20T10:00:00", + "2023-02-20T12:00:00", + "2023-02-20T14:00:00", + "2023-02-20T16:00:00", + "2023-02-20T18:00:00", + "2023-02-20T20:00:00", + "2023-02-20T22:00:00", + "2023-02-21T00:00:00", + "2023-02-21T02:00:00", + "2023-02-21T04:00:00", + "2023-02-21T06:00:00", + "2023-02-21T08:00:00", + "2023-02-21T10:00:00", + "2023-02-21T12:00:00", + "2023-02-21T14:00:00", + "2023-02-21T16:00:00", + "2023-02-21T18:00:00", + "2023-02-21T20:00:00", + "2023-02-21T22:00:00", + "2023-02-22T00:00:00", + "2023-02-22T02:00:00", + "2023-02-22T04:00:00", + "2023-02-22T06:00:00", + "2023-02-22T08:00:00", + "2023-02-22T10:00:00", + "2023-02-22T12:00:00", + "2023-02-22T14:00:00", + "2023-02-22T16:00:00", + "2023-02-22T18:00:00", + "2023-02-22T20:00:00", + "2023-02-22T22:00:00", + "2023-02-23T00:00:00", + "2023-02-23T02:00:00", + "2023-02-23T04:00:00", + "2023-02-23T06:00:00", + "2023-02-23T08:00:00", + "2023-02-23T10:00:00", + "2023-02-23T12:00:00", + "2023-02-23T14:00:00", + "2023-02-23T16:00:00", + "2023-02-23T18:00:00", + "2023-02-23T20:00:00", + "2023-02-23T22:00:00", + "2023-02-24T00:00:00", + "2023-02-24T02:00:00", + "2023-02-24T04:00:00", + "2023-02-24T06:00:00", + "2023-02-24T08:00:00", + "2023-02-24T10:00:00", + "2023-02-24T12:00:00", + "2023-02-24T14:00:00", + "2023-02-24T16:00:00", + "2023-02-24T18:00:00", + "2023-02-24T20:00:00", + "2023-02-24T22:00:00", + "2023-02-25T00:00:00", + "2023-02-25T02:00:00", + "2023-02-25T04:00:00", + "2023-02-25T06:00:00", + "2023-02-25T08:00:00", + "2023-02-25T10:00:00", + "2023-02-25T12:00:00", + "2023-02-25T14:00:00", + "2023-02-25T16:00:00", + "2023-02-25T18:00:00", + "2023-02-25T20:00:00", + "2023-02-25T22:00:00", + "2023-02-26T00:00:00", + "2023-02-26T02:00:00", + "2023-02-26T04:00:00", + "2023-02-26T06:00:00", + "2023-02-26T08:00:00", + "2023-02-26T10:00:00", + "2023-02-26T12:00:00", + "2023-02-26T14:00:00", + "2023-02-26T16:00:00", + "2023-02-26T18:00:00", + "2023-02-26T20:00:00", + "2023-02-26T22:00:00", + "2023-02-27T00:00:00", + "2023-02-27T02:00:00", + "2023-02-27T04:00:00", + "2023-02-27T06:00:00", + "2023-02-27T08:00:00", + "2023-02-27T10:00:00", + "2023-02-27T12:00:00", + "2023-02-27T14:00:00", + "2023-02-27T16:00:00", + "2023-02-27T18:00:00", + "2023-02-27T20:00:00", + "2023-02-27T22:00:00", + "2023-02-28T00:00:00", + "2023-02-28T02:00:00", + "2023-02-28T04:00:00", + "2023-02-28T06:00:00", + "2023-02-28T08:00:00", + "2023-02-28T10:00:00", + "2023-02-28T12:00:00", + "2023-02-28T14:00:00", + "2023-02-28T16:00:00", + "2023-02-28T18:00:00", + "2023-02-28T20:00:00", + "2023-02-28T22:00:00", + "2023-03-01T00:00:00", + "2023-03-01T02:00:00", + "2023-03-01T04:00:00", + "2023-03-01T06:00:00", + "2023-03-01T08:00:00", + "2023-03-01T10:00:00", + "2023-03-01T12:00:00", + "2023-03-01T14:00:00", + "2023-03-01T16:00:00", + "2023-03-01T18:00:00", + "2023-03-01T20:00:00", + "2023-03-01T22:00:00", + "2023-03-02T00:00:00", + "2023-03-02T02:00:00", + "2023-03-02T04:00:00", + "2023-03-02T06:00:00", + "2023-03-02T08:00:00", + "2023-03-02T10:00:00", + "2023-03-02T12:00:00", + "2023-03-02T14:00:00", + "2023-03-02T16:00:00", + "2023-03-02T18:00:00", + "2023-03-02T20:00:00", + "2023-03-02T22:00:00", + "2023-03-03T00:00:00", + "2023-03-03T02:00:00", + "2023-03-03T04:00:00", + "2023-03-03T06:00:00", + "2023-03-03T08:00:00", + "2023-03-03T10:00:00", + "2023-03-03T12:00:00", + "2023-03-03T14:00:00", + "2023-03-03T16:00:00", + "2023-03-03T18:00:00", + "2023-03-03T20:00:00", + "2023-03-03T22:00:00", + "2023-03-04T00:00:00", + "2023-03-04T02:00:00", + "2023-03-04T04:00:00", + "2023-03-04T06:00:00", + "2023-03-04T08:00:00", + "2023-03-04T10:00:00", + "2023-03-04T12:00:00", + "2023-03-04T14:00:00", + "2023-03-04T16:00:00", + "2023-03-04T18:00:00", + "2023-03-04T20:00:00", + "2023-03-04T22:00:00", + "2023-03-05T00:00:00", + "2023-03-05T02:00:00", + "2023-03-05T04:00:00", + "2023-03-05T06:00:00", + "2023-03-05T08:00:00", + "2023-03-05T10:00:00", + "2023-03-05T12:00:00", + "2023-03-05T14:00:00", + "2023-03-05T16:00:00", + "2023-03-05T18:00:00", + "2023-03-05T20:00:00", + "2023-03-05T22:00:00", + "2023-03-06T00:00:00", + "2023-03-06T02:00:00", + "2023-03-06T04:00:00", + "2023-03-06T06:00:00", + "2023-03-06T08:00:00", + "2023-03-06T10:00:00", + "2023-03-06T12:00:00", + "2023-03-06T14:00:00", + "2023-03-06T16:00:00", + "2023-03-06T18:00:00", + "2023-03-06T20:00:00", + "2023-03-06T22:00:00", + "2023-03-07T00:00:00", + "2023-03-07T02:00:00", + "2023-03-07T04:00:00", + "2023-03-07T06:00:00", + "2023-03-07T08:00:00", + "2023-03-07T10:00:00", + "2023-03-07T12:00:00", + "2023-03-07T14:00:00", + "2023-03-07T16:00:00", + "2023-03-07T18:00:00", + "2023-03-07T20:00:00", + "2023-03-07T22:00:00", + "2023-03-08T00:00:00", + "2023-03-08T02:00:00", + "2023-03-08T04:00:00", + "2023-03-08T06:00:00", + "2023-03-08T08:00:00", + "2023-03-08T10:00:00", + "2023-03-08T12:00:00", + "2023-03-08T14:00:00", + "2023-03-08T16:00:00", + "2023-03-08T18:00:00", + "2023-03-08T20:00:00", + "2023-03-08T22:00:00", + "2023-03-09T00:00:00", + "2023-03-09T02:00:00", + "2023-03-09T04:00:00", + "2023-03-09T06:00:00", + "2023-03-09T08:00:00", + "2023-03-09T10:00:00", + "2023-03-09T12:00:00", + "2023-03-09T14:00:00", + "2023-03-09T16:00:00", + "2023-03-09T18:00:00", + "2023-03-09T20:00:00", + "2023-03-09T22:00:00", + "2023-03-10T00:00:00", + "2023-03-10T02:00:00", + "2023-03-10T04:00:00", + "2023-03-10T06:00:00", + "2023-03-10T08:00:00", + "2023-03-10T10:00:00", + "2023-03-10T12:00:00", + "2023-03-10T14:00:00", + "2023-03-10T16:00:00", + "2023-03-10T18:00:00", + "2023-03-10T20:00:00", + "2023-03-10T22:00:00", + "2023-03-11T00:00:00", + "2023-03-11T02:00:00", + "2023-03-11T04:00:00", + "2023-03-11T06:00:00", + "2023-03-11T08:00:00", + "2023-03-11T10:00:00", + "2023-03-11T12:00:00", + "2023-03-11T14:00:00", + "2023-03-11T16:00:00", + "2023-03-11T18:00:00", + "2023-03-11T20:00:00", + "2023-03-11T22:00:00", + "2023-03-12T00:00:00", + "2023-03-12T02:00:00", + "2023-03-12T04:00:00", + "2023-03-12T06:00:00", + "2023-03-12T08:00:00", + "2023-03-12T10:00:00", + "2023-03-12T12:00:00", + "2023-03-12T14:00:00", + "2023-03-12T16:00:00", + "2023-03-12T18:00:00", + "2023-03-12T20:00:00", + "2023-03-12T22:00:00", + "2023-03-13T00:00:00", + "2023-03-13T02:00:00", + "2023-03-13T04:00:00", + "2023-03-13T06:00:00", + "2023-03-13T08:00:00", + "2023-03-13T10:00:00", + "2023-03-13T12:00:00", + "2023-03-13T14:00:00", + "2023-03-13T16:00:00", + "2023-03-13T18:00:00", + "2023-03-13T20:00:00", + "2023-03-13T22:00:00", + "2023-03-14T00:00:00", + "2023-03-14T02:00:00", + "2023-03-14T04:00:00", + "2023-03-14T06:00:00", + "2023-03-14T08:00:00", + "2023-03-14T10:00:00", + "2023-03-14T12:00:00", + "2023-03-14T14:00:00", + "2023-03-14T16:00:00", + "2023-03-14T18:00:00", + "2023-03-14T20:00:00", + "2023-03-14T22:00:00", + "2023-03-15T00:00:00", + "2023-03-15T02:00:00", + "2023-03-15T04:00:00", + "2023-03-15T06:00:00", + "2023-03-15T08:00:00", + "2023-03-15T10:00:00", + "2023-03-15T12:00:00", + "2023-03-15T14:00:00", + "2023-03-15T16:00:00", + "2023-03-15T18:00:00", + "2023-03-15T20:00:00", + "2023-03-15T22:00:00", + "2023-03-16T00:00:00", + "2023-03-16T02:00:00", + "2023-03-16T04:00:00", + "2023-03-16T06:00:00", + "2023-03-16T08:00:00", + "2023-03-16T10:00:00", + "2023-03-16T12:00:00", + "2023-03-16T14:00:00", + "2023-03-16T16:00:00", + "2023-03-16T18:00:00", + "2023-03-16T20:00:00", + "2023-03-16T22:00:00", + "2023-03-17T00:00:00", + "2023-03-17T02:00:00", + "2023-03-17T04:00:00", + "2023-03-17T06:00:00", + "2023-03-17T08:00:00", + "2023-03-17T10:00:00", + "2023-03-17T12:00:00", + "2023-03-17T14:00:00", + "2023-03-17T16:00:00", + "2023-03-17T18:00:00", + "2023-03-17T20:00:00", + "2023-03-17T22:00:00", + "2023-03-18T00:00:00", + "2023-03-18T02:00:00", + "2023-03-18T04:00:00", + "2023-03-18T06:00:00", + "2023-03-18T08:00:00", + "2023-03-18T10:00:00", + "2023-03-18T12:00:00", + "2023-03-18T14:00:00", + "2023-03-18T16:00:00", + "2023-03-18T18:00:00", + "2023-03-18T20:00:00", + "2023-03-18T22:00:00", + "2023-03-19T00:00:00", + "2023-03-19T02:00:00", + "2023-03-19T04:00:00", + "2023-03-19T06:00:00", + "2023-03-19T08:00:00", + "2023-03-19T10:00:00", + "2023-03-19T12:00:00", + "2023-03-19T14:00:00", + "2023-03-19T16:00:00", + "2023-03-19T18:00:00", + "2023-03-19T20:00:00", + "2023-03-19T22:00:00", + "2023-03-20T00:00:00", + "2023-03-20T02:00:00", + "2023-03-20T04:00:00", + "2023-03-20T06:00:00", + "2023-03-20T08:00:00", + "2023-03-20T10:00:00", + "2023-03-20T12:00:00", + "2023-03-20T14:00:00", + "2023-03-20T16:00:00", + "2023-03-20T18:00:00", + "2023-03-20T20:00:00", + "2023-03-20T22:00:00", + "2023-03-21T00:00:00", + "2023-03-21T02:00:00", + "2023-03-21T04:00:00", + "2023-03-21T06:00:00", + "2023-03-21T08:00:00", + "2023-03-21T10:00:00", + "2023-03-21T12:00:00", + "2023-03-21T14:00:00", + "2023-03-21T16:00:00", + "2023-03-21T18:00:00", + "2023-03-21T20:00:00", + "2023-03-21T22:00:00", + "2023-03-22T00:00:00", + "2023-03-22T02:00:00", + "2023-03-22T04:00:00", + "2023-03-22T06:00:00", + "2023-03-22T08:00:00", + "2023-03-22T10:00:00", + "2023-03-22T12:00:00", + "2023-03-22T14:00:00", + "2023-03-22T16:00:00", + "2023-03-22T18:00:00", + "2023-03-22T20:00:00", + "2023-03-22T22:00:00", + "2023-03-23T00:00:00", + "2023-03-23T02:00:00", + "2023-03-23T04:00:00", + "2023-03-23T06:00:00", + "2023-03-23T08:00:00", + "2023-03-23T10:00:00", + "2023-03-23T12:00:00", + "2023-03-23T14:00:00", + "2023-03-23T16:00:00", + "2023-03-23T18:00:00", + "2023-03-23T20:00:00", + "2023-03-23T22:00:00", + "2023-03-24T00:00:00", + "2023-03-24T02:00:00", + "2023-03-24T04:00:00", + "2023-03-24T06:00:00", + "2023-03-24T08:00:00", + "2023-03-24T10:00:00", + "2023-03-24T12:00:00", + "2023-03-24T14:00:00", + "2023-03-24T16:00:00", + "2023-03-24T18:00:00", + "2023-03-24T20:00:00", + "2023-03-24T22:00:00", + "2023-03-25T00:00:00", + "2023-03-25T02:00:00", + "2023-03-25T04:00:00", + "2023-03-25T06:00:00", + "2023-03-25T08:00:00", + "2023-03-25T10:00:00", + "2023-03-25T12:00:00", + "2023-03-25T14:00:00", + "2023-03-25T16:00:00", + "2023-03-25T18:00:00", + "2023-03-25T20:00:00", + "2023-03-25T22:00:00", + "2023-03-26T00:00:00", + "2023-03-26T02:00:00", + "2023-03-26T04:00:00", + "2023-03-26T06:00:00", + "2023-03-26T08:00:00", + "2023-03-26T10:00:00", + "2023-03-26T12:00:00", + "2023-03-26T14:00:00", + "2023-03-26T16:00:00", + "2023-03-26T18:00:00", + "2023-03-26T20:00:00", + "2023-03-26T22:00:00", + "2023-03-27T00:00:00", + "2023-03-27T02:00:00", + "2023-03-27T04:00:00", + "2023-03-27T06:00:00", + "2023-03-27T08:00:00", + "2023-03-27T10:00:00", + "2023-03-27T12:00:00", + "2023-03-27T14:00:00", + "2023-03-27T16:00:00", + "2023-03-27T18:00:00", + "2023-03-27T20:00:00", + "2023-03-27T22:00:00", + "2023-03-28T00:00:00", + "2023-03-28T02:00:00", + "2023-03-28T04:00:00", + "2023-03-28T06:00:00", + "2023-03-28T08:00:00", + "2023-03-28T10:00:00", + "2023-03-28T12:00:00", + "2023-03-28T14:00:00", + "2023-03-28T16:00:00", + "2023-03-28T18:00:00", + "2023-03-28T20:00:00", + "2023-03-28T22:00:00", + "2023-03-29T00:00:00", + "2023-03-29T02:00:00", + "2023-03-29T04:00:00", + "2023-03-29T06:00:00", + "2023-03-29T08:00:00", + "2023-03-29T10:00:00", + "2023-03-29T12:00:00", + "2023-03-29T14:00:00", + "2023-03-29T16:00:00", + "2023-03-29T18:00:00", + "2023-03-29T20:00:00", + "2023-03-29T22:00:00", + "2023-03-30T00:00:00", + "2023-03-30T02:00:00", + "2023-03-30T04:00:00", + "2023-03-30T06:00:00", + "2023-03-30T08:00:00", + "2023-03-30T10:00:00", + "2023-03-30T12:00:00", + "2023-03-30T14:00:00", + "2023-03-30T16:00:00", + "2023-03-30T18:00:00", + "2023-03-30T20:00:00", + "2023-03-30T22:00:00", + "2023-03-31T00:00:00", + "2023-03-31T02:00:00", + "2023-03-31T04:00:00", + "2023-03-31T06:00:00", + "2023-03-31T08:00:00", + "2023-03-31T10:00:00", + "2023-03-31T12:00:00", + "2023-03-31T14:00:00", + "2023-03-31T16:00:00", + "2023-03-31T18:00:00", + "2023-03-31T20:00:00", + "2023-03-31T22:00:00", + "2023-04-01T00:00:00", + "2023-04-01T02:00:00", + "2023-04-01T04:00:00", + "2023-04-01T06:00:00", + "2023-04-01T08:00:00", + "2023-04-01T10:00:00", + "2023-04-01T12:00:00", + "2023-04-01T14:00:00", + "2023-04-01T16:00:00", + "2023-04-01T18:00:00", + "2023-04-01T20:00:00", + "2023-04-01T22:00:00", + "2023-04-02T00:00:00", + "2023-04-02T02:00:00", + "2023-04-02T04:00:00", + "2023-04-02T06:00:00", + "2023-04-02T08:00:00", + "2023-04-02T10:00:00", + "2023-04-02T12:00:00", + "2023-04-02T14:00:00", + "2023-04-02T16:00:00", + "2023-04-02T18:00:00", + "2023-04-02T20:00:00", + "2023-04-02T22:00:00", + "2023-04-03T00:00:00", + "2023-04-03T02:00:00", + "2023-04-03T04:00:00", + "2023-04-03T06:00:00", + "2023-04-03T08:00:00", + "2023-04-03T10:00:00", + "2023-04-03T12:00:00", + "2023-04-03T14:00:00", + "2023-04-03T16:00:00", + "2023-04-03T18:00:00", + "2023-04-03T20:00:00", + "2023-04-03T22:00:00", + "2023-04-04T00:00:00", + "2023-04-04T02:00:00", + "2023-04-04T04:00:00", + "2023-04-04T06:00:00", + "2023-04-04T08:00:00", + "2023-04-04T10:00:00", + "2023-04-04T12:00:00", + "2023-04-04T14:00:00", + "2023-04-04T16:00:00", + "2023-04-04T18:00:00", + "2023-04-04T20:00:00", + "2023-04-04T22:00:00", + "2023-04-05T00:00:00", + "2023-04-05T02:00:00", + "2023-04-05T04:00:00", + "2023-04-05T06:00:00", + "2023-04-05T08:00:00", + "2023-04-05T10:00:00", + "2023-04-05T12:00:00", + "2023-04-05T14:00:00", + "2023-04-05T16:00:00", + "2023-04-05T18:00:00", + "2023-04-05T20:00:00", + "2023-04-05T22:00:00", + "2023-04-06T00:00:00", + "2023-04-06T02:00:00", + "2023-04-06T04:00:00", + "2023-04-06T06:00:00", + "2023-04-06T08:00:00", + "2023-04-06T10:00:00", + "2023-04-06T12:00:00", + "2023-04-06T14:00:00", + "2023-04-06T16:00:00", + "2023-04-06T18:00:00", + "2023-04-06T20:00:00", + "2023-04-06T22:00:00", + "2023-04-07T00:00:00", + "2023-04-07T02:00:00", + "2023-04-07T04:00:00", + "2023-04-07T06:00:00", + "2023-04-07T08:00:00", + "2023-04-07T10:00:00", + "2023-04-07T12:00:00", + "2023-04-07T14:00:00", + "2023-04-07T16:00:00", + "2023-04-07T18:00:00", + "2023-04-07T20:00:00", + "2023-04-07T22:00:00", + "2023-04-08T00:00:00", + "2023-04-08T02:00:00", + "2023-04-08T04:00:00", + "2023-04-08T06:00:00", + "2023-04-08T08:00:00", + "2023-04-08T10:00:00", + "2023-04-08T12:00:00", + "2023-04-08T14:00:00", + "2023-04-08T16:00:00", + "2023-04-08T18:00:00", + "2023-04-08T20:00:00", + "2023-04-08T22:00:00", + "2023-04-09T00:00:00", + "2023-04-09T02:00:00", + "2023-04-09T04:00:00", + "2023-04-09T06:00:00", + "2023-04-09T08:00:00", + "2023-04-09T10:00:00", + "2023-04-09T12:00:00", + "2023-04-09T14:00:00", + "2023-04-09T16:00:00", + "2023-04-09T18:00:00", + "2023-04-09T20:00:00", + "2023-04-09T22:00:00", + "2023-04-10T00:00:00", + "2023-04-10T02:00:00", + "2023-04-10T04:00:00", + "2023-04-10T06:00:00", + "2023-04-10T08:00:00", + "2023-04-10T10:00:00", + "2023-04-10T12:00:00", + "2023-04-10T14:00:00", + "2023-04-10T16:00:00", + "2023-04-10T18:00:00", + "2023-04-10T20:00:00", + "2023-04-10T22:00:00", + "2023-04-11T00:00:00", + "2023-04-11T02:00:00", + "2023-04-11T04:00:00", + "2023-04-11T06:00:00", + "2023-04-11T08:00:00", + "2023-04-11T10:00:00", + "2023-04-11T12:00:00", + "2023-04-11T14:00:00", + "2023-04-11T16:00:00", + "2023-04-11T18:00:00", + "2023-04-11T20:00:00", + "2023-04-11T22:00:00", + "2023-04-12T00:00:00", + "2023-04-12T02:00:00", + "2023-04-12T04:00:00", + "2023-04-12T06:00:00", + "2023-04-12T08:00:00", + "2023-04-12T10:00:00", + "2023-04-12T12:00:00", + "2023-04-12T14:00:00", + "2023-04-12T16:00:00", + "2023-04-12T18:00:00", + "2023-04-12T20:00:00", + "2023-04-12T22:00:00", + "2023-04-13T00:00:00", + "2023-04-13T02:00:00", + "2023-04-13T04:00:00", + "2023-04-13T06:00:00", + "2023-04-13T08:00:00", + "2023-04-13T10:00:00", + "2023-04-13T12:00:00", + "2023-04-13T14:00:00", + "2023-04-13T16:00:00", + "2023-04-13T18:00:00", + "2023-04-13T20:00:00", + "2023-04-13T22:00:00", + "2023-04-14T00:00:00", + "2023-04-14T02:00:00", + "2023-04-14T04:00:00", + "2023-04-14T06:00:00", + "2023-04-14T08:00:00", + "2023-04-14T10:00:00", + "2023-04-14T12:00:00", + "2023-04-14T14:00:00", + "2023-04-14T16:00:00", + "2023-04-14T18:00:00", + "2023-04-14T20:00:00", + "2023-04-14T22:00:00", + "2023-04-15T00:00:00", + "2023-04-15T02:00:00", + "2023-04-15T04:00:00", + "2023-04-15T06:00:00", + "2023-04-15T08:00:00", + "2023-04-15T10:00:00", + "2023-04-15T12:00:00", + "2023-04-15T14:00:00", + "2023-04-15T16:00:00", + "2023-04-15T18:00:00", + "2023-04-15T20:00:00", + "2023-04-15T22:00:00", + "2023-04-16T00:00:00", + "2023-04-16T04:00:00", + "2023-04-16T06:00:00", + "2023-04-16T08:00:00", + "2023-04-16T10:00:00", + "2023-04-16T12:00:00", + "2023-04-16T14:00:00", + "2023-04-16T16:00:00", + "2023-04-16T18:00:00", + "2023-04-16T20:00:00", + "2023-04-16T22:00:00", + "2023-04-17T00:00:00", + "2023-04-17T02:00:00", + "2023-04-17T04:00:00", + "2023-04-17T06:00:00", + "2023-04-17T08:00:00", + "2023-04-17T10:00:00", + "2023-04-17T12:00:00", + "2023-04-17T14:00:00", + "2023-04-17T16:00:00", + "2023-04-17T18:00:00", + "2023-04-17T20:00:00", + "2023-04-17T22:00:00", + "2023-04-18T00:00:00", + "2023-04-18T02:00:00", + "2023-04-18T04:00:00", + "2023-04-18T06:00:00", + "2023-04-18T08:00:00", + "2023-04-18T10:00:00", + "2023-04-18T12:00:00", + "2023-04-18T14:00:00", + "2023-04-18T16:00:00", + "2023-04-18T18:00:00", + "2023-04-18T20:00:00", + "2023-04-18T22:00:00", + "2023-04-19T00:00:00", + "2023-04-19T02:00:00", + "2023-04-19T04:00:00", + "2023-04-19T06:00:00", + "2023-04-19T08:00:00", + "2023-04-19T10:00:00", + "2023-04-19T12:00:00", + "2023-04-19T14:00:00", + "2023-04-19T16:00:00", + "2023-04-19T18:00:00", + "2023-04-19T20:00:00", + "2023-04-19T22:00:00", + "2023-04-20T00:00:00", + "2023-04-20T02:00:00", + "2023-04-20T04:00:00", + "2023-04-20T06:00:00", + "2023-04-20T08:00:00", + "2023-04-20T10:00:00", + "2023-04-20T12:00:00", + "2023-04-20T14:00:00", + "2023-04-20T16:00:00", + "2023-04-20T18:00:00", + "2023-04-20T20:00:00", + "2023-04-20T22:00:00", + "2023-04-21T00:00:00", + "2023-04-21T02:00:00", + "2023-04-21T04:00:00", + "2023-04-21T06:00:00", + "2023-04-21T08:00:00", + "2023-04-21T10:00:00", + "2023-04-21T12:00:00", + "2023-04-21T14:00:00", + "2023-04-21T16:00:00", + "2023-04-21T18:00:00", + "2023-04-21T20:00:00", + "2023-04-21T22:00:00", + "2023-04-22T00:00:00", + "2023-04-22T02:00:00", + "2023-04-22T04:00:00", + "2023-04-22T06:00:00", + "2023-04-22T08:00:00", + "2023-04-22T10:00:00", + "2023-04-22T12:00:00", + "2023-04-22T14:00:00", + "2023-04-22T16:00:00", + "2023-04-22T18:00:00", + "2023-04-22T20:00:00", + "2023-04-22T22:00:00", + "2023-04-23T00:00:00", + "2023-04-23T02:00:00", + "2023-04-23T04:00:00", + "2023-04-23T06:00:00", + "2023-04-23T08:00:00", + "2023-04-23T10:00:00", + "2023-04-23T12:00:00", + "2023-04-23T14:00:00", + "2023-04-23T16:00:00", + "2023-04-23T18:00:00", + "2023-04-23T20:00:00", + "2023-04-23T22:00:00", + "2023-04-24T00:00:00", + "2023-04-24T02:00:00", + "2023-04-24T04:00:00", + "2023-04-24T06:00:00", + "2023-04-24T08:00:00", + "2023-04-24T10:00:00", + "2023-04-24T12:00:00", + "2023-04-24T14:00:00", + "2023-04-24T16:00:00", + "2023-04-24T18:00:00", + "2023-04-24T20:00:00", + "2023-04-24T22:00:00", + "2023-04-25T00:00:00", + "2023-04-25T02:00:00", + "2023-04-25T04:00:00", + "2023-04-25T06:00:00", + "2023-04-25T08:00:00", + "2023-04-25T10:00:00", + "2023-04-25T12:00:00", + "2023-04-25T14:00:00", + "2023-04-25T16:00:00", + "2023-04-25T18:00:00", + "2023-04-25T20:00:00", + "2023-04-25T22:00:00", + "2023-04-26T00:00:00", + "2023-04-26T02:00:00", + "2023-04-26T04:00:00", + "2023-04-26T06:00:00", + "2023-04-26T08:00:00", + "2023-04-26T10:00:00", + "2023-04-26T12:00:00", + "2023-04-26T14:00:00", + "2023-04-26T16:00:00", + "2023-04-26T18:00:00", + "2023-04-26T20:00:00", + "2023-04-26T22:00:00", + "2023-04-27T00:00:00", + "2023-04-27T02:00:00", + "2023-04-27T04:00:00", + "2023-04-27T06:00:00", + "2023-04-27T08:00:00", + "2023-04-27T10:00:00", + "2023-04-27T12:00:00", + "2023-04-27T14:00:00", + "2023-04-27T16:00:00", + "2023-04-27T18:00:00", + "2023-04-27T20:00:00", + "2023-04-27T22:00:00", + "2023-04-28T00:00:00", + "2023-04-28T02:00:00", + "2023-04-28T04:00:00", + "2023-04-28T06:00:00", + "2023-04-28T08:00:00", + "2023-04-28T10:00:00", + "2023-04-28T12:00:00", + "2023-04-28T14:00:00", + "2023-04-28T16:00:00", + "2023-04-28T18:00:00", + "2023-04-28T20:00:00", + "2023-04-28T22:00:00", + "2023-04-29T00:00:00", + "2023-04-29T02:00:00", + "2023-04-29T04:00:00", + "2023-04-29T06:00:00", + "2023-04-29T08:00:00", + "2023-04-29T10:00:00", + "2023-04-29T12:00:00", + "2023-04-29T14:00:00", + "2023-04-29T16:00:00", + "2023-04-29T18:00:00", + "2023-04-29T20:00:00", + "2023-04-29T22:00:00", + "2023-04-30T00:00:00", + "2023-04-30T02:00:00", + "2023-04-30T04:00:00", + "2023-04-30T06:00:00", + "2023-04-30T08:00:00", + "2023-04-30T10:00:00", + "2023-04-30T12:00:00", + "2023-04-30T14:00:00", + "2023-04-30T16:00:00", + "2023-04-30T18:00:00", + "2023-04-30T20:00:00", + "2023-04-30T22:00:00", + "2023-05-01T00:00:00", + "2023-05-01T02:00:00", + "2023-05-01T04:00:00", + "2023-05-01T06:00:00", + "2023-05-01T08:00:00", + "2023-05-01T10:00:00", + "2023-05-01T12:00:00", + "2023-05-01T14:00:00", + "2023-05-01T16:00:00", + "2023-05-01T18:00:00", + "2023-05-01T20:00:00", + "2023-05-01T22:00:00", + "2023-05-02T00:00:00", + "2023-05-02T02:00:00", + "2023-05-02T04:00:00", + "2023-05-02T06:00:00", + "2023-05-02T08:00:00", + "2023-05-02T10:00:00", + "2023-05-02T12:00:00", + "2023-05-02T14:00:00", + "2023-05-02T16:00:00", + "2023-05-02T18:00:00", + "2023-05-02T20:00:00", + "2023-05-02T22:00:00", + "2023-05-03T00:00:00", + "2023-05-03T02:00:00", + "2023-05-03T04:00:00", + "2023-05-03T06:00:00", + "2023-05-03T08:00:00", + "2023-05-03T10:00:00", + "2023-05-03T12:00:00", + "2023-05-03T14:00:00", + "2023-05-03T16:00:00", + "2023-05-03T18:00:00", + "2023-05-03T20:00:00", + "2023-05-03T22:00:00", + "2023-05-04T00:00:00", + "2023-05-04T02:00:00", + "2023-05-04T04:00:00", + "2023-05-04T06:00:00", + "2023-05-04T08:00:00", + "2023-05-04T10:00:00", + "2023-05-04T12:00:00", + "2023-05-04T14:00:00", + "2023-05-04T16:00:00", + "2023-05-04T18:00:00", + "2023-05-04T20:00:00", + "2023-05-04T22:00:00", + "2023-05-05T00:00:00", + "2023-05-05T02:00:00", + "2023-05-05T04:00:00", + "2023-05-05T06:00:00", + "2023-05-05T08:00:00", + "2023-05-05T10:00:00", + "2023-05-05T12:00:00", + "2023-05-05T14:00:00", + "2023-05-05T16:00:00", + "2023-05-05T18:00:00", + "2023-05-05T20:00:00", + "2023-05-05T22:00:00", + "2023-05-06T00:00:00", + "2023-05-06T02:00:00", + "2023-05-06T04:00:00", + "2023-05-06T06:00:00", + "2023-05-06T08:00:00", + "2023-05-06T10:00:00", + "2023-05-06T12:00:00", + "2023-05-06T14:00:00", + "2023-05-06T16:00:00", + "2023-05-06T18:00:00", + "2023-05-06T20:00:00", + "2023-05-06T22:00:00", + "2023-05-07T00:00:00", + "2023-05-07T02:00:00", + "2023-05-07T04:00:00", + "2023-05-07T06:00:00", + "2023-05-07T08:00:00", + "2023-05-07T10:00:00", + "2023-05-07T12:00:00", + "2023-05-07T14:00:00", + "2023-05-07T16:00:00", + "2023-05-07T18:00:00", + "2023-05-07T20:00:00", + "2023-05-07T22:00:00", + "2023-05-08T00:00:00", + "2023-05-08T02:00:00", + "2023-05-08T04:00:00", + "2023-05-08T06:00:00", + "2023-05-08T08:00:00", + "2023-05-08T10:00:00", + "2023-05-08T12:00:00", + "2023-05-08T14:00:00", + "2023-05-08T16:00:00", + "2023-05-08T18:00:00", + "2023-05-08T20:00:00", + "2023-05-08T22:00:00", + "2023-05-09T00:00:00", + "2023-05-09T02:00:00", + "2023-05-09T04:00:00", + "2023-05-09T06:00:00", + "2023-05-09T08:00:00", + "2023-05-09T10:00:00", + "2023-05-09T12:00:00", + "2023-05-09T14:00:00", + "2023-05-09T16:00:00", + "2023-05-09T18:00:00", + "2023-05-09T20:00:00", + "2023-05-09T22:00:00", + "2023-05-10T00:00:00", + "2023-05-10T02:00:00", + "2023-05-10T04:00:00", + "2023-05-10T06:00:00", + "2023-05-10T08:00:00", + "2023-05-10T10:00:00", + "2023-05-10T12:00:00", + "2023-05-10T14:00:00", + "2023-05-10T16:00:00", + "2023-05-10T18:00:00", + "2023-05-10T20:00:00", + "2023-05-10T22:00:00", + "2023-05-11T00:00:00", + "2023-05-11T02:00:00", + "2023-05-11T04:00:00", + "2023-05-11T06:00:00", + "2023-05-11T08:00:00", + "2023-05-11T10:00:00", + "2023-05-11T12:00:00", + "2023-05-11T14:00:00", + "2023-05-11T16:00:00", + "2023-05-11T18:00:00", + "2023-05-11T20:00:00", + "2023-05-11T22:00:00", + "2023-05-12T00:00:00", + "2023-05-12T02:00:00", + "2023-05-12T04:00:00", + "2023-05-12T06:00:00", + "2023-05-12T08:00:00", + "2023-05-12T10:00:00", + "2023-05-12T12:00:00", + "2023-05-12T14:00:00", + "2023-05-12T16:00:00", + "2023-05-12T18:00:00", + "2023-05-12T20:00:00", + "2023-05-12T22:00:00", + "2023-05-13T00:00:00", + "2023-05-13T02:00:00", + "2023-05-13T04:00:00", + "2023-05-13T06:00:00", + "2023-05-13T08:00:00", + "2023-05-13T10:00:00", + "2023-05-13T12:00:00", + "2023-05-13T14:00:00", + "2023-05-13T16:00:00", + "2023-05-13T18:00:00", + "2023-05-13T20:00:00", + "2023-05-13T22:00:00", + "2023-05-14T00:00:00", + "2023-05-14T02:00:00", + "2023-05-14T04:00:00", + "2023-05-14T06:00:00", + "2023-05-14T08:00:00", + "2023-05-14T10:00:00", + "2023-05-14T12:00:00", + "2023-05-14T14:00:00", + "2023-05-14T16:00:00", + "2023-05-14T18:00:00", + "2023-05-14T20:00:00", + "2023-05-14T22:00:00", + "2023-05-15T00:00:00", + "2023-05-15T02:00:00", + "2023-05-15T04:00:00", + "2023-05-15T06:00:00", + "2023-05-15T08:00:00", + "2023-05-15T10:00:00", + "2023-05-15T12:00:00", + "2023-05-15T14:00:00", + "2023-05-15T16:00:00", + "2023-05-15T18:00:00", + "2023-05-15T20:00:00", + "2023-05-15T22:00:00", + "2023-05-16T00:00:00", + "2023-05-16T02:00:00", + "2023-05-16T04:00:00", + "2023-05-16T06:00:00", + "2023-05-16T08:00:00", + "2023-05-16T10:00:00", + "2023-05-16T12:00:00", + "2023-05-16T14:00:00", + "2023-05-16T16:00:00", + "2023-05-16T18:00:00", + "2023-05-16T20:00:00", + "2023-05-16T22:00:00", + "2023-05-17T00:00:00", + "2023-05-17T02:00:00", + "2023-05-17T04:00:00", + "2023-05-17T06:00:00", + "2023-05-17T08:00:00", + "2023-05-17T10:00:00", + "2023-05-17T12:00:00", + "2023-05-17T14:00:00", + "2023-05-17T16:00:00", + "2023-05-17T18:00:00", + "2023-05-17T20:00:00", + "2023-05-17T22:00:00", + "2023-05-18T00:00:00", + "2023-05-18T02:00:00", + "2023-05-18T04:00:00", + "2023-05-18T06:00:00", + "2023-05-18T08:00:00", + "2023-05-18T10:00:00", + "2023-05-18T12:00:00", + "2023-05-18T14:00:00", + "2023-05-18T16:00:00", + "2023-05-18T18:00:00", + "2023-05-18T20:00:00", + "2023-05-18T22:00:00", + "2023-05-19T00:00:00", + "2023-05-19T02:00:00", + "2023-05-19T04:00:00", + "2023-05-19T06:00:00", + "2023-05-19T08:00:00", + "2023-05-19T10:00:00", + "2023-05-19T12:00:00", + "2023-05-19T14:00:00", + "2023-05-19T16:00:00", + "2023-05-19T18:00:00", + "2023-05-19T20:00:00", + "2023-05-19T22:00:00", + "2023-05-20T00:00:00", + "2023-05-20T02:00:00", + "2023-05-20T04:00:00", + "2023-05-20T06:00:00", + "2023-05-20T08:00:00", + "2023-05-20T10:00:00", + "2023-05-20T12:00:00", + "2023-05-20T14:00:00", + "2023-05-20T16:00:00", + "2023-05-20T18:00:00", + "2023-05-20T20:00:00", + "2023-05-20T22:00:00", + "2023-05-21T00:00:00", + "2023-05-21T02:00:00", + "2023-05-21T04:00:00", + "2023-05-21T06:00:00", + "2023-05-21T08:00:00", + "2023-05-21T10:00:00", + "2023-05-21T12:00:00", + "2023-05-21T14:00:00", + "2023-05-21T16:00:00", + "2023-05-21T18:00:00", + "2023-05-21T20:00:00", + "2023-05-21T22:00:00", + "2023-05-22T00:00:00", + "2023-05-22T02:00:00", + "2023-05-22T04:00:00", + "2023-05-22T06:00:00", + "2023-05-22T08:00:00", + "2023-05-22T10:00:00", + "2023-05-22T12:00:00", + "2023-05-22T14:00:00", + "2023-05-22T16:00:00", + "2023-05-22T18:00:00", + "2023-05-22T20:00:00", + "2023-05-22T22:00:00", + "2023-05-23T00:00:00", + "2023-05-23T02:00:00", + "2023-05-23T04:00:00", + "2023-05-23T06:00:00", + "2023-05-23T08:00:00", + "2023-05-23T10:00:00", + "2023-05-23T12:00:00", + "2023-05-23T14:00:00", + "2023-05-23T16:00:00", + "2023-05-23T18:00:00", + "2023-05-23T20:00:00", + "2023-05-23T22:00:00", + "2023-05-24T00:00:00", + "2023-05-24T02:00:00", + "2023-05-24T04:00:00", + "2023-05-24T06:00:00", + "2023-05-24T08:00:00", + "2023-05-24T10:00:00", + "2023-05-24T12:00:00", + "2023-05-24T14:00:00", + "2023-05-24T16:00:00", + "2023-05-24T18:00:00", + "2023-05-24T20:00:00", + "2023-05-24T22:00:00", + "2023-05-25T00:00:00", + "2023-05-25T02:00:00", + "2023-05-25T04:00:00", + "2023-05-25T06:00:00", + "2023-05-25T08:00:00", + "2023-05-25T10:00:00", + "2023-05-25T12:00:00", + "2023-05-25T14:00:00", + "2023-05-25T16:00:00", + "2023-05-25T18:00:00", + "2023-05-25T20:00:00", + "2023-05-25T22:00:00", + "2023-05-26T00:00:00", + "2023-05-26T02:00:00", + "2023-05-26T04:00:00", + "2023-05-26T06:00:00", + "2023-05-26T08:00:00", + "2023-05-26T10:00:00", + "2023-05-26T12:00:00", + "2023-05-26T14:00:00", + "2023-05-26T16:00:00", + "2023-05-26T18:00:00", + "2023-05-26T20:00:00", + "2023-05-26T22:00:00", + "2023-05-27T00:00:00", + "2023-05-27T02:00:00", + "2023-05-27T04:00:00", + "2023-05-27T06:00:00", + "2023-05-27T08:00:00", + "2023-05-27T10:00:00", + "2023-05-27T12:00:00", + "2023-05-27T14:00:00", + "2023-05-27T16:00:00", + "2023-05-27T18:00:00", + "2023-05-27T20:00:00", + "2023-05-27T22:00:00", + "2023-05-28T00:00:00", + "2023-05-28T02:00:00", + "2023-05-28T04:00:00", + "2023-05-28T06:00:00", + "2023-05-28T08:00:00", + "2023-05-28T10:00:00", + "2023-05-28T12:00:00", + "2023-05-28T14:00:00", + "2023-05-28T16:00:00", + "2023-05-28T18:00:00", + "2023-05-28T20:00:00", + "2023-05-28T22:00:00", + "2023-05-29T00:00:00", + "2023-05-29T02:00:00", + "2023-05-29T04:00:00", + "2023-05-29T06:00:00", + "2023-05-29T08:00:00", + "2023-05-29T10:00:00", + "2023-05-29T12:00:00", + "2023-05-29T14:00:00", + "2023-05-29T16:00:00", + "2023-05-29T18:00:00", + "2023-05-29T20:00:00", + "2023-05-29T22:00:00", + "2023-05-30T00:00:00", + "2023-05-30T02:00:00", + "2023-05-30T04:00:00", + "2023-05-30T06:00:00", + "2023-05-30T08:00:00", + "2023-05-30T10:00:00", + "2023-05-30T12:00:00", + "2023-05-30T14:00:00", + "2023-05-30T16:00:00", + "2023-05-30T18:00:00", + "2023-05-30T20:00:00", + "2023-05-30T22:00:00", + "2023-05-31T00:00:00", + "2023-05-31T02:00:00", + "2023-05-31T04:00:00", + "2023-05-31T06:00:00", + "2023-05-31T08:00:00", + "2023-05-31T10:00:00", + "2023-05-31T12:00:00", + "2023-05-31T14:00:00", + "2023-05-31T16:00:00", + "2023-05-31T18:00:00", + "2023-05-31T20:00:00", + "2023-05-31T22:00:00", + "2023-06-01T00:00:00" + ], + "y": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 15912.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 15897.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 15629.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 21550.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 21661.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 20679.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 20775.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26296.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26165.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26240.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26108.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25952.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 27689.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25763.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26316.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25208.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25228.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25089.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25360.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 24957.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "type": "scatter", + "xaxis": "x", + "yaxis": "y" + }, + { + "marker": { + "color": "red", + "symbol": "arrow-down" + }, + "mode": "markers", + "name": "Sell", + "x": [ + "2022-12-20T00:00:00", + "2022-12-20T02:00:00", + "2022-12-20T04:00:00", + "2022-12-20T06:00:00", + "2022-12-20T08:00:00", + "2022-12-20T10:00:00", + "2022-12-20T12:00:00", + "2022-12-20T14:00:00", + "2022-12-20T16:00:00", + "2022-12-20T18:00:00", + "2022-12-20T20:00:00", + "2022-12-20T22:00:00", + "2022-12-21T00:00:00", + "2022-12-21T02:00:00", + "2022-12-21T04:00:00", + "2022-12-21T06:00:00", + "2022-12-21T08:00:00", + "2022-12-21T10:00:00", + "2022-12-21T12:00:00", + "2022-12-21T14:00:00", + "2022-12-21T16:00:00", + "2022-12-21T18:00:00", + "2022-12-21T20:00:00", + "2022-12-21T22:00:00", + "2022-12-22T00:00:00", + "2022-12-22T02:00:00", + "2022-12-22T04:00:00", + "2022-12-22T06:00:00", + "2022-12-22T08:00:00", + "2022-12-22T10:00:00", + "2022-12-22T12:00:00", + "2022-12-22T14:00:00", + "2022-12-22T16:00:00", + "2022-12-22T18:00:00", + "2022-12-22T20:00:00", + "2022-12-22T22:00:00", + "2022-12-23T00:00:00", + "2022-12-23T02:00:00", + "2022-12-23T04:00:00", + "2022-12-23T06:00:00", + "2022-12-23T08:00:00", + "2022-12-23T10:00:00", + "2022-12-23T12:00:00", + "2022-12-23T14:00:00", + "2022-12-23T16:00:00", + "2022-12-23T18:00:00", + "2022-12-23T20:00:00", + "2022-12-23T22:00:00", + "2022-12-24T00:00:00", + "2022-12-24T02:00:00", + "2022-12-24T04:00:00", + "2022-12-24T06:00:00", + "2022-12-24T08:00:00", + "2022-12-24T10:00:00", + "2022-12-24T12:00:00", + "2022-12-24T14:00:00", + "2022-12-24T16:00:00", + "2022-12-24T18:00:00", + "2022-12-24T20:00:00", + "2022-12-24T22:00:00", + "2022-12-25T00:00:00", + "2022-12-25T02:00:00", + "2022-12-25T04:00:00", + "2022-12-25T06:00:00", + "2022-12-25T08:00:00", + "2022-12-25T10:00:00", + "2022-12-25T12:00:00", + "2022-12-25T14:00:00", + "2022-12-25T16:00:00", + "2022-12-25T18:00:00", + "2022-12-25T20:00:00", + "2022-12-25T22:00:00", + "2022-12-26T00:00:00", + "2022-12-26T02:00:00", + "2022-12-26T04:00:00", + "2022-12-26T06:00:00", + "2022-12-26T08:00:00", + "2022-12-26T10:00:00", + "2022-12-26T12:00:00", + "2022-12-26T14:00:00", + "2022-12-26T16:00:00", + "2022-12-26T18:00:00", + "2022-12-26T20:00:00", + "2022-12-26T22:00:00", + "2022-12-27T00:00:00", + "2022-12-27T02:00:00", + "2022-12-27T04:00:00", + "2022-12-27T06:00:00", + "2022-12-27T08:00:00", + "2022-12-27T10:00:00", + "2022-12-27T12:00:00", + "2022-12-27T14:00:00", + "2022-12-27T16:00:00", + "2022-12-27T18:00:00", + "2022-12-27T20:00:00", + "2022-12-27T22:00:00", + "2022-12-28T00:00:00", + "2022-12-28T02:00:00", + "2022-12-28T04:00:00", + "2022-12-28T06:00:00", + "2022-12-28T08:00:00", + "2022-12-28T10:00:00", + "2022-12-28T12:00:00", + "2022-12-28T14:00:00", + "2022-12-28T16:00:00", + "2022-12-28T18:00:00", + "2022-12-28T20:00:00", + "2022-12-28T22:00:00", + "2022-12-29T00:00:00", + "2022-12-29T02:00:00", + "2022-12-29T04:00:00", + "2022-12-29T06:00:00", + "2022-12-29T08:00:00", + "2022-12-29T10:00:00", + "2022-12-29T12:00:00", + "2022-12-29T14:00:00", + "2022-12-29T16:00:00", + "2022-12-29T18:00:00", + "2022-12-29T20:00:00", + "2022-12-29T22:00:00", + "2022-12-30T00:00:00", + "2022-12-30T02:00:00", + "2022-12-30T04:00:00", + "2022-12-30T06:00:00", + "2022-12-30T08:00:00", + "2022-12-30T10:00:00", + "2022-12-30T12:00:00", + "2022-12-30T14:00:00", + "2022-12-30T16:00:00", + "2022-12-30T18:00:00", + "2022-12-30T20:00:00", + "2022-12-30T22:00:00", + "2022-12-31T00:00:00", + "2022-12-31T02:00:00", + "2022-12-31T04:00:00", + "2022-12-31T06:00:00", + "2022-12-31T08:00:00", + "2022-12-31T10:00:00", + "2022-12-31T12:00:00", + "2022-12-31T14:00:00", + "2022-12-31T16:00:00", + "2022-12-31T18:00:00", + "2022-12-31T20:00:00", + "2022-12-31T22:00:00", + "2023-01-01T00:00:00", + "2023-01-01T02:00:00", + "2023-01-01T04:00:00", + "2023-01-01T06:00:00", + "2023-01-01T08:00:00", + "2023-01-01T10:00:00", + "2023-01-01T12:00:00", + "2023-01-01T14:00:00", + "2023-01-01T16:00:00", + "2023-01-01T18:00:00", + "2023-01-01T20:00:00", + "2023-01-01T22:00:00", + "2023-01-02T00:00:00", + "2023-01-02T02:00:00", + "2023-01-02T04:00:00", + "2023-01-02T06:00:00", + "2023-01-02T08:00:00", + "2023-01-02T10:00:00", + "2023-01-02T12:00:00", + "2023-01-02T14:00:00", + "2023-01-02T16:00:00", + "2023-01-02T18:00:00", + "2023-01-02T20:00:00", + "2023-01-02T22:00:00", + "2023-01-03T00:00:00", + "2023-01-03T02:00:00", + "2023-01-03T04:00:00", + "2023-01-03T06:00:00", + "2023-01-03T08:00:00", + "2023-01-03T10:00:00", + "2023-01-03T12:00:00", + "2023-01-03T14:00:00", + "2023-01-03T16:00:00", + "2023-01-03T18:00:00", + "2023-01-03T20:00:00", + "2023-01-03T22:00:00", + "2023-01-04T00:00:00", + "2023-01-04T02:00:00", + "2023-01-04T04:00:00", + "2023-01-04T06:00:00", + "2023-01-04T08:00:00", + "2023-01-04T10:00:00", + "2023-01-04T12:00:00", + "2023-01-04T14:00:00", + "2023-01-04T16:00:00", + "2023-01-04T18:00:00", + "2023-01-04T20:00:00", + "2023-01-04T22:00:00", + "2023-01-05T00:00:00", + "2023-01-05T02:00:00", + "2023-01-05T04:00:00", + "2023-01-05T06:00:00", + "2023-01-05T08:00:00", + "2023-01-05T10:00:00", + "2023-01-05T12:00:00", + "2023-01-05T14:00:00", + "2023-01-05T16:00:00", + "2023-01-05T18:00:00", + "2023-01-05T20:00:00", + "2023-01-05T22:00:00", + "2023-01-06T00:00:00", + "2023-01-06T02:00:00", + "2023-01-06T04:00:00", + "2023-01-06T06:00:00", + "2023-01-06T08:00:00", + "2023-01-06T10:00:00", + "2023-01-06T12:00:00", + "2023-01-06T14:00:00", + "2023-01-06T16:00:00", + "2023-01-06T18:00:00", + "2023-01-06T20:00:00", + "2023-01-06T22:00:00", + "2023-01-07T00:00:00", + "2023-01-07T02:00:00", + "2023-01-07T04:00:00", + "2023-01-07T06:00:00", + "2023-01-07T08:00:00", + "2023-01-07T10:00:00", + "2023-01-07T12:00:00", + "2023-01-07T14:00:00", + "2023-01-07T16:00:00", + "2023-01-07T18:00:00", + "2023-01-07T20:00:00", + "2023-01-07T22:00:00", + "2023-01-08T00:00:00", + "2023-01-08T02:00:00", + "2023-01-08T04:00:00", + "2023-01-08T06:00:00", + "2023-01-08T08:00:00", + "2023-01-08T10:00:00", + "2023-01-08T12:00:00", + "2023-01-08T14:00:00", + "2023-01-08T16:00:00", + "2023-01-08T18:00:00", + "2023-01-08T20:00:00", + "2023-01-08T22:00:00", + "2023-01-09T00:00:00", + "2023-01-09T02:00:00", + "2023-01-09T04:00:00", + "2023-01-09T06:00:00", + "2023-01-09T08:00:00", + "2023-01-09T10:00:00", + "2023-01-09T12:00:00", + "2023-01-09T14:00:00", + "2023-01-09T16:00:00", + "2023-01-09T18:00:00", + "2023-01-09T20:00:00", + "2023-01-09T22:00:00", + "2023-01-10T00:00:00", + "2023-01-10T02:00:00", + "2023-01-10T04:00:00", + "2023-01-10T06:00:00", + "2023-01-10T08:00:00", + "2023-01-10T10:00:00", + "2023-01-10T12:00:00", + "2023-01-10T14:00:00", + "2023-01-10T16:00:00", + "2023-01-10T18:00:00", + "2023-01-10T20:00:00", + "2023-01-10T22:00:00", + "2023-01-11T00:00:00", + "2023-01-11T02:00:00", + "2023-01-11T04:00:00", + "2023-01-11T06:00:00", + "2023-01-11T08:00:00", + "2023-01-11T10:00:00", + "2023-01-11T12:00:00", + "2023-01-11T14:00:00", + "2023-01-11T16:00:00", + "2023-01-11T18:00:00", + "2023-01-11T20:00:00", + "2023-01-11T22:00:00", + "2023-01-12T00:00:00", + "2023-01-12T02:00:00", + "2023-01-12T04:00:00", + "2023-01-12T06:00:00", + "2023-01-12T08:00:00", + "2023-01-12T10:00:00", + "2023-01-12T12:00:00", + "2023-01-12T14:00:00", + "2023-01-12T16:00:00", + "2023-01-12T18:00:00", + "2023-01-12T20:00:00", + "2023-01-12T22:00:00", + "2023-01-13T00:00:00", + "2023-01-13T02:00:00", + "2023-01-13T04:00:00", + "2023-01-13T06:00:00", + "2023-01-13T08:00:00", + "2023-01-13T10:00:00", + "2023-01-13T12:00:00", + "2023-01-13T14:00:00", + "2023-01-13T16:00:00", + "2023-01-13T18:00:00", + "2023-01-13T20:00:00", + "2023-01-13T22:00:00", + "2023-01-14T00:00:00", + "2023-01-14T02:00:00", + "2023-01-14T04:00:00", + "2023-01-14T06:00:00", + "2023-01-14T08:00:00", + "2023-01-14T10:00:00", + "2023-01-14T12:00:00", + "2023-01-14T14:00:00", + "2023-01-14T16:00:00", + "2023-01-14T18:00:00", + "2023-01-14T20:00:00", + "2023-01-14T22:00:00", + "2023-01-15T00:00:00", + "2023-01-15T02:00:00", + "2023-01-15T04:00:00", + "2023-01-15T06:00:00", + "2023-01-15T08:00:00", + "2023-01-15T10:00:00", + "2023-01-15T12:00:00", + "2023-01-15T14:00:00", + "2023-01-15T16:00:00", + "2023-01-15T18:00:00", + "2023-01-15T20:00:00", + "2023-01-15T22:00:00", + "2023-01-16T00:00:00", + "2023-01-16T02:00:00", + "2023-01-16T04:00:00", + "2023-01-16T06:00:00", + "2023-01-16T08:00:00", + "2023-01-16T10:00:00", + "2023-01-16T12:00:00", + "2023-01-16T14:00:00", + "2023-01-16T16:00:00", + "2023-01-16T18:00:00", + "2023-01-16T20:00:00", + "2023-01-16T22:00:00", + "2023-01-17T00:00:00", + "2023-01-17T02:00:00", + "2023-01-17T04:00:00", + "2023-01-17T06:00:00", + "2023-01-17T08:00:00", + "2023-01-17T10:00:00", + "2023-01-17T12:00:00", + "2023-01-17T14:00:00", + "2023-01-17T16:00:00", + "2023-01-17T18:00:00", + "2023-01-17T20:00:00", + "2023-01-17T22:00:00", + "2023-01-18T00:00:00", + "2023-01-18T02:00:00", + "2023-01-18T04:00:00", + "2023-01-18T06:00:00", + "2023-01-18T08:00:00", + "2023-01-18T10:00:00", + "2023-01-18T12:00:00", + "2023-01-18T14:00:00", + "2023-01-18T16:00:00", + "2023-01-18T18:00:00", + "2023-01-18T20:00:00", + "2023-01-18T22:00:00", + "2023-01-19T00:00:00", + "2023-01-19T02:00:00", + "2023-01-19T04:00:00", + "2023-01-19T06:00:00", + "2023-01-19T08:00:00", + "2023-01-19T10:00:00", + "2023-01-19T12:00:00", + "2023-01-19T14:00:00", + "2023-01-19T16:00:00", + "2023-01-19T18:00:00", + "2023-01-19T20:00:00", + "2023-01-19T22:00:00", + "2023-01-20T00:00:00", + "2023-01-20T02:00:00", + "2023-01-20T04:00:00", + "2023-01-20T06:00:00", + "2023-01-20T08:00:00", + "2023-01-20T10:00:00", + "2023-01-20T12:00:00", + "2023-01-20T14:00:00", + "2023-01-20T16:00:00", + "2023-01-20T18:00:00", + "2023-01-20T20:00:00", + "2023-01-20T22:00:00", + "2023-01-21T00:00:00", + "2023-01-21T02:00:00", + "2023-01-21T04:00:00", + "2023-01-21T06:00:00", + "2023-01-21T08:00:00", + "2023-01-21T10:00:00", + "2023-01-21T12:00:00", + "2023-01-21T14:00:00", + "2023-01-21T16:00:00", + "2023-01-21T18:00:00", + "2023-01-21T20:00:00", + "2023-01-21T22:00:00", + "2023-01-22T00:00:00", + "2023-01-22T02:00:00", + "2023-01-22T04:00:00", + "2023-01-22T06:00:00", + "2023-01-22T08:00:00", + "2023-01-22T10:00:00", + "2023-01-22T12:00:00", + "2023-01-22T14:00:00", + "2023-01-22T16:00:00", + "2023-01-22T18:00:00", + "2023-01-22T20:00:00", + "2023-01-22T22:00:00", + "2023-01-23T00:00:00", + "2023-01-23T02:00:00", + "2023-01-23T04:00:00", + "2023-01-23T06:00:00", + "2023-01-23T08:00:00", + "2023-01-23T10:00:00", + "2023-01-23T12:00:00", + "2023-01-23T14:00:00", + "2023-01-23T16:00:00", + "2023-01-23T18:00:00", + "2023-01-23T20:00:00", + "2023-01-23T22:00:00", + "2023-01-24T00:00:00", + "2023-01-24T02:00:00", + "2023-01-24T04:00:00", + "2023-01-24T06:00:00", + "2023-01-24T08:00:00", + "2023-01-24T10:00:00", + "2023-01-24T12:00:00", + "2023-01-24T14:00:00", + "2023-01-24T16:00:00", + "2023-01-24T18:00:00", + "2023-01-24T20:00:00", + "2023-01-24T22:00:00", + "2023-01-25T00:00:00", + "2023-01-25T02:00:00", + "2023-01-25T04:00:00", + "2023-01-25T06:00:00", + "2023-01-25T08:00:00", + "2023-01-25T10:00:00", + "2023-01-25T12:00:00", + "2023-01-25T14:00:00", + "2023-01-25T16:00:00", + "2023-01-25T18:00:00", + "2023-01-25T20:00:00", + "2023-01-25T22:00:00", + "2023-01-26T00:00:00", + "2023-01-26T02:00:00", + "2023-01-26T04:00:00", + "2023-01-26T06:00:00", + "2023-01-26T08:00:00", + "2023-01-26T10:00:00", + "2023-01-26T12:00:00", + "2023-01-26T14:00:00", + "2023-01-26T16:00:00", + "2023-01-26T18:00:00", + "2023-01-26T20:00:00", + "2023-01-26T22:00:00", + "2023-01-27T00:00:00", + "2023-01-27T02:00:00", + "2023-01-27T04:00:00", + "2023-01-27T06:00:00", + "2023-01-27T08:00:00", + "2023-01-27T10:00:00", + "2023-01-27T12:00:00", + "2023-01-27T14:00:00", + "2023-01-27T16:00:00", + "2023-01-27T18:00:00", + "2023-01-27T20:00:00", + "2023-01-27T22:00:00", + "2023-01-28T00:00:00", + "2023-01-28T02:00:00", + "2023-01-28T04:00:00", + "2023-01-28T06:00:00", + "2023-01-28T08:00:00", + "2023-01-28T10:00:00", + "2023-01-28T12:00:00", + "2023-01-28T14:00:00", + "2023-01-28T16:00:00", + "2023-01-28T18:00:00", + "2023-01-28T20:00:00", + "2023-01-28T22:00:00", + "2023-01-29T00:00:00", + "2023-01-29T02:00:00", + "2023-01-29T04:00:00", + "2023-01-29T06:00:00", + "2023-01-29T08:00:00", + "2023-01-29T10:00:00", + "2023-01-29T12:00:00", + "2023-01-29T14:00:00", + "2023-01-29T16:00:00", + "2023-01-29T18:00:00", + "2023-01-29T20:00:00", + "2023-01-29T22:00:00", + "2023-01-30T00:00:00", + "2023-01-30T02:00:00", + "2023-01-30T04:00:00", + "2023-01-30T06:00:00", + "2023-01-30T08:00:00", + "2023-01-30T10:00:00", + "2023-01-30T12:00:00", + "2023-01-30T14:00:00", + "2023-01-30T16:00:00", + "2023-01-30T18:00:00", + "2023-01-30T20:00:00", + "2023-01-30T22:00:00", + "2023-01-31T00:00:00", + "2023-01-31T02:00:00", + "2023-01-31T04:00:00", + "2023-01-31T06:00:00", + "2023-01-31T08:00:00", + "2023-01-31T10:00:00", + "2023-01-31T12:00:00", + "2023-01-31T14:00:00", + "2023-01-31T16:00:00", + "2023-01-31T18:00:00", + "2023-01-31T20:00:00", + "2023-01-31T22:00:00", + "2023-02-01T00:00:00", + "2023-02-01T02:00:00", + "2023-02-01T04:00:00", + "2023-02-01T06:00:00", + "2023-02-01T08:00:00", + "2023-02-01T10:00:00", + "2023-02-01T12:00:00", + "2023-02-01T14:00:00", + "2023-02-01T16:00:00", + "2023-02-01T18:00:00", + "2023-02-01T20:00:00", + "2023-02-01T22:00:00", + "2023-02-02T00:00:00", + "2023-02-02T02:00:00", + "2023-02-02T04:00:00", + "2023-02-02T06:00:00", + "2023-02-02T08:00:00", + "2023-02-02T10:00:00", + "2023-02-02T12:00:00", + "2023-02-02T14:00:00", + "2023-02-02T16:00:00", + "2023-02-02T18:00:00", + "2023-02-02T20:00:00", + "2023-02-02T22:00:00", + "2023-02-03T00:00:00", + "2023-02-03T02:00:00", + "2023-02-03T04:00:00", + "2023-02-03T06:00:00", + "2023-02-03T08:00:00", + "2023-02-03T10:00:00", + "2023-02-03T12:00:00", + "2023-02-03T14:00:00", + "2023-02-03T16:00:00", + "2023-02-03T18:00:00", + "2023-02-03T20:00:00", + "2023-02-03T22:00:00", + "2023-02-04T00:00:00", + "2023-02-04T02:00:00", + "2023-02-04T04:00:00", + "2023-02-04T06:00:00", + "2023-02-04T08:00:00", + "2023-02-04T10:00:00", + "2023-02-04T12:00:00", + "2023-02-04T14:00:00", + "2023-02-04T16:00:00", + "2023-02-04T18:00:00", + "2023-02-04T20:00:00", + "2023-02-04T22:00:00", + "2023-02-05T00:00:00", + "2023-02-05T02:00:00", + "2023-02-05T04:00:00", + "2023-02-05T06:00:00", + "2023-02-05T08:00:00", + "2023-02-05T10:00:00", + "2023-02-05T12:00:00", + "2023-02-05T14:00:00", + "2023-02-05T16:00:00", + "2023-02-05T18:00:00", + "2023-02-05T20:00:00", + "2023-02-05T22:00:00", + "2023-02-06T00:00:00", + "2023-02-06T02:00:00", + "2023-02-06T04:00:00", + "2023-02-06T06:00:00", + "2023-02-06T08:00:00", + "2023-02-06T10:00:00", + "2023-02-06T12:00:00", + "2023-02-06T14:00:00", + "2023-02-06T16:00:00", + "2023-02-06T18:00:00", + "2023-02-06T20:00:00", + "2023-02-06T22:00:00", + "2023-02-07T00:00:00", + "2023-02-07T02:00:00", + "2023-02-07T04:00:00", + "2023-02-07T06:00:00", + "2023-02-07T08:00:00", + "2023-02-07T10:00:00", + "2023-02-07T12:00:00", + "2023-02-07T14:00:00", + "2023-02-07T16:00:00", + "2023-02-07T18:00:00", + "2023-02-07T20:00:00", + "2023-02-07T22:00:00", + "2023-02-08T00:00:00", + "2023-02-08T02:00:00", + "2023-02-08T04:00:00", + "2023-02-08T06:00:00", + "2023-02-08T08:00:00", + "2023-02-08T10:00:00", + "2023-02-08T12:00:00", + "2023-02-08T14:00:00", + "2023-02-08T16:00:00", + "2023-02-08T18:00:00", + "2023-02-08T20:00:00", + "2023-02-08T22:00:00", + "2023-02-09T00:00:00", + "2023-02-09T02:00:00", + "2023-02-09T04:00:00", + "2023-02-09T06:00:00", + "2023-02-09T08:00:00", + "2023-02-09T10:00:00", + "2023-02-09T12:00:00", + "2023-02-09T14:00:00", + "2023-02-09T16:00:00", + "2023-02-09T18:00:00", + "2023-02-09T20:00:00", + "2023-02-09T22:00:00", + "2023-02-10T00:00:00", + "2023-02-10T02:00:00", + "2023-02-10T04:00:00", + "2023-02-10T06:00:00", + "2023-02-10T08:00:00", + "2023-02-10T10:00:00", + "2023-02-10T12:00:00", + "2023-02-10T14:00:00", + "2023-02-10T16:00:00", + "2023-02-10T18:00:00", + "2023-02-10T20:00:00", + "2023-02-10T22:00:00", + "2023-02-11T00:00:00", + "2023-02-11T02:00:00", + "2023-02-11T04:00:00", + "2023-02-11T06:00:00", + "2023-02-11T08:00:00", + "2023-02-11T10:00:00", + "2023-02-11T12:00:00", + "2023-02-11T14:00:00", + "2023-02-11T16:00:00", + "2023-02-11T18:00:00", + "2023-02-11T20:00:00", + "2023-02-11T22:00:00", + "2023-02-12T00:00:00", + "2023-02-12T02:00:00", + "2023-02-12T04:00:00", + "2023-02-12T06:00:00", + "2023-02-12T08:00:00", + "2023-02-12T10:00:00", + "2023-02-12T12:00:00", + "2023-02-12T14:00:00", + "2023-02-12T16:00:00", + "2023-02-12T18:00:00", + "2023-02-12T20:00:00", + "2023-02-12T22:00:00", + "2023-02-13T00:00:00", + "2023-02-13T02:00:00", + "2023-02-13T04:00:00", + "2023-02-13T06:00:00", + "2023-02-13T08:00:00", + "2023-02-13T10:00:00", + "2023-02-13T12:00:00", + "2023-02-13T14:00:00", + "2023-02-13T16:00:00", + "2023-02-13T18:00:00", + "2023-02-13T20:00:00", + "2023-02-13T22:00:00", + "2023-02-14T00:00:00", + "2023-02-14T02:00:00", + "2023-02-14T04:00:00", + "2023-02-14T06:00:00", + "2023-02-14T08:00:00", + "2023-02-14T10:00:00", + "2023-02-14T12:00:00", + "2023-02-14T14:00:00", + "2023-02-14T16:00:00", + "2023-02-14T18:00:00", + "2023-02-14T20:00:00", + "2023-02-14T22:00:00", + "2023-02-15T00:00:00", + "2023-02-15T02:00:00", + "2023-02-15T04:00:00", + "2023-02-15T06:00:00", + "2023-02-15T08:00:00", + "2023-02-15T10:00:00", + "2023-02-15T12:00:00", + "2023-02-15T14:00:00", + "2023-02-15T16:00:00", + "2023-02-15T18:00:00", + "2023-02-15T20:00:00", + "2023-02-15T22:00:00", + "2023-02-16T00:00:00", + "2023-02-16T02:00:00", + "2023-02-16T04:00:00", + "2023-02-16T06:00:00", + "2023-02-16T08:00:00", + "2023-02-16T10:00:00", + "2023-02-16T12:00:00", + "2023-02-16T14:00:00", + "2023-02-16T16:00:00", + "2023-02-16T18:00:00", + "2023-02-16T20:00:00", + "2023-02-16T22:00:00", + "2023-02-17T00:00:00", + "2023-02-17T02:00:00", + "2023-02-17T04:00:00", + "2023-02-17T06:00:00", + "2023-02-17T08:00:00", + "2023-02-17T10:00:00", + "2023-02-17T12:00:00", + "2023-02-17T14:00:00", + "2023-02-17T16:00:00", + "2023-02-17T18:00:00", + "2023-02-17T20:00:00", + "2023-02-17T22:00:00", + "2023-02-18T00:00:00", + "2023-02-18T02:00:00", + "2023-02-18T04:00:00", + "2023-02-18T06:00:00", + "2023-02-18T08:00:00", + "2023-02-18T10:00:00", + "2023-02-18T12:00:00", + "2023-02-18T14:00:00", + "2023-02-18T16:00:00", + "2023-02-18T18:00:00", + "2023-02-18T20:00:00", + "2023-02-18T22:00:00", + "2023-02-19T00:00:00", + "2023-02-19T02:00:00", + "2023-02-19T04:00:00", + "2023-02-19T06:00:00", + "2023-02-19T08:00:00", + "2023-02-19T10:00:00", + "2023-02-19T12:00:00", + "2023-02-19T14:00:00", + "2023-02-19T16:00:00", + "2023-02-19T18:00:00", + "2023-02-19T20:00:00", + "2023-02-19T22:00:00", + "2023-02-20T00:00:00", + "2023-02-20T02:00:00", + "2023-02-20T04:00:00", + "2023-02-20T06:00:00", + "2023-02-20T08:00:00", + "2023-02-20T10:00:00", + "2023-02-20T12:00:00", + "2023-02-20T14:00:00", + "2023-02-20T16:00:00", + "2023-02-20T18:00:00", + "2023-02-20T20:00:00", + "2023-02-20T22:00:00", + "2023-02-21T00:00:00", + "2023-02-21T02:00:00", + "2023-02-21T04:00:00", + "2023-02-21T06:00:00", + "2023-02-21T08:00:00", + "2023-02-21T10:00:00", + "2023-02-21T12:00:00", + "2023-02-21T14:00:00", + "2023-02-21T16:00:00", + "2023-02-21T18:00:00", + "2023-02-21T20:00:00", + "2023-02-21T22:00:00", + "2023-02-22T00:00:00", + "2023-02-22T02:00:00", + "2023-02-22T04:00:00", + "2023-02-22T06:00:00", + "2023-02-22T08:00:00", + "2023-02-22T10:00:00", + "2023-02-22T12:00:00", + "2023-02-22T14:00:00", + "2023-02-22T16:00:00", + "2023-02-22T18:00:00", + "2023-02-22T20:00:00", + "2023-02-22T22:00:00", + "2023-02-23T00:00:00", + "2023-02-23T02:00:00", + "2023-02-23T04:00:00", + "2023-02-23T06:00:00", + "2023-02-23T08:00:00", + "2023-02-23T10:00:00", + "2023-02-23T12:00:00", + "2023-02-23T14:00:00", + "2023-02-23T16:00:00", + "2023-02-23T18:00:00", + "2023-02-23T20:00:00", + "2023-02-23T22:00:00", + "2023-02-24T00:00:00", + "2023-02-24T02:00:00", + "2023-02-24T04:00:00", + "2023-02-24T06:00:00", + "2023-02-24T08:00:00", + "2023-02-24T10:00:00", + "2023-02-24T12:00:00", + "2023-02-24T14:00:00", + "2023-02-24T16:00:00", + "2023-02-24T18:00:00", + "2023-02-24T20:00:00", + "2023-02-24T22:00:00", + "2023-02-25T00:00:00", + "2023-02-25T02:00:00", + "2023-02-25T04:00:00", + "2023-02-25T06:00:00", + "2023-02-25T08:00:00", + "2023-02-25T10:00:00", + "2023-02-25T12:00:00", + "2023-02-25T14:00:00", + "2023-02-25T16:00:00", + "2023-02-25T18:00:00", + "2023-02-25T20:00:00", + "2023-02-25T22:00:00", + "2023-02-26T00:00:00", + "2023-02-26T02:00:00", + "2023-02-26T04:00:00", + "2023-02-26T06:00:00", + "2023-02-26T08:00:00", + "2023-02-26T10:00:00", + "2023-02-26T12:00:00", + "2023-02-26T14:00:00", + "2023-02-26T16:00:00", + "2023-02-26T18:00:00", + "2023-02-26T20:00:00", + "2023-02-26T22:00:00", + "2023-02-27T00:00:00", + "2023-02-27T02:00:00", + "2023-02-27T04:00:00", + "2023-02-27T06:00:00", + "2023-02-27T08:00:00", + "2023-02-27T10:00:00", + "2023-02-27T12:00:00", + "2023-02-27T14:00:00", + "2023-02-27T16:00:00", + "2023-02-27T18:00:00", + "2023-02-27T20:00:00", + "2023-02-27T22:00:00", + "2023-02-28T00:00:00", + "2023-02-28T02:00:00", + "2023-02-28T04:00:00", + "2023-02-28T06:00:00", + "2023-02-28T08:00:00", + "2023-02-28T10:00:00", + "2023-02-28T12:00:00", + "2023-02-28T14:00:00", + "2023-02-28T16:00:00", + "2023-02-28T18:00:00", + "2023-02-28T20:00:00", + "2023-02-28T22:00:00", + "2023-03-01T00:00:00", + "2023-03-01T02:00:00", + "2023-03-01T04:00:00", + "2023-03-01T06:00:00", + "2023-03-01T08:00:00", + "2023-03-01T10:00:00", + "2023-03-01T12:00:00", + "2023-03-01T14:00:00", + "2023-03-01T16:00:00", + "2023-03-01T18:00:00", + "2023-03-01T20:00:00", + "2023-03-01T22:00:00", + "2023-03-02T00:00:00", + "2023-03-02T02:00:00", + "2023-03-02T04:00:00", + "2023-03-02T06:00:00", + "2023-03-02T08:00:00", + "2023-03-02T10:00:00", + "2023-03-02T12:00:00", + "2023-03-02T14:00:00", + "2023-03-02T16:00:00", + "2023-03-02T18:00:00", + "2023-03-02T20:00:00", + "2023-03-02T22:00:00", + "2023-03-03T00:00:00", + "2023-03-03T02:00:00", + "2023-03-03T04:00:00", + "2023-03-03T06:00:00", + "2023-03-03T08:00:00", + "2023-03-03T10:00:00", + "2023-03-03T12:00:00", + "2023-03-03T14:00:00", + "2023-03-03T16:00:00", + "2023-03-03T18:00:00", + "2023-03-03T20:00:00", + "2023-03-03T22:00:00", + "2023-03-04T00:00:00", + "2023-03-04T02:00:00", + "2023-03-04T04:00:00", + "2023-03-04T06:00:00", + "2023-03-04T08:00:00", + "2023-03-04T10:00:00", + "2023-03-04T12:00:00", + "2023-03-04T14:00:00", + "2023-03-04T16:00:00", + "2023-03-04T18:00:00", + "2023-03-04T20:00:00", + "2023-03-04T22:00:00", + "2023-03-05T00:00:00", + "2023-03-05T02:00:00", + "2023-03-05T04:00:00", + "2023-03-05T06:00:00", + "2023-03-05T08:00:00", + "2023-03-05T10:00:00", + "2023-03-05T12:00:00", + "2023-03-05T14:00:00", + "2023-03-05T16:00:00", + "2023-03-05T18:00:00", + "2023-03-05T20:00:00", + "2023-03-05T22:00:00", + "2023-03-06T00:00:00", + "2023-03-06T02:00:00", + "2023-03-06T04:00:00", + "2023-03-06T06:00:00", + "2023-03-06T08:00:00", + "2023-03-06T10:00:00", + "2023-03-06T12:00:00", + "2023-03-06T14:00:00", + "2023-03-06T16:00:00", + "2023-03-06T18:00:00", + "2023-03-06T20:00:00", + "2023-03-06T22:00:00", + "2023-03-07T00:00:00", + "2023-03-07T02:00:00", + "2023-03-07T04:00:00", + "2023-03-07T06:00:00", + "2023-03-07T08:00:00", + "2023-03-07T10:00:00", + "2023-03-07T12:00:00", + "2023-03-07T14:00:00", + "2023-03-07T16:00:00", + "2023-03-07T18:00:00", + "2023-03-07T20:00:00", + "2023-03-07T22:00:00", + "2023-03-08T00:00:00", + "2023-03-08T02:00:00", + "2023-03-08T04:00:00", + "2023-03-08T06:00:00", + "2023-03-08T08:00:00", + "2023-03-08T10:00:00", + "2023-03-08T12:00:00", + "2023-03-08T14:00:00", + "2023-03-08T16:00:00", + "2023-03-08T18:00:00", + "2023-03-08T20:00:00", + "2023-03-08T22:00:00", + "2023-03-09T00:00:00", + "2023-03-09T02:00:00", + "2023-03-09T04:00:00", + "2023-03-09T06:00:00", + "2023-03-09T08:00:00", + "2023-03-09T10:00:00", + "2023-03-09T12:00:00", + "2023-03-09T14:00:00", + "2023-03-09T16:00:00", + "2023-03-09T18:00:00", + "2023-03-09T20:00:00", + "2023-03-09T22:00:00", + "2023-03-10T00:00:00", + "2023-03-10T02:00:00", + "2023-03-10T04:00:00", + "2023-03-10T06:00:00", + "2023-03-10T08:00:00", + "2023-03-10T10:00:00", + "2023-03-10T12:00:00", + "2023-03-10T14:00:00", + "2023-03-10T16:00:00", + "2023-03-10T18:00:00", + "2023-03-10T20:00:00", + "2023-03-10T22:00:00", + "2023-03-11T00:00:00", + "2023-03-11T02:00:00", + "2023-03-11T04:00:00", + "2023-03-11T06:00:00", + "2023-03-11T08:00:00", + "2023-03-11T10:00:00", + "2023-03-11T12:00:00", + "2023-03-11T14:00:00", + "2023-03-11T16:00:00", + "2023-03-11T18:00:00", + "2023-03-11T20:00:00", + "2023-03-11T22:00:00", + "2023-03-12T00:00:00", + "2023-03-12T02:00:00", + "2023-03-12T04:00:00", + "2023-03-12T06:00:00", + "2023-03-12T08:00:00", + "2023-03-12T10:00:00", + "2023-03-12T12:00:00", + "2023-03-12T14:00:00", + "2023-03-12T16:00:00", + "2023-03-12T18:00:00", + "2023-03-12T20:00:00", + "2023-03-12T22:00:00", + "2023-03-13T00:00:00", + "2023-03-13T02:00:00", + "2023-03-13T04:00:00", + "2023-03-13T06:00:00", + "2023-03-13T08:00:00", + "2023-03-13T10:00:00", + "2023-03-13T12:00:00", + "2023-03-13T14:00:00", + "2023-03-13T16:00:00", + "2023-03-13T18:00:00", + "2023-03-13T20:00:00", + "2023-03-13T22:00:00", + "2023-03-14T00:00:00", + "2023-03-14T02:00:00", + "2023-03-14T04:00:00", + "2023-03-14T06:00:00", + "2023-03-14T08:00:00", + "2023-03-14T10:00:00", + "2023-03-14T12:00:00", + "2023-03-14T14:00:00", + "2023-03-14T16:00:00", + "2023-03-14T18:00:00", + "2023-03-14T20:00:00", + "2023-03-14T22:00:00", + "2023-03-15T00:00:00", + "2023-03-15T02:00:00", + "2023-03-15T04:00:00", + "2023-03-15T06:00:00", + "2023-03-15T08:00:00", + "2023-03-15T10:00:00", + "2023-03-15T12:00:00", + "2023-03-15T14:00:00", + "2023-03-15T16:00:00", + "2023-03-15T18:00:00", + "2023-03-15T20:00:00", + "2023-03-15T22:00:00", + "2023-03-16T00:00:00", + "2023-03-16T02:00:00", + "2023-03-16T04:00:00", + "2023-03-16T06:00:00", + "2023-03-16T08:00:00", + "2023-03-16T10:00:00", + "2023-03-16T12:00:00", + "2023-03-16T14:00:00", + "2023-03-16T16:00:00", + "2023-03-16T18:00:00", + "2023-03-16T20:00:00", + "2023-03-16T22:00:00", + "2023-03-17T00:00:00", + "2023-03-17T02:00:00", + "2023-03-17T04:00:00", + "2023-03-17T06:00:00", + "2023-03-17T08:00:00", + "2023-03-17T10:00:00", + "2023-03-17T12:00:00", + "2023-03-17T14:00:00", + "2023-03-17T16:00:00", + "2023-03-17T18:00:00", + "2023-03-17T20:00:00", + "2023-03-17T22:00:00", + "2023-03-18T00:00:00", + "2023-03-18T02:00:00", + "2023-03-18T04:00:00", + "2023-03-18T06:00:00", + "2023-03-18T08:00:00", + "2023-03-18T10:00:00", + "2023-03-18T12:00:00", + "2023-03-18T14:00:00", + "2023-03-18T16:00:00", + "2023-03-18T18:00:00", + "2023-03-18T20:00:00", + "2023-03-18T22:00:00", + "2023-03-19T00:00:00", + "2023-03-19T02:00:00", + "2023-03-19T04:00:00", + "2023-03-19T06:00:00", + "2023-03-19T08:00:00", + "2023-03-19T10:00:00", + "2023-03-19T12:00:00", + "2023-03-19T14:00:00", + "2023-03-19T16:00:00", + "2023-03-19T18:00:00", + "2023-03-19T20:00:00", + "2023-03-19T22:00:00", + "2023-03-20T00:00:00", + "2023-03-20T02:00:00", + "2023-03-20T04:00:00", + "2023-03-20T06:00:00", + "2023-03-20T08:00:00", + "2023-03-20T10:00:00", + "2023-03-20T12:00:00", + "2023-03-20T14:00:00", + "2023-03-20T16:00:00", + "2023-03-20T18:00:00", + "2023-03-20T20:00:00", + "2023-03-20T22:00:00", + "2023-03-21T00:00:00", + "2023-03-21T02:00:00", + "2023-03-21T04:00:00", + "2023-03-21T06:00:00", + "2023-03-21T08:00:00", + "2023-03-21T10:00:00", + "2023-03-21T12:00:00", + "2023-03-21T14:00:00", + "2023-03-21T16:00:00", + "2023-03-21T18:00:00", + "2023-03-21T20:00:00", + "2023-03-21T22:00:00", + "2023-03-22T00:00:00", + "2023-03-22T02:00:00", + "2023-03-22T04:00:00", + "2023-03-22T06:00:00", + "2023-03-22T08:00:00", + "2023-03-22T10:00:00", + "2023-03-22T12:00:00", + "2023-03-22T14:00:00", + "2023-03-22T16:00:00", + "2023-03-22T18:00:00", + "2023-03-22T20:00:00", + "2023-03-22T22:00:00", + "2023-03-23T00:00:00", + "2023-03-23T02:00:00", + "2023-03-23T04:00:00", + "2023-03-23T06:00:00", + "2023-03-23T08:00:00", + "2023-03-23T10:00:00", + "2023-03-23T12:00:00", + "2023-03-23T14:00:00", + "2023-03-23T16:00:00", + "2023-03-23T18:00:00", + "2023-03-23T20:00:00", + "2023-03-23T22:00:00", + "2023-03-24T00:00:00", + "2023-03-24T02:00:00", + "2023-03-24T04:00:00", + "2023-03-24T06:00:00", + "2023-03-24T08:00:00", + "2023-03-24T10:00:00", + "2023-03-24T12:00:00", + "2023-03-24T14:00:00", + "2023-03-24T16:00:00", + "2023-03-24T18:00:00", + "2023-03-24T20:00:00", + "2023-03-24T22:00:00", + "2023-03-25T00:00:00", + "2023-03-25T02:00:00", + "2023-03-25T04:00:00", + "2023-03-25T06:00:00", + "2023-03-25T08:00:00", + "2023-03-25T10:00:00", + "2023-03-25T12:00:00", + "2023-03-25T14:00:00", + "2023-03-25T16:00:00", + "2023-03-25T18:00:00", + "2023-03-25T20:00:00", + "2023-03-25T22:00:00", + "2023-03-26T00:00:00", + "2023-03-26T02:00:00", + "2023-03-26T04:00:00", + "2023-03-26T06:00:00", + "2023-03-26T08:00:00", + "2023-03-26T10:00:00", + "2023-03-26T12:00:00", + "2023-03-26T14:00:00", + "2023-03-26T16:00:00", + "2023-03-26T18:00:00", + "2023-03-26T20:00:00", + "2023-03-26T22:00:00", + "2023-03-27T00:00:00", + "2023-03-27T02:00:00", + "2023-03-27T04:00:00", + "2023-03-27T06:00:00", + "2023-03-27T08:00:00", + "2023-03-27T10:00:00", + "2023-03-27T12:00:00", + "2023-03-27T14:00:00", + "2023-03-27T16:00:00", + "2023-03-27T18:00:00", + "2023-03-27T20:00:00", + "2023-03-27T22:00:00", + "2023-03-28T00:00:00", + "2023-03-28T02:00:00", + "2023-03-28T04:00:00", + "2023-03-28T06:00:00", + "2023-03-28T08:00:00", + "2023-03-28T10:00:00", + "2023-03-28T12:00:00", + "2023-03-28T14:00:00", + "2023-03-28T16:00:00", + "2023-03-28T18:00:00", + "2023-03-28T20:00:00", + "2023-03-28T22:00:00", + "2023-03-29T00:00:00", + "2023-03-29T02:00:00", + "2023-03-29T04:00:00", + "2023-03-29T06:00:00", + "2023-03-29T08:00:00", + "2023-03-29T10:00:00", + "2023-03-29T12:00:00", + "2023-03-29T14:00:00", + "2023-03-29T16:00:00", + "2023-03-29T18:00:00", + "2023-03-29T20:00:00", + "2023-03-29T22:00:00", + "2023-03-30T00:00:00", + "2023-03-30T02:00:00", + "2023-03-30T04:00:00", + "2023-03-30T06:00:00", + "2023-03-30T08:00:00", + "2023-03-30T10:00:00", + "2023-03-30T12:00:00", + "2023-03-30T14:00:00", + "2023-03-30T16:00:00", + "2023-03-30T18:00:00", + "2023-03-30T20:00:00", + "2023-03-30T22:00:00", + "2023-03-31T00:00:00", + "2023-03-31T02:00:00", + "2023-03-31T04:00:00", + "2023-03-31T06:00:00", + "2023-03-31T08:00:00", + "2023-03-31T10:00:00", + "2023-03-31T12:00:00", + "2023-03-31T14:00:00", + "2023-03-31T16:00:00", + "2023-03-31T18:00:00", + "2023-03-31T20:00:00", + "2023-03-31T22:00:00", + "2023-04-01T00:00:00", + "2023-04-01T02:00:00", + "2023-04-01T04:00:00", + "2023-04-01T06:00:00", + "2023-04-01T08:00:00", + "2023-04-01T10:00:00", + "2023-04-01T12:00:00", + "2023-04-01T14:00:00", + "2023-04-01T16:00:00", + "2023-04-01T18:00:00", + "2023-04-01T20:00:00", + "2023-04-01T22:00:00", + "2023-04-02T00:00:00", + "2023-04-02T02:00:00", + "2023-04-02T04:00:00", + "2023-04-02T06:00:00", + "2023-04-02T08:00:00", + "2023-04-02T10:00:00", + "2023-04-02T12:00:00", + "2023-04-02T14:00:00", + "2023-04-02T16:00:00", + "2023-04-02T18:00:00", + "2023-04-02T20:00:00", + "2023-04-02T22:00:00", + "2023-04-03T00:00:00", + "2023-04-03T02:00:00", + "2023-04-03T04:00:00", + "2023-04-03T06:00:00", + "2023-04-03T08:00:00", + "2023-04-03T10:00:00", + "2023-04-03T12:00:00", + "2023-04-03T14:00:00", + "2023-04-03T16:00:00", + "2023-04-03T18:00:00", + "2023-04-03T20:00:00", + "2023-04-03T22:00:00", + "2023-04-04T00:00:00", + "2023-04-04T02:00:00", + "2023-04-04T04:00:00", + "2023-04-04T06:00:00", + "2023-04-04T08:00:00", + "2023-04-04T10:00:00", + "2023-04-04T12:00:00", + "2023-04-04T14:00:00", + "2023-04-04T16:00:00", + "2023-04-04T18:00:00", + "2023-04-04T20:00:00", + "2023-04-04T22:00:00", + "2023-04-05T00:00:00", + "2023-04-05T02:00:00", + "2023-04-05T04:00:00", + "2023-04-05T06:00:00", + "2023-04-05T08:00:00", + "2023-04-05T10:00:00", + "2023-04-05T12:00:00", + "2023-04-05T14:00:00", + "2023-04-05T16:00:00", + "2023-04-05T18:00:00", + "2023-04-05T20:00:00", + "2023-04-05T22:00:00", + "2023-04-06T00:00:00", + "2023-04-06T02:00:00", + "2023-04-06T04:00:00", + "2023-04-06T06:00:00", + "2023-04-06T08:00:00", + "2023-04-06T10:00:00", + "2023-04-06T12:00:00", + "2023-04-06T14:00:00", + "2023-04-06T16:00:00", + "2023-04-06T18:00:00", + "2023-04-06T20:00:00", + "2023-04-06T22:00:00", + "2023-04-07T00:00:00", + "2023-04-07T02:00:00", + "2023-04-07T04:00:00", + "2023-04-07T06:00:00", + "2023-04-07T08:00:00", + "2023-04-07T10:00:00", + "2023-04-07T12:00:00", + "2023-04-07T14:00:00", + "2023-04-07T16:00:00", + "2023-04-07T18:00:00", + "2023-04-07T20:00:00", + "2023-04-07T22:00:00", + "2023-04-08T00:00:00", + "2023-04-08T02:00:00", + "2023-04-08T04:00:00", + "2023-04-08T06:00:00", + "2023-04-08T08:00:00", + "2023-04-08T10:00:00", + "2023-04-08T12:00:00", + "2023-04-08T14:00:00", + "2023-04-08T16:00:00", + "2023-04-08T18:00:00", + "2023-04-08T20:00:00", + "2023-04-08T22:00:00", + "2023-04-09T00:00:00", + "2023-04-09T02:00:00", + "2023-04-09T04:00:00", + "2023-04-09T06:00:00", + "2023-04-09T08:00:00", + "2023-04-09T10:00:00", + "2023-04-09T12:00:00", + "2023-04-09T14:00:00", + "2023-04-09T16:00:00", + "2023-04-09T18:00:00", + "2023-04-09T20:00:00", + "2023-04-09T22:00:00", + "2023-04-10T00:00:00", + "2023-04-10T02:00:00", + "2023-04-10T04:00:00", + "2023-04-10T06:00:00", + "2023-04-10T08:00:00", + "2023-04-10T10:00:00", + "2023-04-10T12:00:00", + "2023-04-10T14:00:00", + "2023-04-10T16:00:00", + "2023-04-10T18:00:00", + "2023-04-10T20:00:00", + "2023-04-10T22:00:00", + "2023-04-11T00:00:00", + "2023-04-11T02:00:00", + "2023-04-11T04:00:00", + "2023-04-11T06:00:00", + "2023-04-11T08:00:00", + "2023-04-11T10:00:00", + "2023-04-11T12:00:00", + "2023-04-11T14:00:00", + "2023-04-11T16:00:00", + "2023-04-11T18:00:00", + "2023-04-11T20:00:00", + "2023-04-11T22:00:00", + "2023-04-12T00:00:00", + "2023-04-12T02:00:00", + "2023-04-12T04:00:00", + "2023-04-12T06:00:00", + "2023-04-12T08:00:00", + "2023-04-12T10:00:00", + "2023-04-12T12:00:00", + "2023-04-12T14:00:00", + "2023-04-12T16:00:00", + "2023-04-12T18:00:00", + "2023-04-12T20:00:00", + "2023-04-12T22:00:00", + "2023-04-13T00:00:00", + "2023-04-13T02:00:00", + "2023-04-13T04:00:00", + "2023-04-13T06:00:00", + "2023-04-13T08:00:00", + "2023-04-13T10:00:00", + "2023-04-13T12:00:00", + "2023-04-13T14:00:00", + "2023-04-13T16:00:00", + "2023-04-13T18:00:00", + "2023-04-13T20:00:00", + "2023-04-13T22:00:00", + "2023-04-14T00:00:00", + "2023-04-14T02:00:00", + "2023-04-14T04:00:00", + "2023-04-14T06:00:00", + "2023-04-14T08:00:00", + "2023-04-14T10:00:00", + "2023-04-14T12:00:00", + "2023-04-14T14:00:00", + "2023-04-14T16:00:00", + "2023-04-14T18:00:00", + "2023-04-14T20:00:00", + "2023-04-14T22:00:00", + "2023-04-15T00:00:00", + "2023-04-15T02:00:00", + "2023-04-15T04:00:00", + "2023-04-15T06:00:00", + "2023-04-15T08:00:00", + "2023-04-15T10:00:00", + "2023-04-15T12:00:00", + "2023-04-15T14:00:00", + "2023-04-15T16:00:00", + "2023-04-15T18:00:00", + "2023-04-15T20:00:00", + "2023-04-15T22:00:00", + "2023-04-16T00:00:00", + "2023-04-16T04:00:00", + "2023-04-16T06:00:00", + "2023-04-16T08:00:00", + "2023-04-16T10:00:00", + "2023-04-16T12:00:00", + "2023-04-16T14:00:00", + "2023-04-16T16:00:00", + "2023-04-16T18:00:00", + "2023-04-16T20:00:00", + "2023-04-16T22:00:00", + "2023-04-17T00:00:00", + "2023-04-17T02:00:00", + "2023-04-17T04:00:00", + "2023-04-17T06:00:00", + "2023-04-17T08:00:00", + "2023-04-17T10:00:00", + "2023-04-17T12:00:00", + "2023-04-17T14:00:00", + "2023-04-17T16:00:00", + "2023-04-17T18:00:00", + "2023-04-17T20:00:00", + "2023-04-17T22:00:00", + "2023-04-18T00:00:00", + "2023-04-18T02:00:00", + "2023-04-18T04:00:00", + "2023-04-18T06:00:00", + "2023-04-18T08:00:00", + "2023-04-18T10:00:00", + "2023-04-18T12:00:00", + "2023-04-18T14:00:00", + "2023-04-18T16:00:00", + "2023-04-18T18:00:00", + "2023-04-18T20:00:00", + "2023-04-18T22:00:00", + "2023-04-19T00:00:00", + "2023-04-19T02:00:00", + "2023-04-19T04:00:00", + "2023-04-19T06:00:00", + "2023-04-19T08:00:00", + "2023-04-19T10:00:00", + "2023-04-19T12:00:00", + "2023-04-19T14:00:00", + "2023-04-19T16:00:00", + "2023-04-19T18:00:00", + "2023-04-19T20:00:00", + "2023-04-19T22:00:00", + "2023-04-20T00:00:00", + "2023-04-20T02:00:00", + "2023-04-20T04:00:00", + "2023-04-20T06:00:00", + "2023-04-20T08:00:00", + "2023-04-20T10:00:00", + "2023-04-20T12:00:00", + "2023-04-20T14:00:00", + "2023-04-20T16:00:00", + "2023-04-20T18:00:00", + "2023-04-20T20:00:00", + "2023-04-20T22:00:00", + "2023-04-21T00:00:00", + "2023-04-21T02:00:00", + "2023-04-21T04:00:00", + "2023-04-21T06:00:00", + "2023-04-21T08:00:00", + "2023-04-21T10:00:00", + "2023-04-21T12:00:00", + "2023-04-21T14:00:00", + "2023-04-21T16:00:00", + "2023-04-21T18:00:00", + "2023-04-21T20:00:00", + "2023-04-21T22:00:00", + "2023-04-22T00:00:00", + "2023-04-22T02:00:00", + "2023-04-22T04:00:00", + "2023-04-22T06:00:00", + "2023-04-22T08:00:00", + "2023-04-22T10:00:00", + "2023-04-22T12:00:00", + "2023-04-22T14:00:00", + "2023-04-22T16:00:00", + "2023-04-22T18:00:00", + "2023-04-22T20:00:00", + "2023-04-22T22:00:00", + "2023-04-23T00:00:00", + "2023-04-23T02:00:00", + "2023-04-23T04:00:00", + "2023-04-23T06:00:00", + "2023-04-23T08:00:00", + "2023-04-23T10:00:00", + "2023-04-23T12:00:00", + "2023-04-23T14:00:00", + "2023-04-23T16:00:00", + "2023-04-23T18:00:00", + "2023-04-23T20:00:00", + "2023-04-23T22:00:00", + "2023-04-24T00:00:00", + "2023-04-24T02:00:00", + "2023-04-24T04:00:00", + "2023-04-24T06:00:00", + "2023-04-24T08:00:00", + "2023-04-24T10:00:00", + "2023-04-24T12:00:00", + "2023-04-24T14:00:00", + "2023-04-24T16:00:00", + "2023-04-24T18:00:00", + "2023-04-24T20:00:00", + "2023-04-24T22:00:00", + "2023-04-25T00:00:00", + "2023-04-25T02:00:00", + "2023-04-25T04:00:00", + "2023-04-25T06:00:00", + "2023-04-25T08:00:00", + "2023-04-25T10:00:00", + "2023-04-25T12:00:00", + "2023-04-25T14:00:00", + "2023-04-25T16:00:00", + "2023-04-25T18:00:00", + "2023-04-25T20:00:00", + "2023-04-25T22:00:00", + "2023-04-26T00:00:00", + "2023-04-26T02:00:00", + "2023-04-26T04:00:00", + "2023-04-26T06:00:00", + "2023-04-26T08:00:00", + "2023-04-26T10:00:00", + "2023-04-26T12:00:00", + "2023-04-26T14:00:00", + "2023-04-26T16:00:00", + "2023-04-26T18:00:00", + "2023-04-26T20:00:00", + "2023-04-26T22:00:00", + "2023-04-27T00:00:00", + "2023-04-27T02:00:00", + "2023-04-27T04:00:00", + "2023-04-27T06:00:00", + "2023-04-27T08:00:00", + "2023-04-27T10:00:00", + "2023-04-27T12:00:00", + "2023-04-27T14:00:00", + "2023-04-27T16:00:00", + "2023-04-27T18:00:00", + "2023-04-27T20:00:00", + "2023-04-27T22:00:00", + "2023-04-28T00:00:00", + "2023-04-28T02:00:00", + "2023-04-28T04:00:00", + "2023-04-28T06:00:00", + "2023-04-28T08:00:00", + "2023-04-28T10:00:00", + "2023-04-28T12:00:00", + "2023-04-28T14:00:00", + "2023-04-28T16:00:00", + "2023-04-28T18:00:00", + "2023-04-28T20:00:00", + "2023-04-28T22:00:00", + "2023-04-29T00:00:00", + "2023-04-29T02:00:00", + "2023-04-29T04:00:00", + "2023-04-29T06:00:00", + "2023-04-29T08:00:00", + "2023-04-29T10:00:00", + "2023-04-29T12:00:00", + "2023-04-29T14:00:00", + "2023-04-29T16:00:00", + "2023-04-29T18:00:00", + "2023-04-29T20:00:00", + "2023-04-29T22:00:00", + "2023-04-30T00:00:00", + "2023-04-30T02:00:00", + "2023-04-30T04:00:00", + "2023-04-30T06:00:00", + "2023-04-30T08:00:00", + "2023-04-30T10:00:00", + "2023-04-30T12:00:00", + "2023-04-30T14:00:00", + "2023-04-30T16:00:00", + "2023-04-30T18:00:00", + "2023-04-30T20:00:00", + "2023-04-30T22:00:00", + "2023-05-01T00:00:00", + "2023-05-01T02:00:00", + "2023-05-01T04:00:00", + "2023-05-01T06:00:00", + "2023-05-01T08:00:00", + "2023-05-01T10:00:00", + "2023-05-01T12:00:00", + "2023-05-01T14:00:00", + "2023-05-01T16:00:00", + "2023-05-01T18:00:00", + "2023-05-01T20:00:00", + "2023-05-01T22:00:00", + "2023-05-02T00:00:00", + "2023-05-02T02:00:00", + "2023-05-02T04:00:00", + "2023-05-02T06:00:00", + "2023-05-02T08:00:00", + "2023-05-02T10:00:00", + "2023-05-02T12:00:00", + "2023-05-02T14:00:00", + "2023-05-02T16:00:00", + "2023-05-02T18:00:00", + "2023-05-02T20:00:00", + "2023-05-02T22:00:00", + "2023-05-03T00:00:00", + "2023-05-03T02:00:00", + "2023-05-03T04:00:00", + "2023-05-03T06:00:00", + "2023-05-03T08:00:00", + "2023-05-03T10:00:00", + "2023-05-03T12:00:00", + "2023-05-03T14:00:00", + "2023-05-03T16:00:00", + "2023-05-03T18:00:00", + "2023-05-03T20:00:00", + "2023-05-03T22:00:00", + "2023-05-04T00:00:00", + "2023-05-04T02:00:00", + "2023-05-04T04:00:00", + "2023-05-04T06:00:00", + "2023-05-04T08:00:00", + "2023-05-04T10:00:00", + "2023-05-04T12:00:00", + "2023-05-04T14:00:00", + "2023-05-04T16:00:00", + "2023-05-04T18:00:00", + "2023-05-04T20:00:00", + "2023-05-04T22:00:00", + "2023-05-05T00:00:00", + "2023-05-05T02:00:00", + "2023-05-05T04:00:00", + "2023-05-05T06:00:00", + "2023-05-05T08:00:00", + "2023-05-05T10:00:00", + "2023-05-05T12:00:00", + "2023-05-05T14:00:00", + "2023-05-05T16:00:00", + "2023-05-05T18:00:00", + "2023-05-05T20:00:00", + "2023-05-05T22:00:00", + "2023-05-06T00:00:00", + "2023-05-06T02:00:00", + "2023-05-06T04:00:00", + "2023-05-06T06:00:00", + "2023-05-06T08:00:00", + "2023-05-06T10:00:00", + "2023-05-06T12:00:00", + "2023-05-06T14:00:00", + "2023-05-06T16:00:00", + "2023-05-06T18:00:00", + "2023-05-06T20:00:00", + "2023-05-06T22:00:00", + "2023-05-07T00:00:00", + "2023-05-07T02:00:00", + "2023-05-07T04:00:00", + "2023-05-07T06:00:00", + "2023-05-07T08:00:00", + "2023-05-07T10:00:00", + "2023-05-07T12:00:00", + "2023-05-07T14:00:00", + "2023-05-07T16:00:00", + "2023-05-07T18:00:00", + "2023-05-07T20:00:00", + "2023-05-07T22:00:00", + "2023-05-08T00:00:00", + "2023-05-08T02:00:00", + "2023-05-08T04:00:00", + "2023-05-08T06:00:00", + "2023-05-08T08:00:00", + "2023-05-08T10:00:00", + "2023-05-08T12:00:00", + "2023-05-08T14:00:00", + "2023-05-08T16:00:00", + "2023-05-08T18:00:00", + "2023-05-08T20:00:00", + "2023-05-08T22:00:00", + "2023-05-09T00:00:00", + "2023-05-09T02:00:00", + "2023-05-09T04:00:00", + "2023-05-09T06:00:00", + "2023-05-09T08:00:00", + "2023-05-09T10:00:00", + "2023-05-09T12:00:00", + "2023-05-09T14:00:00", + "2023-05-09T16:00:00", + "2023-05-09T18:00:00", + "2023-05-09T20:00:00", + "2023-05-09T22:00:00", + "2023-05-10T00:00:00", + "2023-05-10T02:00:00", + "2023-05-10T04:00:00", + "2023-05-10T06:00:00", + "2023-05-10T08:00:00", + "2023-05-10T10:00:00", + "2023-05-10T12:00:00", + "2023-05-10T14:00:00", + "2023-05-10T16:00:00", + "2023-05-10T18:00:00", + "2023-05-10T20:00:00", + "2023-05-10T22:00:00", + "2023-05-11T00:00:00", + "2023-05-11T02:00:00", + "2023-05-11T04:00:00", + "2023-05-11T06:00:00", + "2023-05-11T08:00:00", + "2023-05-11T10:00:00", + "2023-05-11T12:00:00", + "2023-05-11T14:00:00", + "2023-05-11T16:00:00", + "2023-05-11T18:00:00", + "2023-05-11T20:00:00", + "2023-05-11T22:00:00", + "2023-05-12T00:00:00", + "2023-05-12T02:00:00", + "2023-05-12T04:00:00", + "2023-05-12T06:00:00", + "2023-05-12T08:00:00", + "2023-05-12T10:00:00", + "2023-05-12T12:00:00", + "2023-05-12T14:00:00", + "2023-05-12T16:00:00", + "2023-05-12T18:00:00", + "2023-05-12T20:00:00", + "2023-05-12T22:00:00", + "2023-05-13T00:00:00", + "2023-05-13T02:00:00", + "2023-05-13T04:00:00", + "2023-05-13T06:00:00", + "2023-05-13T08:00:00", + "2023-05-13T10:00:00", + "2023-05-13T12:00:00", + "2023-05-13T14:00:00", + "2023-05-13T16:00:00", + "2023-05-13T18:00:00", + "2023-05-13T20:00:00", + "2023-05-13T22:00:00", + "2023-05-14T00:00:00", + "2023-05-14T02:00:00", + "2023-05-14T04:00:00", + "2023-05-14T06:00:00", + "2023-05-14T08:00:00", + "2023-05-14T10:00:00", + "2023-05-14T12:00:00", + "2023-05-14T14:00:00", + "2023-05-14T16:00:00", + "2023-05-14T18:00:00", + "2023-05-14T20:00:00", + "2023-05-14T22:00:00", + "2023-05-15T00:00:00", + "2023-05-15T02:00:00", + "2023-05-15T04:00:00", + "2023-05-15T06:00:00", + "2023-05-15T08:00:00", + "2023-05-15T10:00:00", + "2023-05-15T12:00:00", + "2023-05-15T14:00:00", + "2023-05-15T16:00:00", + "2023-05-15T18:00:00", + "2023-05-15T20:00:00", + "2023-05-15T22:00:00", + "2023-05-16T00:00:00", + "2023-05-16T02:00:00", + "2023-05-16T04:00:00", + "2023-05-16T06:00:00", + "2023-05-16T08:00:00", + "2023-05-16T10:00:00", + "2023-05-16T12:00:00", + "2023-05-16T14:00:00", + "2023-05-16T16:00:00", + "2023-05-16T18:00:00", + "2023-05-16T20:00:00", + "2023-05-16T22:00:00", + "2023-05-17T00:00:00", + "2023-05-17T02:00:00", + "2023-05-17T04:00:00", + "2023-05-17T06:00:00", + "2023-05-17T08:00:00", + "2023-05-17T10:00:00", + "2023-05-17T12:00:00", + "2023-05-17T14:00:00", + "2023-05-17T16:00:00", + "2023-05-17T18:00:00", + "2023-05-17T20:00:00", + "2023-05-17T22:00:00", + "2023-05-18T00:00:00", + "2023-05-18T02:00:00", + "2023-05-18T04:00:00", + "2023-05-18T06:00:00", + "2023-05-18T08:00:00", + "2023-05-18T10:00:00", + "2023-05-18T12:00:00", + "2023-05-18T14:00:00", + "2023-05-18T16:00:00", + "2023-05-18T18:00:00", + "2023-05-18T20:00:00", + "2023-05-18T22:00:00", + "2023-05-19T00:00:00", + "2023-05-19T02:00:00", + "2023-05-19T04:00:00", + "2023-05-19T06:00:00", + "2023-05-19T08:00:00", + "2023-05-19T10:00:00", + "2023-05-19T12:00:00", + "2023-05-19T14:00:00", + "2023-05-19T16:00:00", + "2023-05-19T18:00:00", + "2023-05-19T20:00:00", + "2023-05-19T22:00:00", + "2023-05-20T00:00:00", + "2023-05-20T02:00:00", + "2023-05-20T04:00:00", + "2023-05-20T06:00:00", + "2023-05-20T08:00:00", + "2023-05-20T10:00:00", + "2023-05-20T12:00:00", + "2023-05-20T14:00:00", + "2023-05-20T16:00:00", + "2023-05-20T18:00:00", + "2023-05-20T20:00:00", + "2023-05-20T22:00:00", + "2023-05-21T00:00:00", + "2023-05-21T02:00:00", + "2023-05-21T04:00:00", + "2023-05-21T06:00:00", + "2023-05-21T08:00:00", + "2023-05-21T10:00:00", + "2023-05-21T12:00:00", + "2023-05-21T14:00:00", + "2023-05-21T16:00:00", + "2023-05-21T18:00:00", + "2023-05-21T20:00:00", + "2023-05-21T22:00:00", + "2023-05-22T00:00:00", + "2023-05-22T02:00:00", + "2023-05-22T04:00:00", + "2023-05-22T06:00:00", + "2023-05-22T08:00:00", + "2023-05-22T10:00:00", + "2023-05-22T12:00:00", + "2023-05-22T14:00:00", + "2023-05-22T16:00:00", + "2023-05-22T18:00:00", + "2023-05-22T20:00:00", + "2023-05-22T22:00:00", + "2023-05-23T00:00:00", + "2023-05-23T02:00:00", + "2023-05-23T04:00:00", + "2023-05-23T06:00:00", + "2023-05-23T08:00:00", + "2023-05-23T10:00:00", + "2023-05-23T12:00:00", + "2023-05-23T14:00:00", + "2023-05-23T16:00:00", + "2023-05-23T18:00:00", + "2023-05-23T20:00:00", + "2023-05-23T22:00:00", + "2023-05-24T00:00:00", + "2023-05-24T02:00:00", + "2023-05-24T04:00:00", + "2023-05-24T06:00:00", + "2023-05-24T08:00:00", + "2023-05-24T10:00:00", + "2023-05-24T12:00:00", + "2023-05-24T14:00:00", + "2023-05-24T16:00:00", + "2023-05-24T18:00:00", + "2023-05-24T20:00:00", + "2023-05-24T22:00:00", + "2023-05-25T00:00:00", + "2023-05-25T02:00:00", + "2023-05-25T04:00:00", + "2023-05-25T06:00:00", + "2023-05-25T08:00:00", + "2023-05-25T10:00:00", + "2023-05-25T12:00:00", + "2023-05-25T14:00:00", + "2023-05-25T16:00:00", + "2023-05-25T18:00:00", + "2023-05-25T20:00:00", + "2023-05-25T22:00:00", + "2023-05-26T00:00:00", + "2023-05-26T02:00:00", + "2023-05-26T04:00:00", + "2023-05-26T06:00:00", + "2023-05-26T08:00:00", + "2023-05-26T10:00:00", + "2023-05-26T12:00:00", + "2023-05-26T14:00:00", + "2023-05-26T16:00:00", + "2023-05-26T18:00:00", + "2023-05-26T20:00:00", + "2023-05-26T22:00:00", + "2023-05-27T00:00:00", + "2023-05-27T02:00:00", + "2023-05-27T04:00:00", + "2023-05-27T06:00:00", + "2023-05-27T08:00:00", + "2023-05-27T10:00:00", + "2023-05-27T12:00:00", + "2023-05-27T14:00:00", + "2023-05-27T16:00:00", + "2023-05-27T18:00:00", + "2023-05-27T20:00:00", + "2023-05-27T22:00:00", + "2023-05-28T00:00:00", + "2023-05-28T02:00:00", + "2023-05-28T04:00:00", + "2023-05-28T06:00:00", + "2023-05-28T08:00:00", + "2023-05-28T10:00:00", + "2023-05-28T12:00:00", + "2023-05-28T14:00:00", + "2023-05-28T16:00:00", + "2023-05-28T18:00:00", + "2023-05-28T20:00:00", + "2023-05-28T22:00:00", + "2023-05-29T00:00:00", + "2023-05-29T02:00:00", + "2023-05-29T04:00:00", + "2023-05-29T06:00:00", + "2023-05-29T08:00:00", + "2023-05-29T10:00:00", + "2023-05-29T12:00:00", + "2023-05-29T14:00:00", + "2023-05-29T16:00:00", + "2023-05-29T18:00:00", + "2023-05-29T20:00:00", + "2023-05-29T22:00:00", + "2023-05-30T00:00:00", + "2023-05-30T02:00:00", + "2023-05-30T04:00:00", + "2023-05-30T06:00:00", + "2023-05-30T08:00:00", + "2023-05-30T10:00:00", + "2023-05-30T12:00:00", + "2023-05-30T14:00:00", + "2023-05-30T16:00:00", + "2023-05-30T18:00:00", + "2023-05-30T20:00:00", + "2023-05-30T22:00:00", + "2023-05-31T00:00:00", + "2023-05-31T02:00:00", + "2023-05-31T04:00:00", + "2023-05-31T06:00:00", + "2023-05-31T08:00:00", + "2023-05-31T10:00:00", + "2023-05-31T12:00:00", + "2023-05-31T14:00:00", + "2023-05-31T16:00:00", + "2023-05-31T18:00:00", + "2023-05-31T20:00:00", + "2023-05-31T22:00:00", + "2023-06-01T00:00:00" + ], + "y": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 15897.0, + null, + null, + null, + 15821.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 21206.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 21248.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 20992.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 22352.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26296.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25679.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25000.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26128.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25755.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26894.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 26801.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25865.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 25639.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 24781.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 24903.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 24901.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 24458.0, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "type": "scatter", + "xaxis": "x", + "yaxis": "y" + } + ], + "layout": { + "template": { + "data": { + "histogram2dcontour": [ + { + "type": "histogram2dcontour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "choropleth": [ + { + "type": "choropleth", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "histogram2d": [ + { + "type": "histogram2d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmap": [ + { + "type": "heatmap", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmapgl": [ + { + "type": "heatmapgl", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "contourcarpet": [ + { + "type": "contourcarpet", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "contour": [ + { + "type": "contour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "surface": [ + { + "type": "surface", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "mesh3d": [ + { + "type": "mesh3d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "parcoords": [ + { + "type": "parcoords", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolargl": [ + { + "type": "scatterpolargl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "scattergeo": [ + { + "type": "scattergeo", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolar": [ + { + "type": "scatterpolar", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "scattergl": [ + { + "type": "scattergl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatter3d": [ + { + "type": "scatter3d", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattermapbox": [ + { + "type": "scattermapbox", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterternary": [ + { + "type": "scatterternary", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattercarpet": [ + { + "type": "scattercarpet", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ] + }, + "layout": { + "autotypenumbers": "strict", + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "hovermode": "closest", + "hoverlabel": { + "align": "left" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "bgcolor": "#E5ECF6", + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "ternary": { + "bgcolor": "#E5ECF6", + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ] + }, + "xaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "automargin": true, + "zerolinewidth": 2 + }, + "yaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "automargin": true, + "zerolinewidth": 2 + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "geo": { + "bgcolor": "white", + "landcolor": "#E5ECF6", + "subunitcolor": "white", + "showland": true, + "showlakes": true, + "lakecolor": "white" + }, + "title": { + "x": 0.05 + }, + "mapbox": { + "style": "light" + } + } + }, + "xaxis": { + "anchor": "y", + "domain": [ + 0.0, + 1.0 + ], + "title": { + "text": "Date" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0.0, + 1.0 + ], + "title": { + "text": "Prices up turn" + } + }, + "title": { + "text": "Up turn backtest date range trades overview for best performing algorithm" + }, + "height": 600, + "width": 800 + }, + "config": { + "plotlyServerURL": "https://plot.ly" + } + }, + "text/html": "
" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from investing_algorithm_framework import pretty_print_backtest, create_trade_exit_markers_chart, create_trade_entry_markers_chart\n", + "import pandas as pd\n", + "\n", + "# Set the weights for the evaluation criteria, where we prioritize the profit over the growth\n", + "algorithm_name = evaluation.rank(weight_profit=0.7, weight_growth=0.3)\n", + "print(f\"The winning algorithm is {algorithm_name}\")\n", + "\n", + "# Highlight the winning strategy by displaying the backtest result of the up turn date range\n", + "up_turn_report = evaluation.get_report(name=algorithm_name, backtest_date_range=up_turn_date_range)\n", + "pretty_print_backtest(up_turn_report)\n", + "\n", + "from plotly.subplots import make_subplots\n", + "fig = make_subplots(rows=1, cols=1, shared_xaxes=False, vertical_spacing=0.02)\n", + "df_up_turn[\"Datetime\"] = pd.to_datetime(df_up_turn.index)\n", + "df_up_turn.set_index('Datetime', inplace=True)\n", + "\n", + "fig.add_trace(create_prices_graph(df_up_turn, name=\"Close price up turn\", color=\"blue\"), row=1, col=1)\n", + "fig.add_trace(create_trade_entry_markers_chart(df_up_turn, up_turn_report.trades), row=1, col=1)\n", + "fig.add_trace(create_trade_exit_markers_chart(df_up_turn, up_turn_report.trades), row=1, col=1)\n", + "fig.update_layout(height=600, width=800, title_text=\"Up turn backtest date range trades overview for best performing algorithm\")\n", + "fig.update_xaxes(title_text=\"Date\", row=1, col=1)\n", + "fig.update_yaxes(title_text=\"Prices up turn\", row=1, col=1)\n", + "fig.show()" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 6: Optimizing the winning strategy with different parameters" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 12, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[93mRunning backtests for date range:\u001B[0m \u001B[92mdown_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 for a total of 4 algorithms.\u001B[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 875.64it/s]\n", + "Running backtest for algorithm with name primary_21_50: 100%|\u001B[32m██████████\u001B[0m| 2173/2173 [00:12<00:00, 170.01it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1153.55it/s]\n", + "Running backtest for algorithm with name primary_21_75: 100%|\u001B[32m██████████\u001B[0m| 2173/2173 [00:10<00:00, 202.24it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 778.24it/s]\n", + "Running backtest for algorithm with name primary_50_100: 100%|\u001B[32m██████████\u001B[0m| 2173/2173 [00:09<00:00, 234.25it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1085.76it/s]\n", + "Running backtest for algorithm with name primary_50_200: 100%|\u001B[32m██████████\u001B[0m| 2173/2173 [00:09<00:00, 231.95it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[93mRunning backtests for date range:\u001B[0m \u001B[92mup_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 for a total of 4 algorithms.\u001B[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 978.04it/s]\n", + "Running backtest for algorithm with name primary_21_50: 100%|\u001B[32m██████████\u001B[0m| 1957/1957 [00:09<00:00, 202.39it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1133.75it/s]\n", + "Running backtest for algorithm with name primary_21_75: 100%|\u001B[32m██████████\u001B[0m| 1957/1957 [00:08<00:00, 218.84it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1178.51it/s]\n", + "Running backtest for algorithm with name primary_50_100: 100%|\u001B[32m██████████\u001B[0m| 1957/1957 [00:07<00:00, 249.54it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 960.23it/s]\n", + "Running backtest for algorithm with name primary_50_200: 100%|\u001B[32m██████████\u001B[0m| 1957/1957 [00:07<00:00, 264.58it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[93mRunning backtests for date range:\u001B[0m \u001B[92msideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 for a total of 4 algorithms.\u001B[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1031.05it/s]\n", + "Running backtest for algorithm with name primary_21_50: 100%|\u001B[32m██████████\u001B[0m| 2569/2569 [00:12<00:00, 209.66it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1356.06it/s]\n", + "Running backtest for algorithm with name primary_21_75: 100%|\u001B[32m██████████\u001B[0m| 2569/2569 [00:11<00:00, 217.44it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 949.69it/s]\n", + "Running backtest for algorithm with name primary_50_100: 100%|\u001B[32m██████████\u001B[0m| 2569/2569 [00:11<00:00, 232.72it/s]\n", + "Preparing backtest market data: 100%|\u001B[32m██████████\u001B[0m| 2/2 [00:00<00:00, 1103.04it/s]\n", + "Running backtest for algorithm with name primary_50_200: 100%|\u001B[32m██████████\u001B[0m| 2569/2569 [00:10<00:00, 240.03it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " :%%%#+- .=*#%%% \u001B[92mBacktest reports evaluation\u001B[0m\n", + " *%%%%%%%+------=*%%%%%%%- \u001B[92m---------------------------\u001B[0m\n", + " *%%%%%%%%%%%%%%%%%%%%%%%- \u001B[93mNumber of reports:\u001B[0m \u001B[92m4 backtest reports\u001B[0m\n", + " .%%%%%%%%%%%%%%%%%%%%%%# \u001B[93mLargest overall profit:\u001B[0m\u001B[92m\u001B[0m\u001B[92m (Algorithm primary_21_50) 121.6183 EUR 12.1618% (up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00)\u001B[0m \n", + " #%%%####%%%%%%%%**#%%%+ \u001B[93mLargest overall growth:\u001B[0m\u001B[92m (Algorithm primary_21_50) 127.5655 EUR 12.7565% (up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00)\u001B[0m\n", + " .:-+*%%%%- \u001B[95m-+..#\u001B[0m%%%+.\u001B[95m+- +\u001B[0m%%%#*=-: \n", + " .:-=*%%%%. \u001B[95m+=\u001B[0m .%%# \u001B[95m-+.-\u001B[0m%%%%=-:.. \n", + " .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: \n", + " +%%%%%%%%%%%%%%%%%%%= \n", + " :++ .=#%%%%%%%%%%%%%*- \n", + " :++: :+%%%%%%#-. \n", + " :++: .%%%%%#= \n", + " :++: .#%%%%%#*= \n", + " :++- :%%%%%%%%%+= \n", + " .++- -%%%%%%%%%%%+= \n", + " .++- .%%%%%%%%%%%%%+= \n", + " .++- *%%%%%%%%%%%%%*+: \n", + " .++- %%%%%%%%%%%%%%#+= \n", + " =++........:::%%%%%%%%%%%%%%*+- \n", + " .=++++++++++**#%%%%%%%%%%%%%++. \n", + " \n", + "\u001B[93mAll profits ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬───────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Profit │ Profit percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_50 │ 121.6183 EUR │ 12.1618% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1127.57 │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_75 │ 120.0602 EUR │ 12.0060% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1126.31 │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_200 │ 84.0464 EUR │ 8.4046% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1085.4 │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_100 │ 54.1972 EUR │ 5.4197% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1055.91 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴───────────────────────────────────────────────────┴───────────────╯\n", + "\u001B[93mAll growths ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬───────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Growth │ Growth percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_50 │ 127.5655 EUR │ 12.7565% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1127.57 │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_75 │ 126.3098 EUR │ 12.6310% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1126.31 │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_200 │ 85.3999 EUR │ 8.5400% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1085.4 │\n", + "├──────────────────┼──────────────┼─────────────────────┼───────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_100 │ 55.9132 EUR │ 5.5913% │ up_turn 2022-12-20 00:00:00 - 2023-06-01 00:00:00 │ 1055.91 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴───────────────────────────────────────────────────┴───────────────╯\n", + "The winning configuration for the up turn backtest date range is primary_21_50\n", + "\n", + " :%%%#+- .=*#%%% \u001B[92mBacktest reports evaluation\u001B[0m\n", + " *%%%%%%%+------=*%%%%%%%- \u001B[92m---------------------------\u001B[0m\n", + " *%%%%%%%%%%%%%%%%%%%%%%%- \u001B[93mNumber of reports:\u001B[0m \u001B[92m4 backtest reports\u001B[0m\n", + " .%%%%%%%%%%%%%%%%%%%%%%# \u001B[93mLargest overall profit:\u001B[0m\u001B[92m\u001B[0m\u001B[92m (Algorithm primary_21_50) -8.5178 EUR -0.8518% (sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00)\u001B[0m \n", + " #%%%####%%%%%%%%**#%%%+ \u001B[93mLargest overall growth:\u001B[0m\u001B[92m (Algorithm primary_21_50) -2.3874 EUR -0.2387% (sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00)\u001B[0m\n", + " .:-+*%%%%- \u001B[95m-+..#\u001B[0m%%%+.\u001B[95m+- +\u001B[0m%%%#*=-: \n", + " .:-=*%%%%. \u001B[95m+=\u001B[0m .%%# \u001B[95m-+.-\u001B[0m%%%%=-:.. \n", + " .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: \n", + " +%%%%%%%%%%%%%%%%%%%= \n", + " :++ .=#%%%%%%%%%%%%%*- \n", + " :++: :+%%%%%%#-. \n", + " :++: .%%%%%#= \n", + " :++: .#%%%%%#*= \n", + " :++- :%%%%%%%%%+= \n", + " .++- -%%%%%%%%%%%+= \n", + " .++- .%%%%%%%%%%%%%+= \n", + " .++- *%%%%%%%%%%%%%*+: \n", + " .++- %%%%%%%%%%%%%%#+= \n", + " =++........:::%%%%%%%%%%%%%%*+- \n", + " .=++++++++++**#%%%%%%%%%%%%%++. \n", + " \n", + "\u001B[93mAll profits ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬────────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Profit │ Profit percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_50 │ -8.5178 EUR │ -0.8518% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 997.613 │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_75 │ -12.4677 EUR │ -1.2468% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 993.279 │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_200 │ -27.2777 EUR │ -2.7278% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 975.484 │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_100 │ -42.4574 EUR │ -4.2457% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 961.348 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴────────────────────────────────────────────────────┴───────────────╯\n", + "\u001B[93mAll growths ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬────────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Growth │ Growth percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_50 │ -2.3874 EUR │ -0.2387% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 997.613 │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_75 │ -6.7215 EUR │ -0.6722% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 993.279 │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_200 │ -24.5160 EUR │ -2.4516% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 975.484 │\n", + "├──────────────────┼──────────────┼─────────────────────┼────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_100 │ -38.6522 EUR │ -3.8652% │ sideways 2022-06-10 00:00:00 - 2023-01-10 00:00:00 │ 961.348 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴────────────────────────────────────────────────────┴───────────────╯\n", + "The winning configuration for the side ways backtest date range is None\n", + "\n", + " :%%%#+- .=*#%%% \u001B[92mBacktest reports evaluation\u001B[0m\n", + " *%%%%%%%+------=*%%%%%%%- \u001B[92m---------------------------\u001B[0m\n", + " *%%%%%%%%%%%%%%%%%%%%%%%- \u001B[93mNumber of reports:\u001B[0m \u001B[92m4 backtest reports\u001B[0m\n", + " .%%%%%%%%%%%%%%%%%%%%%%# \u001B[93mLargest overall profit:\u001B[0m\u001B[92m\u001B[0m\u001B[92m (Algorithm primary_50_100) -40.0021 EUR -4.0002% (down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00)\u001B[0m \n", + " #%%%####%%%%%%%%**#%%%+ \u001B[93mLargest overall growth:\u001B[0m\u001B[92m (Algorithm primary_50_100) -40.0021 EUR -4.0002% (down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00)\u001B[0m\n", + " .:-+*%%%%- \u001B[95m-+..#\u001B[0m%%%+.\u001B[95m+- +\u001B[0m%%%#*=-: \n", + " .:-=*%%%%. \u001B[95m+=\u001B[0m .%%# \u001B[95m-+.-\u001B[0m%%%%=-:.. \n", + " .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: \n", + " +%%%%%%%%%%%%%%%%%%%= \n", + " :++ .=#%%%%%%%%%%%%%*- \n", + " :++: :+%%%%%%#-. \n", + " :++: .%%%%%#= \n", + " :++: .#%%%%%#*= \n", + " :++- :%%%%%%%%%+= \n", + " .++- -%%%%%%%%%%%+= \n", + " .++- .%%%%%%%%%%%%%+= \n", + " .++- *%%%%%%%%%%%%%*+: \n", + " .++- %%%%%%%%%%%%%%#+= \n", + " =++........:::%%%%%%%%%%%%%%*+- \n", + " .=++++++++++**#%%%%%%%%%%%%%++. \n", + " \n", + "\u001B[93mAll profits ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬─────────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Profit │ Profit percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_100 │ -40.0021 EUR │ -4.0002% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 959.998 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_50 │ -57.1643 EUR │ -5.7164% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 942.836 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_200 │ -65.6861 EUR │ -6.5686% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 934.314 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_75 │ -74.4635 EUR │ -7.4464% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 925.537 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴─────────────────────────────────────────────────────┴───────────────╯\n", + "\u001B[93mAll growths ordered\u001B[0m\n", + "╭──────────────────┬──────────────┬─────────────────────┬─────────────────────────────────────────────────────┬───────────────╮\n", + "│ Algorithm name │ Growth │ Growth percentage │ Date range │ Total value │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_100 │ -40.0021 EUR │ -4.0002% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 959.998 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_50 │ -57.1643 EUR │ -5.7164% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 942.836 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_50_200 │ -65.6861 EUR │ -6.5686% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 934.314 │\n", + "├──────────────────┼──────────────┼─────────────────────┼─────────────────────────────────────────────────────┼───────────────┤\n", + "│ primary_21_75 │ -74.4635 EUR │ -7.4463% │ down_turn 2021-12-21 00:00:00 - 2022-06-20 00:00:00 │ 925.537 │\n", + "╰──────────────────┴──────────────┴─────────────────────┴─────────────────────────────────────────────────────┴───────────────╯\n", + "The winning configuration for the down turn backtest date range is None\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "from investing_algorithm_framework import pretty_print_backtest_reports_evaluation, BacktestReportsEvaluation\n", + "\n", + "configurations = [\n", + " {\n", + " \"name\": \"primary_21_50\",\n", + " \"description\": \"This is the primary algorithm configured with 21 ema and 50 ema\",\n", + " \"long_period\": 50,\n", + " \"short_period\": 21\n", + " },\n", + " {\n", + " \"name\": \"primary_21_75\",\n", + " \"description\": \"This is the primary algorithm configured with 21 ema and 50 ema\",\n", + " \"long_period\": 75,\n", + " \"short_period\": 21\n", + " },\n", + " {\n", + " \"name\": \"primary_50_100\",\n", + " \"description\": \"This is the primary algorithm configured with 21 ema and 50 ema\",\n", + " \"long_period\": 100,\n", + " \"short_period\": 50\n", + " },\n", + " {\n", + " \"name\": \"primary_50_200\",\n", + " \"description\": \"This is the primary algorithm configured with 21 ema and 50 ema\",\n", + " \"long_period\": 200,\n", + " \"short_period\": 50\n", + " }\n", + "]\n", + "algorithms = []\n", + "\n", + "for configuration in configurations:\n", + " algorithm = create_primary_algorithm(**configuration)\n", + " algorithms.append(algorithm)\n", + "\n", + "reports = app.run_backtests(algorithms=algorithms, date_ranges=[down_turn_date_range, up_turn_date_range, sideways_date_range])\n", + "evaluation = BacktestReportsEvaluation(reports)\n", + "pretty_print_backtest_reports_evaluation(evaluation, backtest_date_range=up_turn_date_range)\n", + "winning_configuration = evaluation.rank(weight_profit=0.7, weight_growth=0.3, backtest_date_range=up_turn_date_range)\n", + "print(f\"The winning configuration for the up turn backtest date range is {winning_configuration}\")\n", + "\n", + "pretty_print_backtest_reports_evaluation(evaluation, backtest_date_range=sideways_date_range)\n", + "winning_configuration = evaluation.rank(weight_profit=0.7, weight_growth=0.3, backtest_date_range=sideways_date_range)\n", + "print(f\"The winning configuration for the side ways backtest date range is {winning_configuration}\")\n", + "\n", + "pretty_print_backtest_reports_evaluation(evaluation, backtest_date_range=down_turn_date_range)\n", + "winning_configuration = evaluation.rank(weight_profit=0.7, weight_growth=0.3, backtest_date_range=down_turn_date_range)\n", + "print(f\"The winning configuration for the down turn backtest date range is {winning_configuration}\")" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "## Conclusion" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "markdown", + "source": [ + "In this guide we have demonstrated how to leverage the backtests functionality within the Investing Algorithm Framework to conduct A/B Testing effectively. We have compared the performance of multiple models, such as challenger versus champion, and experimented with diverse backtest date ranges and parameter configurations. This process of comparing the challenger model to the production model, or champion, falls under the umbrella of model validation or model evaluation. It entails meticulously assessing the challenger model's performance in relation to the established production model. The Experiment functionality proves invaluable for fine-tuning strategy parameters and comparing different strategies, whether it's testing a new challenger model against the existing production model (champion), or exploring variations in configuration.\n", + "\n", + "Also, when selected an algorithm we showed how to test different configurations of the winning algorithm to optimize the strategy. This process is crucial to ensure that the algorithm is performing at its best and to maximize the profit. By following these steps, you can effectively compare different algorithms and configurations to identify the best performing strategy for your trading needs." + ], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 9bcc9074589f4a9f3467597700f4e1ae9c3585bc Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:13:07 +0200 Subject: [PATCH 08/31] Rename to backtests --- examples/backtests_example/{experiment.ipynb => backtests.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/backtests_example/{experiment.ipynb => backtests.ipynb} (100%) diff --git a/examples/backtests_example/experiment.ipynb b/examples/backtests_example/backtests.ipynb similarity index 100% rename from examples/backtests_example/experiment.ipynb rename to examples/backtests_example/backtests.ipynb From c8c8acfb7a45d14411c38caf781ec447fe492624 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:13:23 +0200 Subject: [PATCH 09/31] Refactor tests --- .../test_csv_ohlcv_market_data_source.py | 95 +++++++++++++------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py b/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py index efd499ca..40761b19 100644 --- a/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py +++ b/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py @@ -2,15 +2,20 @@ from datetime import datetime, timedelta from unittest import TestCase +from dateutil import parser from dateutil.tz import tzutc from polars import DataFrame -from investing_algorithm_framework.domain import OperationalException +from investing_algorithm_framework.domain import OperationalException, \ + TimeFrame, DATETIME_FORMAT from investing_algorithm_framework.infrastructure import \ CSVOHLCVMarketDataSource class Test(TestCase): + """ + Test cases for the CSVOHLCVMarketDataSource class. + """ def setUp(self) -> None: self.resource_dir = os.path.abspath( @@ -33,13 +38,10 @@ def test_right_columns(self): file_name = "OHLCV_BTC-EUR_BINANCE" \ "_2h_2023-08-07:07:59_2023-12-02:00:00.csv" data_source = CSVOHLCVMarketDataSource( - csv_file_path=f"{self.resource_dir}/" - "market_data_sources/" + csv_file_path=f"{self.resource_dir}/market_data_sources/" f"{file_name}", - window_size=10 ) - df = data_source \ - .get_data(datetime(year=2023, month=12, day=17, hour=0, minute=0)) + df = data_source.get_data() self.assertEqual( ["Datetime", "Open", "High", "Low", "Close", "Volume"], df.columns ) @@ -65,12 +67,55 @@ def test_start_date(self): "market_data_sources/" f"{file_name}", window_size=10, + timeframe=TimeFrame.TWO_HOUR, ) self.assertEqual( start_date, csv_ohlcv_market_data_source.start_date.replace(microsecond=0), ) + def test_start_date_with_window_size(self): + start_date = datetime( + year=2023, month=8, day=7, hour=10, minute=0, tzinfo=tzutc() + ) + file_name = "OHLCV_BTC-EUR_BINANCE" \ + "_2h_2023-08-07:07:59_2023-12-02:00:00.csv" + csv_ohlcv_market_data_source = CSVOHLCVMarketDataSource( + csv_file_path=f"{self.resource_dir}/" + "market_data_sources/" + f"{file_name}", + window_size=12, + timeframe=TimeFrame.TWO_HOUR, + ) + data = csv_ohlcv_market_data_source.get_data(start_date=start_date) + self.assertEqual(12, len(data)) + first_date = parser.parse(data["Datetime"][0]) + self.assertEqual( + start_date.strftime(DATETIME_FORMAT), + first_date.strftime(DATETIME_FORMAT) + ) + + def test_start_date_with_backtest_index_date(self): + start_date = datetime(2023, 8, 7, 8, 0, tzinfo=tzutc()) + file_name = "OHLCV_BTC-EUR_BINANCE" \ + "_2h_2023-08-07:07:59_2023-12-02:00:00.csv" + csv_ohlcv_market_data_source = CSVOHLCVMarketDataSource( + csv_file_path=f"{self.resource_dir}/" + "market_data_sources/" + f"{file_name}", + window_size=10, + timeframe=TimeFrame.TWO_HOUR, + ) + data = csv_ohlcv_market_data_source.get_data( + backtest_index_date=datetime(2023, 8, 7, 8, 0, tzinfo=tzutc()) + ) + self.assertEqual(10, len(data)) + first_date = parser.parse(data["Datetime"][0]) + self.assertEqual( + start_date.strftime(DATETIME_FORMAT), + first_date.strftime(DATETIME_FORMAT) + ) + def test_end_date(self): end_date = datetime(2023, 12, 2, 0, 0, tzinfo=tzutc()) file_name = "OHLCV_BTC-EUR_BINANCE" \ @@ -79,7 +124,6 @@ def test_end_date(self): csv_file_path=f"{self.resource_dir}/" "market_data_sources/" f"{file_name}", - window_size=10, ) self.assertEqual( end_date, @@ -87,7 +131,6 @@ def test_end_date(self): ) def test_empty(self): - start_date = datetime(2023, 8, 7, 8, 0, tzinfo=tzutc()) file_name = "OHLCV_BTC-EUR_BINANCE" \ "_2h_2023-08-07:07:59_2023-12-02:00:00.csv" data_source = CSVOHLCVMarketDataSource( @@ -95,13 +138,11 @@ def test_empty(self): "market_data_sources/" f"{file_name}", window_size=10, - timeframe="15m", + timeframe="2h", ) - self.assertFalse(data_source.empty()) - self.assertEqual(start_date, data_source.start_date) - data_source.start_date = datetime(2023, 12, 25, 0, 0, tzinfo=tzutc()) - data_source.end_date = datetime(2023, 12, 16, 0, 0, tzinfo=tzutc()) - self.assertTrue(data_source.empty()) + start_date = datetime(2023, 8, 7, 8, 0, tzinfo=tzutc()) + end_date = datetime(2023, 12, 2, 0, 0, tzinfo=tzutc()) + self.assertFalse(data_source.empty(start_date, end_date)) def test_get_data(self): file_name = "OHLCV_BTC-EUR_BINANCE" \ @@ -110,17 +151,16 @@ def test_get_data(self): csv_file_path=f"{self.resource_dir}/" "market_data_sources/" f"{file_name}", - window_size=10, - timeframe="15m", + window_size=200, + timeframe="2h", ) number_of_runs = 0 + backtest_index_date = datasource.start_date while not datasource.empty(): - data = datasource.get_data() - datasource.start_date = datasource.start_date + timedelta(days=1) - datasource.end_date = datasource.end_date + timedelta(days=1) + data = datasource.get_data(backtest_index_date=backtest_index_date) + backtest_index_date = parser.parse(data["Datetime"][-1]) self.assertTrue(len(data) > 0) - self.assertAlmostEqual(10, len(data), 2) self.assertTrue(isinstance(data, DataFrame)) number_of_runs += 1 @@ -135,7 +175,7 @@ def test_get_identifier(self): f"{file_name}", identifier="test", window_size=10, - timeframe="15m", + timeframe="2h", ) self.assertEqual("test", datasource.get_identifier()) @@ -147,9 +187,7 @@ def test_get_market(self): "market_data_sources/" f"{file_name}", market="test", - timeframe="15m", - start_date=datetime(2023, 12, 1), - end_date=datetime(2023, 12, 25), + timeframe="2h", ) self.assertEqual("test", datasource.get_market()) @@ -162,7 +200,7 @@ def test_get_symbol(self): f"{file_name}", symbol="BTC/EUR", window_size=10, - timeframe="15m", + timeframe="2h", ) self.assertEqual("BTC/EUR", datasource.get_symbol()) @@ -173,10 +211,7 @@ def test_get_timeframe(self): csv_file_path=f"{self.resource_dir}/" "market_data_sources/" f"{file_name}", - timeframe="15m", + timeframe="2h", window_size=10, ) - self.assertEqual("15m", datasource.get_timeframe()) - - def test_get_data(self): - pass + self.assertEqual("2h", datasource.get_timeframe()) From a30169430468960fc30ed79974098df5ff14a5cb Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:15:39 +0200 Subject: [PATCH 10/31] Update readme --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 08bd8a44..470eea18 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ components for creating algorithms, including data provisioning, portfolio management, and order execution. Features: -* Order execution +* Order execution and tracking * Broker and exchange connections through [ccxt](https://github.com/ccxt/ccxt) -* Backtesting and performance analysis reports [example](./examples/backtest) -* Backtest experiments to optimize your trading strategy [example](./examples/backtest_experiment) -* Portfolio management +* Backtesting and performance analysis reports [example](./examples/backtest_example) +* Backtesting multiple algorithms with different backtest date ranges [example](./examples/backtests_example) +* Portfolio management and tracking * Web API for interacting with your deployed trading bot * Data persistence through sqlite db or an in-memory db * Stateless running for cloud function deployments @@ -68,9 +68,6 @@ bitvavo_btc_eur_ticker = CCXTTickerMarketDataSource( ) app = create_app(config=config) algorithm = Algorithm() - -app.add_market_data_source(bitvavo_btc_eur_ohlcv_2h) -app.add_market_data_source(bitvavo_btc_eur_ticker) app.add_market_credential(MarketCredential( market="bitvavo", api_key="", @@ -90,7 +87,7 @@ app.add_algorithm(algorithm) time_unit=TimeUnit.HOUR, interval=2, # Specify market data sources that need to be passed to the strategy - market_data_sources=["BTC-ticker", "BTC-ohlcv"] + market_data_sources=[bitvavo_btc_eur_ticker, bitvavo_btc_eur_ohlcv_2h] ) def perform_strategy(algorithm: Algorithm, market_data: dict): # By default, ohlcv data is passed as polars df in the form of From 9c9ce69c79e415cdb77797b3e8685d57ac6f32f5 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 28 May 2024 14:16:00 +0200 Subject: [PATCH 11/31] Add plotly as dependency --- poetry.lock | 1849 +++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 + 2 files changed, 1835 insertions(+), 16 deletions(-) diff --git a/poetry.lock b/poetry.lock index e51814c7..5008e6e1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -145,6 +145,147 @@ typing-extensions = ">=4" [package.extras] tz = ["backports.zoneinfo"] +[[package]] +name = "anyio" +version = "4.3.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "appnope" +version = "0.1.4" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = ">=3.6" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, +] + +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + +[[package]] +name = "arrow" +version = "1.3.0" +description = "Better dates & times for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"}, + {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.0" +types-python-dateutil = ">=2.8.10" + +[package.extras] +doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] +test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] + +[[package]] +name = "asttokens" +version = "2.4.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + +[[package]] +name = "async-lru" +version = "2.0.4" +description = "Simple LRU cache for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627"}, + {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} + [[package]] name = "async-timeout" version = "4.0.3" @@ -175,6 +316,73 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +[[package]] +name = "babel" +version = "2.14.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, + {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, +] + +[package.dependencies] +pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +optional = false +python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bleach" +version = "6.1.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.8" +files = [ + {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, + {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.3)"] + [[package]] name = "blinker" version = "1.7.0" @@ -410,6 +618,23 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "comm" +version = "0.2.2" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.8" +files = [ + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, +] + +[package.dependencies] +traitlets = ">=4" + +[package.extras] +test = ["pytest"] + [[package]] name = "coverage" version = "7.4.2" @@ -528,6 +753,59 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] +[[package]] +name = "debugpy" +version = "1.8.1" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, + {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, + {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, + {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, + {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, + {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, + {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, + {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, + {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, + {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, + {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, + {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, + {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, + {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, + {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, + {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, + {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, + {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, + {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, + {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, + {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, + {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + [[package]] name = "dependency-injector" version = "4.41.0" @@ -616,6 +894,48 @@ flask = ["flask"] pydantic = ["pydantic"] yaml = ["pyyaml"] +[[package]] +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "executing" +version = "2.0.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.5" +files = [ + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + +[[package]] +name = "fastjsonschema" +version = "2.19.1" +description = "Fastest Python implementation of JSON schema" +optional = false +python-versions = "*" +files = [ + {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, + {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + [[package]] name = "flake8" version = "7.0.0" @@ -714,6 +1034,17 @@ files = [ [package.dependencies] Flask = "*" +[[package]] +name = "fqdn" +version = "1.5.1" +description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" +optional = false +python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" +files = [ + {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, + {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, +] + [[package]] name = "frozenlist" version = "1.4.1" @@ -871,6 +1202,62 @@ files = [ docs = ["Sphinx", "furo"] test = ["objgraph", "psutil"] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.5" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.26.0)"] + +[[package]] +name = "httpx" +version = "0.27.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + [[package]] name = "idna" version = "3.6" @@ -919,6 +1306,113 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] +[[package]] +name = "ipykernel" +version = "6.29.4" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, + {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=24" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.12.3" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipython-8.12.3-py3-none-any.whl", hash = "sha256:b0340d46a933d27c657b211a329d0be23793c36595acf9e6ef4164bc01a1804c"}, + {file = "ipython-8.12.3.tar.gz", hash = "sha256:3910c4b54543c2ad73d06579aa771041b7d5707b033bd488669b4cf544e3b363"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} + +[package.extras] +all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "ipywidgets" +version = "8.1.2" +description = "Jupyter interactive widgets" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, + {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, +] + +[package.dependencies] +comm = ">=0.1.3" +ipython = ">=6.1.0" +jupyterlab-widgets = ">=3.0.10,<3.1.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=4.0.10,<4.1.0" + +[package.extras] +test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] + +[[package]] +name = "isoduration" +version = "20.11.0" +description = "Operations with ISO 8601 durations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"}, + {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"}, +] + +[package.dependencies] +arrow = ">=0.15.0" + [[package]] name = "itsdangerous" version = "2.1.2" @@ -930,6 +1424,25 @@ files = [ {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, ] +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + [[package]] name = "jinja2" version = "3.1.3" @@ -948,32 +1461,365 @@ MarkupSafe = ">=2.0" i18n = ["Babel (>=2.7)"] [[package]] -name = "mako" -version = "1.3.2" -description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +name = "json5" +version = "0.9.25" +description = "A Python implementation of the JSON5 data format." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, - {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, + {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"}, + {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"}, +] + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "jsonschema" +version = "4.22.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, ] [package.dependencies] -MarkupSafe = ">=0.9.2" +attrs = ">=22.2.0" +fqdn = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +idna = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} +isoduration = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +jsonpointer = {version = ">1.13", optional = true, markers = "extra == \"format-nongpl\""} +jsonschema-specifications = ">=2023.03.6" +pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} +referencing = ">=0.28.4" +rfc3339-validator = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} +rpds-py = ">=0.7.1" +uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +webcolors = {version = ">=1.11", optional = true, markers = "extra == \"format-nongpl\""} [package.extras] -babel = ["Babel"] -lingua = ["lingua"] -testing = ["pytest"] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] [[package]] -name = "markupsafe" -version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} +referencing = ">=0.31.0" + +[[package]] +name = "jupyter" +version = "1.0.0" +description = "Jupyter metapackage. Install all the Jupyter components in one go." +optional = false +python-versions = "*" +files = [ + {file = "jupyter-1.0.0-py2.py3-none-any.whl", hash = "sha256:5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78"}, + {file = "jupyter-1.0.0.tar.gz", hash = "sha256:d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"}, + {file = "jupyter-1.0.0.zip", hash = "sha256:3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7"}, +] + +[package.dependencies] +ipykernel = "*" +ipywidgets = "*" +jupyter-console = "*" +nbconvert = "*" +notebook = "*" +qtconsole = "*" + +[[package]] +name = "jupyter-client" +version = "8.6.1" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, + {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = ">=5.3" + +[package.extras] +docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +description = "Jupyter terminal console" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"}, + {file = "jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539"}, +] + +[package.dependencies] +ipykernel = ">=6.14" +ipython = "*" +jupyter-client = ">=7.0.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +prompt-toolkit = ">=3.0.30" +pygments = "*" +pyzmq = ">=17" +traitlets = ">=5.4" + +[package.extras] +test = ["flaky", "pexpect", "pytest"] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyter-events" +version = "0.10.0" +description = "Jupyter Event System library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960"}, + {file = "jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22"}, +] + +[package.dependencies] +jsonschema = {version = ">=4.18.0", extras = ["format-nongpl"]} +python-json-logger = ">=2.0.4" +pyyaml = ">=5.3" +referencing = "*" +rfc3339-validator = "*" +rfc3986-validator = ">=0.1.1" +traitlets = ">=5.3" + +[package.extras] +cli = ["click", "rich"] +docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme", "sphinxcontrib-spelling"] +test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "rich"] + +[[package]] +name = "jupyter-lsp" +version = "2.2.5" +description = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001"}, + {file = "jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jupyter-server = ">=1.1.2" + +[[package]] +name = "jupyter-server" +version = "2.14.0" +description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_server-2.14.0-py3-none-any.whl", hash = "sha256:fb6be52c713e80e004fac34b35a0990d6d36ba06fd0a2b2ed82b899143a64210"}, + {file = "jupyter_server-2.14.0.tar.gz", hash = "sha256:659154cea512083434fd7c93b7fe0897af7a2fd0b9dd4749282b42eaac4ae677"}, +] + +[package.dependencies] +anyio = ">=3.1.0" +argon2-cffi = ">=21.1" +jinja2 = ">=3.0.3" +jupyter-client = ">=7.4.4" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +jupyter-events = ">=0.9.0" +jupyter-server-terminals = ">=0.4.4" +nbconvert = ">=6.4.4" +nbformat = ">=5.3.0" +overrides = ">=5.0" +packaging = ">=22.0" +prometheus-client = ">=0.9" +pywinpty = {version = ">=2.0.1", markers = "os_name == \"nt\""} +pyzmq = ">=24" +send2trash = ">=1.8.2" +terminado = ">=0.8.3" +tornado = ">=6.2.0" +traitlets = ">=5.6.0" +websocket-client = ">=1.7" + +[package.extras] +docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] +test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.7)", "pytest-timeout", "requests"] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.3" +description = "A Jupyter Server Extension Providing Terminals." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"}, + {file = "jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269"}, +] + +[package.dependencies] +pywinpty = {version = ">=2.0.3", markers = "os_name == \"nt\""} +terminado = ">=0.8.3" + +[package.extras] +docs = ["jinja2", "jupyter-server", "mistune (<4.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] +test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] + +[[package]] +name = "jupyterlab" +version = "4.1.8" +description = "JupyterLab computational environment" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab-4.1.8-py3-none-any.whl", hash = "sha256:c3baf3a2f91f89d110ed5786cd18672b9a357129d4e389d2a0dead15e11a4d2c"}, + {file = "jupyterlab-4.1.8.tar.gz", hash = "sha256:3384aded8680e7ce504fd63b8bb89a39df21c9c7694d9e7dc4a68742cdb30f9b"}, +] + +[package.dependencies] +async-lru = ">=1.0.0" +httpx = ">=0.25.0" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +importlib-resources = {version = ">=1.4", markers = "python_version < \"3.9\""} +ipykernel = ">=6.5.0" +jinja2 = ">=3.0.3" +jupyter-core = "*" +jupyter-lsp = ">=2.0.0" +jupyter-server = ">=2.4.0,<3" +jupyterlab-server = ">=2.27.1,<3" +notebook-shim = ">=0.2" +packaging = "*" +tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} +tornado = ">=6.2.0" +traitlets = "*" + +[package.extras] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.2.0)"] +docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] +docs-screenshots = ["altair (==5.2.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.1)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.0.post6)", "matplotlib (==3.8.2)", "nbconvert (>=7.0.0)", "pandas (==2.2.0)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] +test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] +upgrade-extension = ["copier (>=8.0,<9.0)", "jinja2-time (<0.3)", "pydantic (<2.0)", "pyyaml-include (<2.0)", "tomli-w (<2.0)"] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +description = "Pygments theme using JupyterLab CSS variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, + {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, +] + +[[package]] +name = "jupyterlab-server" +version = "2.27.1" +description = "A set of server components for JupyterLab and JupyterLab like applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab_server-2.27.1-py3-none-any.whl", hash = "sha256:f5e26156e5258b24d532c84e7c74cc212e203bff93eb856f81c24c16daeecc75"}, + {file = "jupyterlab_server-2.27.1.tar.gz", hash = "sha256:097b5ac709b676c7284ac9c5e373f11930a561f52cd5a86e4fc7e5a9c8a8631d"}, +] + +[package.dependencies] +babel = ">=2.10" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jinja2 = ">=3.0.3" +json5 = ">=0.9.0" +jsonschema = ">=4.18.0" +jupyter-server = ">=1.21,<3" +packaging = ">=21.3" +requests = ">=2.31" + +[package.extras] +docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi (>0.8)"] +openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"] +test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0,<8)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.10" +description = "Jupyter interactive widgets for JupyterLab" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, + {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, +] + +[[package]] +name = "mako" +version = "1.3.2" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, + {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, +] + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[package.extras] +babel = ["Babel"] +lingua = ["lingua"] +testing = ["pytest"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, @@ -1055,6 +1901,20 @@ docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "s lint = ["pre-commit (>=2.4,<4.0)"] tests = ["pytest", "pytz", "simplejson"] +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, +] + +[package.dependencies] +traitlets = "*" + [[package]] name = "mccabe" version = "0.7.0" @@ -1066,6 +1926,17 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "mistune" +version = "3.0.2" +description = "A sane and fast Markdown parser with useful plugins and renderers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"}, + {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"}, +] + [[package]] name = "multidict" version = "6.0.5" @@ -1165,6 +2036,138 @@ files = [ {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] +[[package]] +name = "nbclient" +version = "0.10.0" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, + {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, +] + +[package.dependencies] +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +nbformat = ">=5.1" +traitlets = ">=5.4" + +[package.extras] +dev = ["pre-commit"] +docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] + +[[package]] +name = "nbconvert" +version = "7.16.4" +description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbconvert-7.16.4-py3-none-any.whl", hash = "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3"}, + {file = "nbconvert-7.16.4.tar.gz", hash = "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +bleach = "!=5.0.0" +defusedxml = "*" +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +jinja2 = ">=3.0" +jupyter-core = ">=4.7" +jupyterlab-pygments = "*" +markupsafe = ">=2.0" +mistune = ">=2.0.3,<4" +nbclient = ">=0.5.0" +nbformat = ">=5.7" +packaging = "*" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +tinycss2 = "*" +traitlets = ">=5.1" + +[package.extras] +all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] +docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] +qtpdf = ["pyqtwebengine (>=5.15)"] +qtpng = ["pyqtwebengine (>=5.15)"] +serve = ["tornado (>=6.1)"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"] +webpdf = ["playwright"] + +[[package]] +name = "nbformat" +version = "5.10.4" +description = "The Jupyter Notebook format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, + {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, +] + +[package.dependencies] +fastjsonschema = ">=2.15" +jsonschema = ">=2.6" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +traitlets = ">=5.1" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["pep440", "pre-commit", "pytest", "testpath"] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + +[[package]] +name = "notebook" +version = "7.1.3" +description = "Jupyter Notebook - A web-based notebook environment for interactive computing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "notebook-7.1.3-py3-none-any.whl", hash = "sha256:919b911e59f41f6e3857ce93c9d93535ba66bb090059712770e5968c07e1004d"}, + {file = "notebook-7.1.3.tar.gz", hash = "sha256:41fcebff44cf7bb9377180808bcbae066629b55d8c7722f1ebbe75ca44f9cfc1"}, +] + +[package.dependencies] +jupyter-server = ">=2.4.0,<3" +jupyterlab = ">=4.1.1,<4.2" +jupyterlab-server = ">=2.22.1,<3" +notebook-shim = ">=0.2,<0.3" +tornado = ">=6.2.0" + +[package.extras] +dev = ["hatch", "pre-commit"] +docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.22.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] + +[[package]] +name = "notebook-shim" +version = "0.2.4" +description = "A shim layer for notebook traits and config" +optional = false +python-versions = ">=3.7" +files = [ + {file = "notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef"}, + {file = "notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb"}, +] + +[package.dependencies] +jupyter-server = ">=1.8,<3" + +[package.extras] +test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync"] + [[package]] name = "numpy" version = "1.24.4" @@ -1202,6 +2205,17 @@ files = [ {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, ] +[[package]] +name = "overrides" +version = "7.7.0" +description = "A decorator to automatically detect mismatch when overriding a method." +optional = false +python-versions = ">=3.6" +files = [ + {file = "overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49"}, + {file = "overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a"}, +] + [[package]] name = "packaging" version = "23.2" @@ -1250,8 +2264,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -1280,6 +2294,84 @@ sql-other = ["SQLAlchemy (>=1.4.16)"] test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.6.3)"] +[[package]] +name = "pandocfilters" +version = "1.5.1" +description = "Utilities for writing pandoc filters in python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, +] + +[[package]] +name = "parso" +version = "0.8.4" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, +] + +[package.extras] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +optional = false +python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] + +[[package]] +name = "pkgutil-resolve-name" +version = "1.3.10" +description = "Resolve a name to an object." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, + {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, + {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + [[package]] name = "polars" version = "0.20.10" @@ -1322,6 +2414,87 @@ timezone = ["backports.zoneinfo", "tzdata"] xlsx2csv = ["xlsx2csv (>=0.8.0)"] xlsxwriter = ["xlsxwriter"] +[[package]] +name = "prometheus-client" +version = "0.20.0" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.8" +files = [ + {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, + {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, +] + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.43" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "pyarrow" version = "15.0.0" @@ -1469,6 +2642,21 @@ files = [ {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1483,6 +2671,17 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "python-json-logger" +version = "2.0.7" +description = "A python library adding a json log formatter" +optional = false +python-versions = ">=3.6" +files = [ + {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, + {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, +] + [[package]] name = "pytz" version = "2024.1" @@ -1494,6 +2693,260 @@ files = [ {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pywinpty" +version = "2.0.13" +description = "Pseudo terminal support for Windows from Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pywinpty-2.0.13-cp310-none-win_amd64.whl", hash = "sha256:697bff211fb5a6508fee2dc6ff174ce03f34a9a233df9d8b5fe9c8ce4d5eaf56"}, + {file = "pywinpty-2.0.13-cp311-none-win_amd64.whl", hash = "sha256:b96fb14698db1284db84ca38c79f15b4cfdc3172065b5137383910567591fa99"}, + {file = "pywinpty-2.0.13-cp312-none-win_amd64.whl", hash = "sha256:2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4"}, + {file = "pywinpty-2.0.13-cp38-none-win_amd64.whl", hash = "sha256:61d420c2116c0212808d31625611b51caf621fe67f8a6377e2e8b617ea1c1f7d"}, + {file = "pywinpty-2.0.13-cp39-none-win_amd64.whl", hash = "sha256:71cb613a9ee24174730ac7ae439fd179ca34ccb8c5349e8d7b72ab5dea2c6f4b"}, + {file = "pywinpty-2.0.13.tar.gz", hash = "sha256:c34e32351a3313ddd0d7da23d27f835c860d32fe4ac814d372a3ea9594f41dde"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "pyzmq" +version = "26.0.3" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, + {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, + {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, + {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, + {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, + {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, + {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, + {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "qtconsole" +version = "5.5.1" +description = "Jupyter Qt console" +optional = false +python-versions = ">= 3.8" +files = [ + {file = "qtconsole-5.5.1-py3-none-any.whl", hash = "sha256:8c75fa3e9b4ed884880ff7cea90a1b67451219279ec33deaee1d59e3df1a5d2b"}, + {file = "qtconsole-5.5.1.tar.gz", hash = "sha256:a0e806c6951db9490628e4df80caec9669b65149c7ba40f9bf033c025a5b56bc"}, +] + +[package.dependencies] +ipykernel = ">=4.1" +jupyter-client = ">=4.1" +jupyter-core = "*" +packaging = "*" +pygments = "*" +pyzmq = ">=17.1" +qtpy = ">=2.4.0" +traitlets = "<5.2.1 || >5.2.1,<5.2.2 || >5.2.2" + +[package.extras] +doc = ["Sphinx (>=1.3)"] +test = ["flaky", "pytest", "pytest-qt"] + +[[package]] +name = "qtpy" +version = "2.4.1" +description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)." +optional = false +python-versions = ">=3.7" +files = [ + {file = "QtPy-2.4.1-py3-none-any.whl", hash = "sha256:1c1d8c4fa2c884ae742b069151b0abe15b3f70491f3972698c683b8e38de839b"}, + {file = "QtPy-2.4.1.tar.gz", hash = "sha256:a5a15ffd519550a1361bdc56ffc07fda56a6af7292f17c7b395d4083af632987"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] + +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "requests" version = "2.31.0" @@ -1515,6 +2968,139 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +description = "A pure python RFC3339 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, + {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, +] + +[package.dependencies] +six = "*" + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +description = "Pure python rfc3986 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"}, + {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, +] + +[[package]] +name = "rpds-py" +version = "0.18.0" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, + {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, + {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, + {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, + {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, + {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, + {file = "rpds_py-0.18.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0"}, + {file = "rpds_py-0.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7"}, + {file = "rpds_py-0.18.0-cp312-none-win32.whl", hash = "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98"}, + {file = "rpds_py-0.18.0-cp312-none-win_amd64.whl", hash = "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec"}, + {file = "rpds_py-0.18.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e"}, + {file = "rpds_py-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594"}, + {file = "rpds_py-0.18.0-cp38-none-win32.whl", hash = "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e"}, + {file = "rpds_py-0.18.0-cp38-none-win_amd64.whl", hash = "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, + {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, + {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, + {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, +] + [[package]] name = "schedule" version = "1.2.1" @@ -1526,6 +3112,22 @@ files = [ {file = "schedule-1.2.1.tar.gz", hash = "sha256:843bc0538b99c93f02b8b50e3e39886c06f2d003b24f48e1aa4cadfa3f341279"}, ] +[[package]] +name = "send2trash" +version = "1.8.3" +description = "Send file to trash natively under Mac OS X, Windows and Linux" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9"}, + {file = "Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf"}, +] + +[package.extras] +nativelib = ["pyobjc-framework-Cocoa", "pywin32"] +objc = ["pyobjc-framework-Cocoa"] +win32 = ["pywin32"] + [[package]] name = "setuptools" version = "69.1.0" @@ -1553,6 +3155,28 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + [[package]] name = "sqlalchemy" version = "2.0.27" @@ -1640,6 +3264,25 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] pymysql = ["pymysql"] sqlcipher = ["sqlcipher3_binary"] +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + [[package]] name = "tabulate" version = "0.9.0" @@ -1654,6 +3297,76 @@ files = [ [package.extras] widechars = ["wcwidth"] +[[package]] +name = "terminado" +version = "0.18.1" +description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"}, + {file = "terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e"}, +] + +[package.dependencies] +ptyprocess = {version = "*", markers = "os_name != \"nt\""} +pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} +tornado = ">=6.1.0" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] +typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] + +[[package]] +name = "tinycss2" +version = "1.3.0" +description = "A tiny CSS parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, + {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["pytest", "ruff"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tornado" +version = "6.4" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, + {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, + {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, + {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, + {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, +] + [[package]] name = "tqdm" version = "4.66.2" @@ -1674,6 +3387,32 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "traitlets" +version = "5.14.3" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20240316" +description = "Typing stubs for python-dateutil" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, + {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, +] + [[package]] name = "typing-extensions" version = "4.9.0" @@ -1696,6 +3435,20 @@ files = [ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] +[[package]] +name = "uri-template" +version = "1.3.0" +description = "RFC 6570 URI Template Processor" +optional = false +python-versions = ">=3.7" +files = [ + {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"}, + {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"}, +] + +[package.extras] +dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake8-commas", "flake8-comprehensions", "flake8-continuation", "flake8-datetimez", "flake8-docstrings", "flake8-import-order", "flake8-literal", "flake8-modern-annotations", "flake8-noqa", "flake8-pyproject", "flake8-requirements", "flake8-typechecking-import", "flake8-use-fstring", "mypy", "pep8-naming", "types-PyYAML"] + [[package]] name = "urllib3" version = "2.2.1" @@ -1713,6 +3466,59 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "webcolors" +version = "1.13" +description = "A library for working with the color formats defined by HTML and CSS." +optional = false +python-versions = ">=3.7" +files = [ + {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, + {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, +] + +[package.extras] +docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +description = "WebSocket client for Python with low level API options" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526"}, + {file = "websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da"}, +] + +[package.extras] +docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx-rtd-theme (>=1.1.0)"] +optional = ["python-socks", "wsaccel"] +test = ["websockets"] + [[package]] name = "werkzeug" version = "3.0.1" @@ -1730,6 +3536,17 @@ MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog (>=2.3)"] +[[package]] +name = "widgetsnbextension" +version = "4.0.10" +description = "Jupyter interactive widgets for Jupyter Notebook" +optional = false +python-versions = ">=3.7" +files = [ + {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, + {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, +] + [[package]] name = "wrapt" version = "1.16.0" @@ -1930,4 +3747,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "c6e53c076721de4553a9ccff1fcbd5ea7cb94b663384ae13a256451c2416748f" +content-hash = "ccc8302927ae1b2b6a906e25a9bcc991faf2f8ca6dafc7d606618dfabe81f977" diff --git a/pyproject.toml b/pyproject.toml index b381caec..0b153ec1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,12 +15,14 @@ SQLAlchemy = "^2.0.18" marshmallow = "^3.5.0" ccxt = "^4.2.48" python-dateutil = "^2.8.2" +plotly = "^5.22.0" MarkupSafe = "^2.1.2" dependency-injector= "^4.40.0" schedule = "^1.1.0" tqdm = "^4.66.1" tabulate = "^0.9.0" polars = { version = "^0.20.10", extras = ["numpy", "pandas"] } +jupyter = "^1.0.0" [tool.poetry.group.test.dependencies] coverage= "7.4.2" From 936aa9bc142b918859dd6243bae527e3e3d806b9 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 22:28:55 +0200 Subject: [PATCH 12/31] Refactor data sources --- .../algorithm/strategy.py | 11 +++++++---- .../backtesting.py | 9 ++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/crossover_moving_average_trading_bot/algorithm/strategy.py b/examples/crossover_moving_average_trading_bot/algorithm/strategy.py index a36d23c0..df818884 100644 --- a/examples/crossover_moving_average_trading_bot/algorithm/strategy.py +++ b/examples/crossover_moving_average_trading_bot/algorithm/strategy.py @@ -2,6 +2,9 @@ from investing_algorithm_framework import TimeUnit, TradingStrategy, \ Algorithm, OrderSide +from .data_sources import bitvavo_btc_eur_ohlcv_2h, bitvavo_btc_eur_ticker, \ + bitvavo_dot_eur_ticker, bitvavo_dot_eur_ohlcv_2h + """ This strategy is based on the golden cross strategy. It will buy when the @@ -49,10 +52,10 @@ class CrossOverStrategy(TradingStrategy): time_unit = TimeUnit.HOUR interval = 2 market_data_sources = [ - "BTC/EUR-ohlcv", - "DOT/EUR-ohlcv", - "BTC/EUR-ticker", - "DOT/EUR-ticker" + bitvavo_dot_eur_ticker, + bitvavo_dot_eur_ohlcv_2h, + bitvavo_btc_eur_ticker, + bitvavo_btc_eur_ohlcv_2h ] symbols = ["BTC/EUR", "DOT/EUR"] diff --git a/examples/crossover_moving_average_trading_bot/backtesting.py b/examples/crossover_moving_average_trading_bot/backtesting.py index 18f668f4..9e34b6ce 100644 --- a/examples/crossover_moving_average_trading_bot/backtesting.py +++ b/examples/crossover_moving_average_trading_bot/backtesting.py @@ -5,7 +5,7 @@ bitvavo_dot_eur_ohlcv_2h, bitvavo_dot_eur_ticker, bitvavo_btc_eur_ticker from app import app from investing_algorithm_framework import PortfolioConfiguration, \ - pretty_print_backtest + pretty_print_backtest, BacktestDateRange app.add_algorithm(algorithm) app.add_market_data_source(bitvavo_btc_eur_ohlcv_2h) @@ -26,10 +26,13 @@ if __name__ == "__main__": end_date = datetime(2023, 12, 2) start_date = end_date - timedelta(days=100) + date_range = BacktestDateRange( + start_date=start_date, + end_date=end_date + ) backtest_report = app.run_backtest( algorithm=algorithm, - start_date=start_date, - end_date=end_date, + backtest_date_range=date_range, pending_order_check_interval="2h", ) pretty_print_backtest(backtest_report) From 9064138c887fa3adc68e22b3b24ac775e151d277 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 22:33:19 +0200 Subject: [PATCH 13/31] Refactor data sources --- examples/backtest_example/algorithm/strategy.py | 10 ++++++---- examples/backtest_example/run_backtest.py | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/examples/backtest_example/algorithm/strategy.py b/examples/backtest_example/algorithm/strategy.py index 6b15b33c..844535bd 100644 --- a/examples/backtest_example/algorithm/strategy.py +++ b/examples/backtest_example/algorithm/strategy.py @@ -2,6 +2,8 @@ from investing_algorithm_framework import TimeUnit, TradingStrategy, \ Algorithm, OrderSide +from .data_sources import bitvavo_btc_eur_ohlcv_2h, bitvavo_btc_eur_ticker, \ + bitvavo_dot_eur_ticker, bitvavo_dot_eur_ohlcv_2h """ This strategy is based on the golden cross strategy. It will buy when the @@ -47,10 +49,10 @@ class CrossOverStrategy(TradingStrategy): time_unit = TimeUnit.HOUR interval = 2 market_data_sources = [ - "BTC/EUR-ohlcv", - "DOT/EUR-ohlcv", - "BTC/EUR-ticker", - "DOT/EUR-ticker" + bitvavo_dot_eur_ticker, + bitvavo_btc_eur_ticker, + bitvavo_dot_eur_ohlcv_2h, + bitvavo_btc_eur_ohlcv_2h ] symbols = ["BTC/EUR", "DOT/EUR"] fast = 21 diff --git a/examples/backtest_example/run_backtest.py b/examples/backtest_example/run_backtest.py index dec528ef..1d1f5cb8 100644 --- a/examples/backtest_example/run_backtest.py +++ b/examples/backtest_example/run_backtest.py @@ -5,7 +5,7 @@ bitvavo_dot_eur_ohlcv_2h, bitvavo_dot_eur_ticker, bitvavo_btc_eur_ticker from app import app from investing_algorithm_framework import PortfolioConfiguration, \ - pretty_print_backtest + pretty_print_backtest, BacktestDateRange app.add_algorithm(algorithm) app.add_market_data_source(bitvavo_btc_eur_ohlcv_2h) @@ -26,9 +26,12 @@ if __name__ == "__main__": end_date = datetime(2023, 12, 2) start_date = end_date - timedelta(days=100) + date_range = BacktestDateRange( + start_date=start_date, + end_date=end_date + ) backtest_report = app.run_backtest( algorithm=algorithm, - start_date=start_date, - end_date=end_date, + backtest_date_range=date_range, ) pretty_print_backtest(backtest_report) From 7b8b718cbff037577969304594f9d437ef7262d9 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 22:33:40 +0200 Subject: [PATCH 14/31] Refactor data sources --- examples/bitvavo_trading_bot/bitvavo.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/bitvavo_trading_bot/bitvavo.py b/examples/bitvavo_trading_bot/bitvavo.py index ca75a243..3d7ebffd 100644 --- a/examples/bitvavo_trading_bot/bitvavo.py +++ b/examples/bitvavo_trading_bot/bitvavo.py @@ -38,10 +38,7 @@ class BitvavoTradingStrategy(TradingStrategy): time_unit = TimeUnit.HOUR interval = 2 - market_data_sources = [ - "BTC/EUR-ohlcv", - "BTC/EUR-ticker" - ] + market_data_sources = [bitvavo_btc_eur_ohlcv_2h, bitvavo_btc_eur_ticker] def apply_strategy(self, algorithm, market_data): print(market_data["BTC/EUR-ohlcv"]) From 07f69f2cf95647ebd8d90fd341621529317ba71c Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 22:33:50 +0200 Subject: [PATCH 15/31] Refactor data sources --- examples/coinbase_trading_bot/coinbase.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/coinbase_trading_bot/coinbase.py b/examples/coinbase_trading_bot/coinbase.py index bb47718d..8a922122 100644 --- a/examples/coinbase_trading_bot/coinbase.py +++ b/examples/coinbase_trading_bot/coinbase.py @@ -36,10 +36,7 @@ class CoinBaseTradingStrategy(TradingStrategy): time_unit = TimeUnit.SECOND interval = 5 - market_data_sources = [ - "BTC/EUR-ohlcv", - "BTC/EUR-ticker" - ] + market_data_sources = [coinbase_btc_eur_ticker, coinbase_btc_eur_ohlcv_2h] def apply_strategy(self, algorithm, market_data): pass From bb7d5f69b948ae617bebb50e906e59037a4d6c75 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 22:39:33 +0200 Subject: [PATCH 16/31] Refactor data source registration --- investing_algorithm_framework/__init__.py | 9 +- investing_algorithm_framework/app/app.py | 124 ++++-- investing_algorithm_framework/app/strategy.py | 76 ++++ .../domain/__init__.py | 6 + .../domain/graphs.py | 379 ++++++++++++++++++ .../domain/metrics/__init__.py | 6 + .../domain/metrics/price_efficiency.py | 58 +++ .../models/backtesting/backtest_report.py | 97 ++++- .../domain/models/tracing/__init__.py | 0 .../domain/models/tracing/trace.py | 23 ++ .../domain/utils/backtesting.py | 64 ++- .../models/market_data_sources/csv.py | 85 +++- .../market_service/ccxt_market_service.py | 13 +- .../services/backtesting/backtest_service.py | 111 +++-- .../backtest_market_data_source_service.py | 21 +- 15 files changed, 961 insertions(+), 111 deletions(-) create mode 100644 investing_algorithm_framework/domain/graphs.py create mode 100644 investing_algorithm_framework/domain/metrics/__init__.py create mode 100644 investing_algorithm_framework/domain/metrics/price_efficiency.py create mode 100644 investing_algorithm_framework/domain/models/tracing/__init__.py create mode 100644 investing_algorithm_framework/domain/models/tracing/trace.py diff --git a/investing_algorithm_framework/__init__.py b/investing_algorithm_framework/__init__.py index e7cf2052..f3998e10 100644 --- a/investing_algorithm_framework/__init__.py +++ b/investing_algorithm_framework/__init__.py @@ -10,7 +10,8 @@ TickerMarketDataSource, MarketService, BacktestReportsEvaluation, \ pretty_print_backtest_reports_evaluation, load_backtest_reports, \ RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT, \ - load_backtest_report, BacktestDateRange + load_backtest_report, BacktestDateRange, create_ema_graph, \ + create_prices_graph, create_rsi_graph, get_price_efficiency_ratio from investing_algorithm_framework.infrastructure import \ CCXTOrderBookMarketDataSource, CCXTOHLCVMarketDataSource, \ CCXTTickerMarketDataSource, CSVOHLCVMarketDataSource, \ @@ -67,5 +68,9 @@ "load_backtest_report", "BacktestDateRange", "create_trade_exit_markers_chart", - "create_trade_entry_markers_chart" + "create_trade_entry_markers_chart", + "create_ema_graph", + "create_prices_graph", + "create_rsi_graph", + "get_price_efficiency_ratio" ] diff --git a/investing_algorithm_framework/app/app.py b/investing_algorithm_framework/app/app.py index f8c2548a..4f562b78 100644 --- a/investing_algorithm_framework/app/app.py +++ b/investing_algorithm_framework/app/app.py @@ -254,10 +254,12 @@ def _initialize_app_for_backtest( before running a backtest or a set of backtests and should be called once. - :param backtest_date_range: instance of BacktestDateRange - :param pending_order_check_interval: The interval at which to check - pending orders (e.g. 1h, 1d, 1w) - :return: None + Args: + backtest_date_range: instance of BacktestDateRange + pending_order_check_interval: The interval at which to check + pending orders (e.g. 1h, 1d, 1w) + + Return None """ # Set all config vars for backtesting configuration_service = self.container.configuration_service() @@ -275,7 +277,18 @@ def _initialize_app_for_backtest( # Create resource dir if not exits self._create_resource_directory_if_not_exists() - def _initialize_algorithm_for_backtest(self, algorithm): + def _create_backtest_database_if_not_exists(self): + """ + Create the backtest database if it does not exist. This method + should be called before running a backtest for an algorithm. + It creates the database if it does not exist. + + Args: + None + + Returns + None + """ configuration_service = self.container.configuration_service() resource_dir = configuration_service.config[RESOURCE_DIRECTORY] @@ -301,15 +314,27 @@ def _initialize_algorithm_for_backtest(self, algorithm): setup_sqlalchemy(self) create_all_tables() - # Override the MarketDataSourceService service with the backtest - # market data source service equivalent. Additionally, convert the - # market data sources to backtest market data sources - # Get all market data source services - market_data_sources = self._market_data_source_service\ + def _initialize_backtest_data_sources(self, algorithm): + """ + Initialize the backtest data sources for the algorithm. This method + should be called before running a backtest. It initializes the + backtest data sources for the algorithm. It takes all registered + data sources and converts them to backtest equivalents + + Args: + algorithm: The algorithm to initialize for backtesting + + Returns + None + """ + + market_data_sources = self._market_data_source_service \ .get_market_data_sources() + backtest_market_data_sources = [] if algorithm.data_sources is not None \ and len(algorithm.data_sources) > 0: + for data_source in algorithm.data_sources: self.add_market_data_source(data_source) @@ -324,16 +349,36 @@ def _initialize_algorithm_for_backtest(self, algorithm): if market_data_source is not None: market_data_source.config = self.config - self.container.market_data_source_service.override( - BacktestMarketDataSourceService( - market_data_sources=backtest_market_data_sources, - market_service=self.container.market_service(), - market_credential_service=self.container - .market_credential_service(), - configuration_service=self.container - .configuration_service(), - ) + # Override the market data source service with the backtest market + # data source service + self.container.market_data_source_service.override( + BacktestMarketDataSourceService( + market_data_sources=backtest_market_data_sources, + market_service=self.container.market_service(), + market_credential_service=self.container + .market_credential_service(), + configuration_service=self.container + .configuration_service(), ) + ) + + # Set all data sources to the algorithm + algorithm.add_data_sources(backtest_market_data_sources) + + def _initialize_algorithm_for_backtest(self, algorithm): + """ + Function to initialize the algorithm for backtesting. This method + should be called before running a backtest. It initializes the + all data sources to backtest data sources and overrides the services + with the backtest services equivalents. + + Args: + algorithm: The algorithm to initialize for backtesting + + Return None + """ + self._create_backtest_database_if_not_exists() + self._initialize_backtest_data_sources(algorithm) # Override the portfolio service with the backtest portfolio service self.container.portfolio_service.override( @@ -385,7 +430,6 @@ def _initialize_algorithm_for_backtest(self, algorithm): market_credential_service = self.container.market_credential_service() market_data_source_service = \ self.container.market_data_source_service() - # Initialize all services in the algorithm algorithm.initialize_services( configuration_service=self.container.configuration_service(), @@ -444,17 +488,19 @@ def run( raises an OperationalException. Then it initializes the algorithm with the services and the configuration. - After the algorithm is initialized, it initializes the app and starts - the algorithm. If the app is running in stateless mode, it handles the + If the app is running in stateless mode, it handles the payload. If the app is running in web mode, it starts the web app in a separate thread. - :param payload: The payload to handle if the app is running in - stateless mode - :param number_of_iterations: The number of iterations to run the - algorithm for - :param sync: Whether to sync the portfolio with the exchange - :return: None + Args: + payload: The payload to handle if the app is running in + stateless mode + number_of_iterations: The number of iterations to run the + algorithm for + sync: Whether to sync the portfolio with the exchange + + Returns: + None """ # Run all on_initialize hooks @@ -676,21 +722,21 @@ def run_backtest( Run a backtest for an algorithm. This method should be called when running a backtest. - :param algorithm: The algorithm to run a backtest for (instance of - Algorithm) - :param backtest_date_range: The date range to run the backtest for - (instance of BacktestDateRange) - :param pending_order_check_interval: The interval at which to check - pending orders - :param output_directory: The directory to write the backtest report to - :return: Instance of BacktestReport + Args: + algorithm: The algorithm to run a backtest for (instance of + Algorithm) + backtest_date_range: The date range to run the backtest for + (instance of BacktestDateRange) + pending_order_check_interval: The interval at which to check + pending orders + output_directory: The directory to write the backtest report to + + Returns: + Instance of BacktestReport """ logger.info("Initializing backtest") self.algorithm = algorithm - market_data_sources = self._market_data_source_service\ - .get_market_data_sources() - self._initialize_app_for_backtest( backtest_date_range=backtest_date_range, pending_order_check_interval=pending_order_check_interval, diff --git a/investing_algorithm_framework/app/strategy.py b/investing_algorithm_framework/app/strategy.py index 8dbaa192..081c96cc 100644 --- a/investing_algorithm_framework/app/strategy.py +++ b/investing_algorithm_framework/app/strategy.py @@ -2,6 +2,7 @@ from investing_algorithm_framework.domain import \ TimeUnit, StrategyProfile, Trade from .algorithm import Algorithm +import pandas as pd class TradingStrategy: @@ -11,6 +12,7 @@ class TradingStrategy: strategy_id: str = None decorated = None market_data_sources = None + traces = None def __init__( self, @@ -46,6 +48,8 @@ def __init__( if strategy_id is not None: self.strategy_id = strategy_id + else: + self.strategy_id = self.worker_id # Check if time_unit is None if self.time_unit is None: @@ -59,6 +63,9 @@ def __init__( f"Interval not set for strategy instance {self.strategy_id}" ) + # context initialization + self._context = None + def run_strategy(self, algorithm, market_data): # Check pending orders before running the strategy algorithm.check_pending_orders() @@ -135,3 +142,72 @@ def strategy_identifier(self): return self.strategy_id return self.worker_id + + @property + def context(self): + return self._context + + @context.setter + def context(self, context): + self._context = context + + def add_trace( + self, + symbol: str, + data, + drop_duplicates=True + ) -> None: + """ + Add data to the straces object for a given symbol + + Args: + symbol (str): The symbol + data (pd.DataFrame): The data to add to the tracing + drop_duplicates (bool): Drop duplicates + + Returns: + None + """ + + # Check if data is a DataFrame + if not isinstance(data, pd.DataFrame): + raise ValueError( + "Currently only pandas DataFrames are " + "supported as tracing data objects." + ) + + data: pd.DataFrame = data + + # Check if index is a datetime object + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("Dataframe Index must be a datetime object.") + + if self.traces is None: + self.traces = {} + + # Check if the key is already in the context dictionary + if symbol in self.traces: + # If the key is already in the context dictionary, + # append the new data to the existing data + combined = pd.concat([self.traces[symbol], data]) + else: + # If the key is not in the context dictionary, + # add the new data to the context dictionary + combined = data + + if drop_duplicates: + # Drop duplicates and sort the data by the index + combined = combined[~combined.index.duplicated(keep='first')] + + # Set the datetime column as the index + combined.set_index(pd.DatetimeIndex(combined.index), inplace=True) + self.traces[symbol] = combined + + def get_traces(self) -> dict: + """ + Get the traces object + + Returns: + dict: The traces object + """ + return self.traces diff --git a/investing_algorithm_framework/domain/__init__.py b/investing_algorithm_framework/domain/__init__.py index 2f953f17..46f009bd 100644 --- a/investing_algorithm_framework/domain/__init__.py +++ b/investing_algorithm_framework/domain/__init__.py @@ -30,6 +30,8 @@ load_backtest_report, \ csv_to_list, StoppableThread, pretty_print_backtest_reports_evaluation, \ pretty_print_backtest, load_csv_into_dict, load_backtest_reports +from .graphs import create_prices_graph, create_ema_graph, create_rsi_graph +from .metrics import get_price_efficiency_ratio __all__ = [ 'Config', @@ -114,4 +116,8 @@ "RoundingService", "BacktestDateRange", "load_backtest_report", + "create_prices_graph", + "create_ema_graph", + "create_rsi_graph", + "get_price_efficiency_ratio" ] diff --git a/investing_algorithm_framework/domain/graphs.py b/investing_algorithm_framework/domain/graphs.py new file mode 100644 index 00000000..dbfe8f76 --- /dev/null +++ b/investing_algorithm_framework/domain/graphs.py @@ -0,0 +1,379 @@ +import pandas as pd +import plotly.graph_objs as go + + +def create_rsi_graph(data: pd.DataFrame): + """ + Create a graph for the RSI metric. + :param data: DataFrame with a 'RSI' column and a Datetime index + :return: Plotly graph object + """ + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + + # Check if the 'RSI' column exists + if 'RSI' not in data.columns: + raise ValueError("The data should have a 'RSI' column") + + return go.Scatter( + x=data.index, + y=data['RSI'], + mode='lines', + line=dict(color="green", width=1), + name="RSI" + ) + + +def create_prices_graph( + data: pd.DataFrame, + data_key="Close", + graph_name="Price", + color="blue", + line_width=1 +): + """ + Create a graph for the close prices. By default, the key is set to 'Close'. + + Args: + data (pd.DataFrame): The data to plot + data_key (str): The key to use for the prices + graph_name (str): The name of the graph + color (str): The color of the graph + line_width (int): The width of the line + + Returns: + go.Scatter: The Plotly graph object + """ + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the 'Close' column exists + if data_key not in data.columns: + raise ValueError("The data should have a 'Close' column") + + return go.Scatter( + x=data.index, + y=data[data_key], + mode='lines', + line=dict(color=color, width=line_width), + name=graph_name + ) + +def create_adx_graph(data: pd.DataFrame): + """ + Create a graph for the ADX metric. + :param data: DataFrame with a 'ADX' column and a Datetime index + :return: Plotly graph object + """ + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the 'ADX' column exists + if 'ADX' not in data.columns: + raise ValueError("The data should have a 'ADX' column") + + return go.Scatter( + x=data.index, + y=data['ADX'], + mode='lines', + line=dict(color="green", width=1), + name="ADX" + ) + +def create_di_plus_graph(data: pd.DataFrame): + """ + Create a graph for the DI+ metric. + :param data: DataFrame with a '+DI' column and a Datetime index + :return: Plotly graph object + """ + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the '+DI' column exists + if '+DI' not in data.columns: + raise ValueError("The data should have a '+DI' column") + + return go.Scatter( + x=data.index, + y=data['+DI'], + mode='lines', + line=dict(color="orange", width=1), + name="+DI" + ) + +def create_di_minus_graph(data: pd.DataFrame): + """ + Create a graph for the DI- metric. + :param data: DataFrame with a '-DI' column and a Datetime index + :return: Plotly graph object + """ + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the '-DI' column exists + if '-DI' not in data.columns: + raise ValueError("The data should have a '-DI' column") + + return go.Scatter( + x=data.index, + y=data['-DI'], + mode='lines', + line=dict(color="purple", width=1), + name="-DI" + ) + +def create_di_plus_di_minus_crossover_graph(data: pd.DataFrame): + """ + Create a graph for the DI- and DI+ crossover. + """ + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the '-DI' and '+DI' columns exist + if '-DI' not in data.columns or '+DI' not in data.columns: + raise ValueError("The data should have a '-DI' and '+DI' column") + + # Get all crossover indexes + crossover_index = data[(data['+DI'] < data['-DI']) & (data['+DI'].shift(1) > data['-DI'].shift(1))].index + + # Use .loc to get the corresponding 'Close' values + crossover_close_values = data.loc[crossover_index, '+DI'] + + return go.Scatter( + x=crossover_index, + y=crossover_close_values, + mode='markers', + marker=dict(symbol='circle', size=10, color='blue'), + name='DI- DI+ Crossover' + ) + + +def create_ema_graph(data: pd.DataFrame, key, color="blue"): + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the key columns exist + if key not in data.columns: + raise ValueError(f"The data should have a {key} column") + + + return go.Scatter( + x=data.index, + y=data[key], + mode='lines', + line=dict(color=color, width=1), + name=key + ) + +def create_crossover_graph(data: pd.DataFrame, key_one, key_two, color="blue"): + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + # Check if the key columns exist + if key_one not in data.columns or key_two not in data.columns: + raise ValueError(f"The data should have a {key_one} and {key_two} column") + + # Get all crossover indexes + crossover_index = data[(data[key_one] <= data[key_two]) & (data[key_one].shift(1) >= data[key_two].shift(1))].index + + # Use .loc to get the corresponding 'Close' values + crossover_close_values = data.loc[crossover_index, key_one] + + return go.Scatter( + x=crossover_index, + y=crossover_close_values, + mode='markers', + marker=dict(symbol='circle', size=10, color=color), + name=f'{key_one} {key_two} Crossover' + ) + +def create_peaks_chart(data: pd.DataFrame, key="Close", order = 5): + + # Check if the index is of type datetime + if not isinstance(data.index, pd.DatetimeIndex): + raise ValueError("The index of the data should be of type datetime") + + keys = [f'{key}_highs', f'{key}_lows'] + + for key_column in keys: + if key_column not in data.columns: + raise ValueError(f"The data should have a '{key_column}' column") + + # Get all peak indexes + hh_close_index = data[data[f'{key}_highs'] == 1].index + lh_close_index = data[data[f'{key}_highs'] == -1].index + ll_close_index = data[data[f'{key}_lows'] == 1].index + hl_close_index = data[data[f'{key}_lows'] == -1].index + + # Subtract for each index 10 hours + # hh_close_index = hh_close_index - pd.Timedelta(hours=2 * order) + # lh_close_index = lh_close_index - pd.Timedelta(hours=2 * order) + # ll_close_index = ll_close_index - pd.Timedelta(hours=2 * order) + # hl_close_index = hl_close_index - pd.Timedelta(hours=2 * order) + # hh_close_index = hh_close_index + # lh_close_index = lh_close_index + # ll_close_index = ll_close_index + # hl_close_index = hl_close_index + + # Use .loc to get the corresponding 'Close' values if the index is in the DataFrame + hh_close_values = data.loc[hh_close_index, key] + lh_close_values = data.loc[lh_close_index, key] + ll_close_values = data.loc[ll_close_index, key] + hl_close_values = data.loc[hl_close_index, key] + + # Add higher highs + higher_high_graph = go.Scatter( + x=hh_close_index, + # x=dates[hh_close_index - order].values, + y=hh_close_values, + mode='markers', + marker=dict(symbol='triangle-up', size=10, color='blue'), + name='Higher High Confirmation' + ) + + # Add lower highs + lower_high_graph = go.Scatter( + x=lh_close_index, + y=lh_close_values, + mode='markers', + marker=dict(symbol='triangle-down', size=10, color='red'), + name='Lower High Confirmation' + ) + + # Add lower lows + lower_lows_graph = go.Scatter( + x=ll_close_index, + y=ll_close_values, + mode='markers', + marker=dict(symbol='triangle-down', size=10, color='green'), + name='Lower Lows Confirmation' + ) + + # Add higher lows + higher_lows = go.Scatter( + x=hl_close_index, + y=hl_close_values, + mode='markers', + marker=dict(symbol='triangle-up', size=10, color='purple'), + name='Higher Lows Confirmation' + ) + + return higher_high_graph, lower_high_graph, lower_lows_graph, higher_lows + + +def create_bullish_divergence_chart(data: pd.DataFrame, key_one, key_two, color = 'red'): + """ + A bullish divergence occurs when the "_lows" makes a new low but the "_lows" makes a higher low. + + For example, if the RSI makes a new low but the close price makes a higher low, then we have a bullish divergence. + """ + divergence_index = data[(data[f'{key_one}_lows'] == -1) & (data[f'{key_two}_lows'] == 1)].index + divergence_close_values = data.loc[divergence_index, 'Close'] + + return go.Scatter( + x=divergence_index, + y=divergence_close_values, + mode='markers', + marker=dict(symbol='circle', size=10, color=color), + name='Bullish Divergence' + ) + + +def create_bearish_divergence_chart(data: pd.DataFrame, key_one, key_two, color = 'red'): + """ + A bearish divergence occurs when the "_highs" makes a new high but the "_highs" makes a lower high. + + For example, if the RSI makes a new high but the close price makes a lower high, then we have a bearish divergence. + """ + + # Add divergence charts + divergence_index = data[(data[f'{key_one}_highs'] == -1) & (data[f'{key_two}_highs'] == 1)].index + divergence_close_values = data.loc[divergence_index, 'Close'] + + return go.Scatter( + x=divergence_index, + y=divergence_close_values, + mode='markers', + marker=dict(symbol='circle', size=10, color=color), + name='Bearish Divergence' + ) + + +def create_entry_graph(data: pd.DataFrame): + + + # Iterate over each row in the DataFrame and check if there is a bullish divergence between the RSI and the close price + # and if there is a crossover between the DI+ and DI- for the last 12 hours (6 candles) + # Get all crossover indexes + crossover_index = data[(data['+DI'] <= data['-DI']) & (data['+DI'].shift(1) >= data['-DI'].shift(1))].index + data['di_crossover'] = 0 + data.loc[crossover_index, 'di_crossover'] = 1 + + entry_indexes = [] + + for row in data.itertuples(): + + if row.di_crossover == 1: + match = False + # Check if there was a bullish divergence between the RSI and the close price in the last 2 days + rsi_window = data.loc[row.Index - pd.Timedelta(days=2):row.Index, 'RSI_lows'] + close_window = data.loc[row.Index - pd.Timedelta(days=2):row.Index, 'Close_lows'] + + # Go over each row and check if there is a bullish divergence between the RSI and the close price + for rsi_row, close_row in zip(rsi_window, close_window): + + if rsi_row == -1 and close_row == 1: + entry_indexes.append(row.Index) + match = True + break + + if not match: + # Check if the RSI had decreased + rsi_window = data.loc[row.Index - pd.Timedelta(days=1):row.Index, 'RSI'] + rsi_diff = rsi_window.diff().mean() + + if rsi_diff < -2: + entry_indexes.append(row.Index) + + # If ema 50 < + + # # Check if there is a bullish divergence between the RSI and the close price + # if row.Close_lows == 1 and row.RSI_lows == -1: + # + # # Check if there is a crossover in the last 12 hours + # crossovers = data.loc[row.Index - pd.Timedelta(hours=12):row.Index, 'di_crossover'] + # + # if crossovers.sum() > 0: + # entry_indexes.append(row.Index) + + # adx_window = data.loc[row.Index - pd.Timedelta(hours=4):row.Index, 'ADX'] + # rsi_window = data.loc[row.Index - pd.Timedelta(hours=4):row.Index, 'RSI'] + # adx_diff = adx_window.diff().mean() + # rsi_diff = rsi_window.diff().mean() + # + # if adx_diff > -2 and adx_diff < 0: + # entry_indexes.append(row.Index) + + entry_close_values = data.loc[entry_indexes, 'Close'] + return go.Scatter( + x=entry_indexes, + y=entry_close_values, + mode='markers', + marker=dict(symbol='circle', size=10, color='green'), + name='Entry Signal' + ) \ No newline at end of file diff --git a/investing_algorithm_framework/domain/metrics/__init__.py b/investing_algorithm_framework/domain/metrics/__init__.py new file mode 100644 index 00000000..44e01fc2 --- /dev/null +++ b/investing_algorithm_framework/domain/metrics/__init__.py @@ -0,0 +1,6 @@ +from .price_efficiency import get_price_efficiency_ratio + + +__all__ = [ + "get_price_efficiency_ratio" +] diff --git a/investing_algorithm_framework/domain/metrics/price_efficiency.py b/investing_algorithm_framework/domain/metrics/price_efficiency.py new file mode 100644 index 00000000..e5af09bd --- /dev/null +++ b/investing_algorithm_framework/domain/metrics/price_efficiency.py @@ -0,0 +1,58 @@ +import logging +from pandas import DataFrame, DatetimeIndex +from investing_algorithm_framework.domain.exceptions import \ + OperationalException + +logger = logging.getLogger(__name__) + + +def get_price_efficiency_ratio(data: DataFrame): + """ + Calculate the price efficiency ratio (noise) for each symbol. + + The price efficiency ratio is calculated as follows: + + 1. Calculate the net price change over the period + 2. Calculate the sum of absolute daily price changes + 3. Calculate Efficiency Ratio = Net Price Change / Sum of Absolute + Daily Price Changes + + The price efficiency ratio is a measure of the efficiency of the + price movement over the period. A higher efficiency ratio indicates + a more efficient price movement. + + Args: + data (dict): A pandas DataFrame containing a column with either a + 'Close' or 'Price' label and a datetime index. + + returns: + float: The price efficiency ratio + """ + + # Check if close value and index is a datetime object + if 'Close' not in data.columns: + raise OperationalException( + "Close column not found in data, " + "required for price efficiency ratio calculation" + ) + + if not isinstance(data.index, DatetimeIndex): + raise OperationalException( + "Index is not a datetime object," + "required for price efficiency ratio calculation" + ) + + # Calculate daily price changes + data['Daily Change'] = data['Close'].diff() + + # Calculate net price change over the period + net_price_change = abs( + data['Close'].iloc[-1] - data['Close'].iloc[0]) + + # Calculate the sum of absolute daily price changes + sum_absolute_changes = data['Daily Change'] \ + .abs().sum() + + # Calculate Efficiency Ratio + return net_price_change / sum_absolute_changes + diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py index 04c63d84..dcc200ec 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py @@ -1,14 +1,23 @@ +from logging import getLogger from datetime import datetime -from pandas import DataFrame +from pandas import DataFrame, to_datetime, DatetimeIndex from investing_algorithm_framework.domain.models.base_model import BaseModel from investing_algorithm_framework.domain.models.time_unit import TimeUnit from investing_algorithm_framework.domain.models\ .backtesting.backtest_date_range import BacktestDateRange from investing_algorithm_framework.domain.constants import DATETIME_FORMAT +from investing_algorithm_framework.domain.metrics import \ + get_price_efficiency_ratio + +logger = getLogger(__name__) class BacktestReport(BaseModel): + """ + Class that represents a backtest report. The backtest report + contains information about the backtest. + """ def __init__( self, @@ -45,13 +54,14 @@ def __init__( created_at: datetime = None, context=None, ): + self._traces = {} + self.metrics = {} self._name = name self._strategy_identifiers = strategy_identifiers self.backtest_date_range = backtest_date_range self._number_of_runs = number_of_runs self._trading_time_frame = trading_time_frame self._trading_time_frame_start_date = trading_time_frame_start_date - self._symbols = symbols self._market = market self._number_of_orders = number_of_orders self._number_of_positions = number_of_positions @@ -77,10 +87,17 @@ def __init__( self._interval = interval self._time_unit = time_unit self._context = context + + self._symbols = symbols + + if self._symbols is None: + self._symbols = [] + self._number_of_days = \ (self.backtest_date_range.end_date - self.backtest_date_range.start_date).days + @property def name(self): return self._name @@ -485,3 +502,79 @@ def get_growth_percentage(self) -> float: def get_trading_symbol(self) -> str: return self.trading_symbol + + def add_symbol(self, symbol): + + if symbol not in self.symbols: + self.symbols.append(symbol) + + def calculate_metrics(self): + """ + Parent method to calculate all metrics. + + returns: + None + """ + if self.traces is not None: + self.metrics['efficiency_ratio'] = {} + + for strategy_id in self.traces: + entries = self.traces[strategy_id] + + if entries is None: + continue + + for symbol in entries: + + self.metrics['efficiency_ratio'][symbol] = \ + get_price_efficiency_ratio( + self.traces[strategy_id][symbol] + ) + + @property + def traces(self): + """ + Get the traces of the backtest report. + """ + return self._traces + + @traces.setter + def traces(self, value): + """ + Set the traces of the backtest report. + + Args: + value (dict): The traces of the backtest report. + + returns: + None + """ + self._traces = value + + def get_trace(self, symbol, strategy_id = None): + """ + Get the trace for a given symbol. If a strategy_id is provided, + it will return the trace for that strategy. + + Args: + symbol (str): The symbol + strategy_id (str): The + """ + + if strategy_id is None: + + for strategy_id, trace in self.traces.items(): + + if symbol in trace: + return trace[symbol] + + else: + if strategy_id in self.traces: + return self.traces[strategy_id][symbol] + + else: + raise ValueError( + f"Trace {symbol} for strategy {strategy_id} not found" + ) + + return None diff --git a/investing_algorithm_framework/domain/models/tracing/__init__.py b/investing_algorithm_framework/domain/models/tracing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/investing_algorithm_framework/domain/models/tracing/trace.py b/investing_algorithm_framework/domain/models/tracing/trace.py new file mode 100644 index 00000000..ccc5c808 --- /dev/null +++ b/investing_algorithm_framework/domain/models/tracing/trace.py @@ -0,0 +1,23 @@ +class Trace: + """ + Represents a trace of a trading strategy. A trace contains + data that has been generated by a trading strategy during its + execution. + + The data can be used to analyze the performance of the trading after + it has been executed. Usually, the data contains metrics that + have been generated by the trading strategy during its execution, + and the signals that have been generated. + """ + + def __init__( + self, + strategy_id: str, + symbol: str, + data, + drop_duplicates=True + ): + self.strategy_id = strategy_id + self.symbol = symbol + self.data = data + self.drop_duplicates = drop_duplicates diff --git a/investing_algorithm_framework/domain/utils/backtesting.py b/investing_algorithm_framework/domain/utils/backtesting.py index 1f89641a..23b45b44 100644 --- a/investing_algorithm_framework/domain/utils/backtesting.py +++ b/investing_algorithm_framework/domain/utils/backtesting.py @@ -145,6 +145,67 @@ def pretty_print_date_ranges(date_ranges: List[BacktestDateRange]) -> None: print(f"{COLOR_GREEN}{start_date} - {end_date}{COLOR_RESET}") +def pretty_print_price_efficiency(reports, precision=4): + """ + Pretty print the price efficiency of the backtest reports evaluation + to the console. + """ + # Get all symbols of the reports + print(f"{COLOR_YELLOW}Price noise{COLOR_RESET}") + rows = [] + + for report in reports: + + if report.metrics is not None and "efficiency_ratio" in report.metrics: + price_efficiency = report.metrics["efficiency_ratio"] + + for symbol in price_efficiency: + row = {} + row["Symbol"] = symbol + row["Efficiency ratio / Noise"] = f"{price_efficiency[symbol]:.{precision}f}" + row["Date"] = f"{report.backtest_start_date} - {report.backtest_end_date}" + + + + + if report.backtest_date_range.name is not None: + row["Date"] = f"{report.backtest_date_range.name} " \ + f"{report.backtest_date_range.start_date}" \ + f" - {report.backtest_date_range.end_date}" + else: + row["Date"] = f"{report.backtest_start_date} - " \ + f"{report.backtest_end_date}" + + rows.append(row) + + # Remove all duplicate rows with the same symbol and date range + unique_rows = [] + + # Initialize an empty set to track unique (symbol, date) pairs + seen = set() + # Initialize a list to store the filtered dictionaries + filtered_data = [] + + # Iterate through each dictionary in the list + for entry in rows: + # Extract the (symbol, date) pair + pair = (entry["Symbol"], entry["Date"]) + # Check if the pair is already in the set + if pair not in seen: + # If not, add the pair to the set and + # the entry to the filtered list + seen.add(pair) + filtered_data.append(entry) + + print( + tabulate( + filtered_data, + headers="keys", + tablefmt="rounded_grid" + ) + ) + + def pretty_print_most_profitable( evaluation: BacktestReportsEvaluation, backtest_date_range: BacktestDateRange, @@ -196,7 +257,6 @@ def pretty_print_backtest_reports_evaluation( most_profitable = backtest_reports_evaluation.get_profit_order(backtest_date_range)[0] most_growth = backtest_reports_evaluation.get_growth_order(backtest_date_range)[0] - ascii_art = f""" :%%%#+- .=*#%%% {COLOR_GREEN}Backtest reports evaluation{COLOR_RESET} *%%%%%%%+------=*%%%%%%%- {COLOR_GREEN}---------------------------{COLOR_RESET} @@ -229,6 +289,7 @@ def pretty_print_backtest_reports_evaluation( pretty_print_date_ranges(backtest_reports_evaluation.get_date_ranges()) print("") + pretty_print_price_efficiency(reports, precision=precision) print(f"{COLOR_YELLOW}All profits ordered{COLOR_RESET}") pretty_print_profit_evaluation( backtest_reports_evaluation.get_profit_order(backtest_date_range), precision @@ -284,6 +345,7 @@ def pretty_print_backtest( """ print(ascii_art) + pretty_print_price_efficiency([backtest_report], precision=precision) if show_positions: print(f"{COLOR_YELLOW}Positions overview{COLOR_RESET}") diff --git a/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py b/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py index 71d13004..cd601560 100644 --- a/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +++ b/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py @@ -17,7 +17,9 @@ class CSVOHLCVMarketDataSource(OHLCVMarketDataSource): Market data source that reads OHLCV data from a csv file. """ - def empty(self, start_date, end_date): + def empty(self, start_date, end_date=None): + if end_date is None: + end_date = self.create_end_date(start_date, self.timeframe, self.window_size) data = self.get_data(start_date=start_date, end_date=end_date) return len(data) == 0 @@ -69,6 +71,16 @@ def get_data(self, **kwargs): the start_date and end_date in the kwargs. backtest_index_date can also be provided to filter the data, where this will be used as start_date. + + Args: + **kwargs: Keyword arguments that can contain the following: + start_date (datetime): The start date to filter the data. + end_date (datetime): The end date to filter the data. + backtest_index_date (datetime): The backtest index date to + filter the data. This will be used as start_date. + + Returns: + df (polars.DataFrame): The data from the csv file. """ start_date = kwargs.get("start_date") end_date = kwargs.get("end_date") @@ -97,17 +109,19 @@ def get_data(self, **kwargs): start_date, self.timeframe, self.window_size ) - if start_date > self._start_date_data_source: - raise OperationalException( - f"Start date {start_date} is before the start date " - f"of the data source {self._start_date_data_source}" - ) - - if end_date < self._end_date_data_source: - raise OperationalException( - f"End date {end_date} is after the end date " - f"of the data source {self._end_date_data_source}" - ) + # # Check if start or end date are out of range with + # # the dates of the datasource. + # if self._start_date_data_source > start_date: + # raise OperationalException( + # f"Given start date {start_date} is before the start date " + # f"of the data source {self._start_date_data_source}" + # ) + # + # if self._end_date_data_source < end_date: + # raise OperationalException( + # f"End date {end_date} is after the end date " + # f"of the data source {self._end_date_data_source}" + # ) df = polars.read_csv( self.csv_file_path, columns=self._columns, separator="," @@ -158,27 +172,62 @@ def __init__( f"Missing columns: {missing_columns}" ) + first_row = df.head(1) + last_row = df.tail(1) + self._start_date_data_source = parse(first_row["Datetime"][0]) + self._end_date_data_source = parse(last_row["Datetime"][0]) + @property def csv_file_path(self): return self._csv_file_path - def get_data(self, index_datetime=None, **kwargs): + def get_data(self, **kwargs): + date = None - if index_datetime is None: - index_datetime = datetime.utcnow() + if "index_datetime" in kwargs: + date = kwargs["index_datetime"] + + if "start_date" in kwargs: + date = kwargs["start_date"] + + if 'date' in kwargs: + date = kwargs['date'] + + if date is None: + raise OperationalException("Date is required to get ticker data") + + if not isinstance(date, datetime): + + if isinstance(date, str): + date = parse(date) + else: + raise OperationalException( + "Date value should be either a string or datetime object" + ) + + if date < self._start_date_data_source: + raise OperationalException( + f"Date {date} is before the start date " + f"of the data source {self._start_date_data_source}" + ) + + if date > self._end_date_data_source: + raise OperationalException( + f"Date {date} is after the end date " + f"of the data source {self._end_date_data_source}" + ) # Filter the data based on the backtest index date and the end date df = polars.read_csv(self._csv_file_path) df = df.filter( - (df['Datetime'] >= index_datetime - .strftime(DATETIME_FORMAT)) + (df['Datetime'] >= date.strftime(DATETIME_FORMAT)) ) # Check if the dataframe is empty if df.shape[0] == 0: raise OperationalException( f"No ticker data found for {self.symbol} " - f"at {index_datetime}" + f"at {date.strftime(DATETIME_FORMAT)}" ) first_row = df.head(1)[0] diff --git a/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py b/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py index 64168488..5ff47dbd 100644 --- a/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +++ b/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py @@ -269,11 +269,11 @@ def create_limit_sell_order( raise OperationalException("Could not create limit sell order") def create_market_sell_order( - self, - target_symbol: str, - trading_symbol: str, - amount: float, - market + self, + target_symbol: str, + trading_symbol: str, + amount: float, + market ): market_credential = self.get_market_credential(market) exchange = self.initialize_exchange(market, market_credential) @@ -358,10 +358,11 @@ def get_ohlcv( ) -> pl.DataFrame: time_frame = TimeFrame.from_value(time_frame).value - if self.config is not None: + if self.config is not None and "DATETIME_FORMAT" in self.config: datetime_format = self.config["DATETIME_FORMAT"] else: datetime_format = DATETIME_FORMAT + market_credential = self.get_market_credential(market) exchange = self.initialize_exchange(market, market_credential) diff --git a/investing_algorithm_framework/services/backtesting/backtest_service.py b/investing_algorithm_framework/services/backtesting/backtest_service.py index 54f16214..bd5a919c 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_service.py @@ -61,10 +61,14 @@ def run_backtest( Also, all backtest data is downloaded (if not already downloaded) and the backtest is run for each date in the schedule. - :param algorithm: The algorithm to run the backtest for - :param backtest_date_range: The backtest date range + At the end of the run all traces - :return: The backtest report instance of BacktestReport + Args: + algorithm: The algorithm to run the backtest for + backtest_date_range: The backtest date range + + return: + BacktestReport: The backtest report """ strategy_profiles = [] portfolios = self._portfolio_repository.get_all() @@ -145,14 +149,25 @@ def run_backtest_for_profile(self, algorithm, strategy, index_date): market_data[data_id] = \ self._market_data_source_service.get_data(data_id) + strategy.context = algorithm.context strategy.run_strategy(algorithm=algorithm, market_data=market_data) def generate_schedule( - self, - strategies, - start_date, - end_date - ): + self, strategies, start_date, end_date + ) -> pd.DataFrame: + """ + Generate a schedule for the given strategies. This function will + calculate when the strategies should run based on the given start + and end date. The schedule will be stored in a pandas DataFrame. + + Args: + strategies: The strategies to generate the schedule for + start_date: The start date of the schedule + end_date: The end date of the schedule + + Returns: + pd.DataFrame: The schedule DataFrame + """ data = [] for strategy in strategies: @@ -212,12 +227,17 @@ def create_backtest_report( the backtest report instance. It will calculate various performance metrics for the backtest. + Also, it will add all traces to the backtest report. The traces + are collected from each strategy that was run during the backtest. + + Args: + algorithm: The algorithm to create the backtest report for + number_of_runs: The number of runs + backtest_date_range: The backtest date range of the backtest + initial_unallocated: The initial unallocated amount - :param algorithm: The algorithm to create the backtest report for - :param number_of_runs: The number of runs - :param backtest_date_range: The backtest date range of the backtest - :param initial_unallocated: The initial unallocated amount - :return: The backtest report instance of BacktestReport + Returns: + BacktestReport: The backtest report instance of BacktestReport """ for portfolio in self._portfolio_repository.get_all(): @@ -228,7 +248,7 @@ def create_backtest_report( # Remove None from ids ids = [x for x in ids if x is not None] - backtest_profile = BacktestReport( + backtest_report = BacktestReport( name=algorithm.name, strategy_identifiers=ids, backtest_date_range=backtest_date_range, @@ -236,33 +256,33 @@ def create_backtest_report( trading_symbol=portfolio.trading_symbol, created_at=datetime.utcnow(), ) - backtest_profile.number_of_runs = number_of_runs - backtest_profile.number_of_orders = self._order_service.count({ + backtest_report.number_of_runs = number_of_runs + backtest_report.number_of_orders = self._order_service.count({ "portfolio": portfolio.id }) - backtest_profile.number_of_positions = \ + backtest_report.number_of_positions = \ self._position_repository.count({ "portfolio": portfolio.id, "amount_gt": 0 }) - backtest_profile.percentage_negative_trades = \ + backtest_report.percentage_negative_trades = \ self._performance_service \ .get_percentage_negative_trades(portfolio.id) - backtest_profile.percentage_positive_trades = \ + backtest_report.percentage_positive_trades = \ self._performance_service \ .get_percentage_positive_trades(portfolio.id) - backtest_profile.number_of_trades_closed = \ + backtest_report.number_of_trades_closed = \ self._performance_service \ .get_number_of_trades_closed(portfolio.id) - backtest_profile.number_of_trades_open = \ + backtest_report.number_of_trades_open = \ self._performance_service \ .get_number_of_trades_open(portfolio.id) - backtest_profile.total_cost = portfolio.total_cost - backtest_profile.total_net_gain = portfolio.total_net_gain - backtest_profile.total_net_gain_percentage = \ + backtest_report.total_cost = portfolio.total_cost + backtest_report.total_net_gain = portfolio.total_net_gain + backtest_report.total_net_gain_percentage = \ self._performance_service \ .get_total_net_gain_percentage_of_backtest( - portfolio.id, backtest_profile + portfolio.id, backtest_report ) positions = self._position_repository.get_all({ "portfolio": portfolio.id @@ -297,20 +317,20 @@ def create_backtest_report( market=portfolio.market ) - backtest_profile.growth_rate = self._performance_service \ + backtest_report.growth_rate = self._performance_service \ .get_growth_rate_of_backtest( - portfolio.id, tickers, backtest_profile + portfolio.id, tickers, backtest_report ) - backtest_profile.growth = self._performance_service \ + backtest_report.growth = self._performance_service \ .get_growth_of_backtest( - portfolio.id, tickers, backtest_profile + portfolio.id, tickers, backtest_report ) - backtest_profile.total_value = self._performance_service \ - .get_total_value(portfolio.id, tickers, backtest_profile) - backtest_profile.average_trade_duration = \ + backtest_report.total_value = self._performance_service \ + .get_total_value(portfolio.id, tickers, backtest_report) + backtest_report.average_trade_duration = \ self._performance_service \ .get_average_trade_duration(portfolio.id) - backtest_profile.average_trade_size = \ + backtest_report.average_trade_size = \ self._performance_service.get_average_trade_size(portfolio.id) positions = self._position_repository.get_all({ "portfolio": portfolio.id @@ -323,7 +343,7 @@ def create_backtest_report( backtest_position = BacktestPosition( position, trading_symbol=True, - total_value_portfolio=backtest_profile.total_value + total_value_portfolio=backtest_report.total_value ) backtest_position.price = 1 else: @@ -353,7 +373,7 @@ def create_backtest_report( position, amount_pending_buy=amount_in_pending_buy_orders, amount_pending_sell=amount_in_pending_sell_orders, - total_value_portfolio=backtest_profile.total_value + total_value_portfolio=backtest_report.total_value ) # Probably not needed @@ -365,11 +385,22 @@ def create_backtest_report( ) backtest_position.price = ticker["bid"] backtest_positions.append(backtest_position) - backtest_profile.positions = backtest_positions - backtest_profile.trades = algorithm.get_trades() - backtest_profile.orders = orders - backtest_profile.context = algorithm.context - return backtest_profile + backtest_report.positions = backtest_positions + backtest_report.trades = algorithm.get_trades() + backtest_report.orders = orders + backtest_report.context = algorithm.context + traces = {} + + # Add traces to the backtest report + for strategy in algorithm.strategies: + strategy_traces = strategy.get_traces() + traces[strategy.strategy_id] = strategy_traces + + backtest_report.traces = traces + + # Calculate metrics for the backtest report + backtest_report.calculate_metrics() + return backtest_report def set_backtest_market_data_sources(self, market_data_sources): self._backtest_market_data_sources = market_data_sources diff --git a/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py b/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py index 08b1fbaa..6289e112 100644 --- a/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +++ b/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py @@ -35,8 +35,13 @@ def __init__( market_data_sources=None, market_credential_service=market_credential_service, ) - self._market_data_sources: List[BacktestMarketDataSource] \ - = market_data_sources + self.market_data_sources = [] + + # Add all market data sources to the list + if market_data_sources is not None: + for market_data_source in market_data_sources: + self.add(market_data_source) + self._configuration_service: ConfigurationService = \ configuration_service @@ -50,7 +55,6 @@ def __init__( if backtest_market_data_source is not None: backtest_market_data_source.market_credentials_service = \ self._market_credential_service - backtest_market_data_source.prepare_data( config=configuration_service.get_config(), backtest_start_date=configuration_service @@ -133,3 +137,14 @@ def is_ohlcv_data_source_present(self, symbol, time_frame, market): symbol=symbol, market=market, time_frame=time_frame ) return market_data_source is not None + + def add(self, market_data_source): + + # Check if there is already a market data source with the same + # identifier + for existing_market_data_source in self._market_data_sources: + if existing_market_data_source.get_identifier() == \ + market_data_source.get_identifier(): + return + + self._market_data_sources.append(market_data_source) \ No newline at end of file From 918f439ce5ec45227c56b23d5374149135147ede Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 22:39:55 +0200 Subject: [PATCH 17/31] Update readme with tracing feature --- README.md | 101 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 470eea18..481e036d 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Features: * Backtesting and performance analysis reports [example](./examples/backtest_example) * Backtesting multiple algorithms with different backtest date ranges [example](./examples/backtests_example) * Portfolio management and tracking +* Tracing for analyzing and debugging your trading bot * Web API for interacting with your deployed trading bot * Data persistence through sqlite db or an in-memory db * Stateless running for cloud function deployments @@ -137,64 +138,82 @@ you will get the following backtesting report: ```bash - /&# #&( Backtest report - &&&&&&&&&&&# &&&&&&&&&&&& --------------------------- - &&&&&&&&&&&&&&&& (&&&&&&&&&&&&&&& Start date: 2023-08-24 00:00:00 - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& End date: 2023-12-02 00:00:00 - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Number of days: 100 - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Number of runs: 1201 - .&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Number of orders: 10 - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&. Initial balance: 400.0 - &&&&&&&# /((( &&&&&&&&&&&&*((( .&&&&&&&. Final balance: 431.1499 - &&&&&&&&&&&&&&&&&&& (((( &&&&&&&& (((( &&&&&&&&&&&&&&&&&&& Total net gain: 28.5542 7.139% - (((&&&&&&&& (((( &&&&&& (((( &&&&&&&&&(( Growth: 31.1499 7.787% - /((((((((((&&&&&&&&&& (((, &&&&&& (((**&&&&&&&&&((((((((((( Number of trades closed: 4 - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Number of trades open(end of backtest): 2 - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Percentage positive trades: 60.0% - &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Percentage negative trades: 20.0% - ((((( &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&( Average trade size: 98.9886 EUR - ((((( &&&&&&&&&&&&&&&&&&&&&&&&, Average trade duration: 184.0 hours - ((((( &&&&&&&&&&&&&# - ((((( #&&&&&&&&&&### - ((((( &&&&&&&&&&&###. - .((((( &&&&&&&&&&&&&&###( - ((((( &&&&&&&&&&&&&&&&#(((/ - ((((( &&&&&&&&&&&&&&&&&&&@(((( - ((((( &&&&&&&&&&&&&&&&&&&&&&(((( - ((((( &&&&&&&&&&&&&&&&&&&&&&&&((((, - .((((( &&&&&&&&&&&&&&&&&&&&&&&&&&(((( - ((((( &&&&&&&&&&&&&&&&&&&&&&&&&&&&(((( - ((((( &&&&&&&&&&&&&&&&&&&&&&&&&&&&&(((( - ((((( &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&(((( - ((((( &&&&&&&&&&&&&&&&&&&&&&&&&&&&&#(((( - (((((((((((((((((((#########&&&&&&&&&&&&&&&&&&&&&&&&&&&&((((( - (((((((((((((((((((((######&&&&&&&&&&&&&&&&&&&&&&&&&&&&(((( + :%%%#+- .=*#%%% Backtest report + *%%%%%%%+------=*%%%%%%%- --------------------------- + *%%%%%%%%%%%%%%%%%%%%%%%- Start date: 2023-08-24 00:00:00 + .%%%%%%%%%%%%%%%%%%%%%%# End date: 2023-12-02 00:00:00 + #%%%####%%%%%%%%**#%%%+ Number of days: 100 + .:-+*%%%%- -+..#%%%+.+- +%%%#*=-: Number of runs: 1201 + .:-=*%%%%. += .%%# -+.-%%%%=-:.. Number of orders: 40 + .:=+#%%%%%*###%%%%#*+#%%%%%%*+-: Initial balance: 400.0 + +%%%%%%%%%%%%%%%%%%%= Final balance: 428.2434 + :++ .=#%%%%%%%%%%%%%*- Total net gain: 28.2434 7.061% + :++: :+%%%%%%#-. Growth: 28.2434 7.061% + :++: .%%%%%#= Number of trades closed: 20 + :++: .#%%%%%#*= Number of trades open(end of backtest): 0 + :++- :%%%%%%%%%+= Percentage positive trades: 30.0% + .++- -%%%%%%%%%%%+= Percentage negative trades: 70.0% + .++- .%%%%%%%%%%%%%+= Average trade size: 100.9692 EUR + .++- *%%%%%%%%%%%%%*+: Average trade duration: 83.6 hours + .++- %%%%%%%%%%%%%%#+= + =++........:::%%%%%%%%%%%%%%*+- + .=++++++++++**#%%%%%%%%%%%%%++. +Price noise + Positions overview ╭────────────┬──────────┬──────────────────────┬───────────────────────┬──────────────┬───────────────┬───────────────────────────┬────────────────┬───────────────╮ │ Position │ Amount │ Pending buy amount │ Pending sell amount │ Cost (EUR) │ Value (EUR) │ Percentage of portfolio │ Growth (EUR) │ Growth_rate │ ├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤ -│ EUR │ 217.044 │ 0 │ 0 │ 217.044 │ 217.044 │ 50.3407% │ 0 │ 0.0000% │ +│ EUR │ 428.243 │ 0 │ 0 │ 428.243 │ 428.243 │ 100.0000% │ 0 │ 0.0000% │ ├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤ -│ BTC │ 0.003 │ 0 │ 0 │ 104.372 │ 106.84 │ 24.7802% │ 2.4678 │ 2.3644% │ +│ DOT │ 0 │ 0 │ 0 │ 0 │ 0 │ 0.0000% │ 0 │ 0.0000% │ ├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤ -│ DOT │ 21.3295 │ 0 │ 0 │ 107.138 │ 107.266 │ 24.8791% │ 0.128 │ 0.1195% │ +│ BTC │ 0 │ 0 │ 0 │ 0 │ 0 │ 0.0000% │ 0 │ 0.0000% │ ╰────────────┴──────────┴──────────────────────┴───────────────────────┴──────────────┴───────────────┴───────────────────────────┴────────────────┴───────────────╯ Trades overview ╭─────────┬─────────────────────┬─────────────────────┬────────────────────┬──────────────┬──────────────────┬───────────────────────┬────────────────────┬─────────────────────╮ │ Pair │ Open date │ Close date │ Duration (hours) │ Size (EUR) │ Net gain (EUR) │ Net gain percentage │ Open price (EUR) │ Close price (EUR) │ ├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ -│ DOT-EUR │ 2023-11-30 18:00:00 │ │ 3207.26 │ 107.138 │ 0 │ 0.0000% │ 5.023 │ │ +│ DOT-EUR │ 2023-11-24 12:00:00 │ 2023-11-27 14:00:00 │ 74 │ 107.55 │ -1.9587 │ -1.8212% │ 4.777 │ 4.69 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-11-20 00:00:00 │ 2023-11-21 08:00:00 │ 32 │ 109.39 │ -4.5949 │ -4.2005% │ 4.9875 │ 4.778 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ BTC-EUR │ 2023-11-19 22:00:00 │ 2023-11-22 00:00:00 │ 50 │ 109.309 │ -2.7624 │ -2.5272% │ 34159.1 │ 33295.9 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ BTC-EUR │ 2023-11-06 12:00:00 │ 2023-11-13 14:00:00 │ 170 │ 107.864 │ 6.1015 │ 5.6567% │ 32685.9 │ 34534.9 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-10-20 12:00:00 │ 2023-10-27 08:00:00 │ 164 │ 99.085 │ 10.9799 │ 11.0813% │ 3.5465 │ 3.9395 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ BTC-EUR │ 2023-10-14 04:00:00 │ 2023-10-27 22:00:00 │ 330 │ 97.4278 │ 24.137 │ 24.7742% │ 25638.9 │ 31990.7 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-10-14 04:00:00 │ 2023-10-17 14:00:00 │ 82 │ 99.5572 │ -1.8877 │ -1.8961% │ 3.56 │ 3.4925 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-10-07 08:00:00 │ 2023-10-08 08:00:00 │ 24 │ 99.9498 │ -1.5708 │ -1.5716% │ 3.8815 │ 3.8205 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ BTC-EUR │ 2023-09-27 10:00:00 │ 2023-10-05 20:00:00 │ 202 │ 98.2888 │ 3.433 │ 3.4927% │ 25202.2 │ 26082.5 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-09-27 10:00:00 │ 2023-10-03 20:00:00 │ 154 │ 98.7893 │ 1.2085 │ 1.2233% │ 3.842 │ 3.889 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-09-25 12:00:00 │ 2023-09-27 04:00:00 │ 40 │ 98.9193 │ -0.5194 │ -0.5251% │ 3.809 │ 3.789 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-09-14 16:00:00 │ 2023-09-18 02:00:00 │ 82 │ 98.9419 │ -0.0912 │ -0.0921% │ 3.799 │ 3.7955 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ BTC-EUR │ 2023-09-07 06:00:00 │ 2023-09-10 16:00:00 │ 82 │ 98.6093 │ 0.3412 │ 0.3460% │ 24051 │ 24134.3 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-09-07 00:00:00 │ 2023-09-09 02:00:00 │ 50 │ 98.9158 │ -0.2358 │ -0.2383% │ 3.986 │ 3.9765 │ +├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ +│ DOT-EUR │ 2023-09-05 14:00:00 │ 2023-09-06 12:00:00 │ 22 │ 99.2132 │ -1.1909 │ -1.2003% │ 3.999 │ 3.951 │ ├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ -│ BTC-EUR │ 2023-11-29 12:00:00 │ │ 3237.26 │ 104.372 │ 0 │ 0.0000% │ 34790.7 │ │ +│ DOT-EUR │ 2023-09-04 16:00:00 │ 2023-09-04 22:00:00 │ 6 │ 99.355 │ -0.5671 │ -0.5708% │ 3.942 │ 3.9195 │ ├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ -│ BTC-EUR │ 2023-11-07 22:00:00 │ 2023-11-14 14:00:00 │ 160 │ 99.2337 │ 2.5395 │ 2.5591% │ 33077.9 │ 33924.4 │ +│ DOT-EUR │ 2023-09-04 10:00:00 │ 2023-09-04 14:00:00 │ 4 │ 99.4774 │ -0.4889 │ -0.4914% │ 3.968 │ 3.9485 │ ├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ -│ BTC-EUR │ 2023-11-06 14:00:00 │ 2023-11-06 18:00:00 │ 4 │ 98.2854 │ -0.4248 │ -0.4322% │ 32761.8 │ 32620.2 │ +│ BTC-EUR │ 2023-08-26 10:00:00 │ 2023-08-26 18:00:00 │ 8 │ 99.0829 │ -0.03 │ -0.0302% │ 24166.6 │ 24159.3 │ ├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ -│ DOT-EUR │ 2023-10-30 04:00:00 │ 2023-11-14 00:00:00 │ 356 │ 100.537 │ 24.2886 │ 24.1588% │ 4.0565 │ 5.0365 │ +│ DOT-EUR │ 2023-08-25 10:00:00 │ 2023-08-28 10:00:00 │ 72 │ 99.659 │ -0.6975 │ -0.6999% │ 4.1435 │ 4.1145 │ ├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤ -│ BTC-EUR │ 2023-09-13 14:00:00 │ 2023-09-22 14:00:00 │ 216 │ 97.8976 │ 2.1508 │ 2.1970% │ 24474.4 │ 25012.1 │ +│ DOT-EUR │ 2023-08-24 00:00:00 │ 2023-08-25 00:00:00 │ 24 │ 99.9999 │ -1.3626 │ -1.3626% │ 4.1465 │ 4.09 │ ╰─────────┴─────────────────────┴─────────────────────┴────────────────────┴──────────────┴──────────────────┴───────────────────────┴────────────────────┴─────────────────────╯ ``` From 8f6b7c857e044efcc5250bc7bdbc5c399575ad13 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 23:47:43 +0200 Subject: [PATCH 18/31] Update flake8 execution --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6ec43140..1b0022ca 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: #---------------------------------------------- - run: python -m pip install black flake8 isort - run: | - flake8 ./investing_algorithm_framework --exclude="investing_algorithm_framework/domain/utils/backtesting.py" + flake8 ./investing_algorithm_framework test: needs: linting strategy: From a15ac8f4cffc6aac709c66912935b3e6fa685e98 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 23:47:57 +0200 Subject: [PATCH 19/31] Add flake8 ignore --- .flake8 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..5a02cc1b --- /dev/null +++ b/.flake8 @@ -0,0 +1,4 @@ +[flake8] +exclude = + investing_algorithm_framework/domain/utils/backtesting.py + examples \ No newline at end of file From 035992736fe25545b889d7f662eb0ff4f7319f09 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 23:48:10 +0200 Subject: [PATCH 20/31] Fix flake8 warnings --- .../app/algorithm.py | 3 +- investing_algorithm_framework/app/app.py | 3 +- .../domain/graphs.py | 115 +++++++++--------- .../domain/metrics/price_efficiency.py | 1 - .../models/backtesting/backtest_report.py | 16 +-- .../backtest_reports_evaluation.py | 11 +- .../models/market_data_sources/csv.py | 12 +- .../backtest_report_writer_service.py | 3 +- .../services/backtesting/backtest_service.py | 53 ++++---- .../services/backtesting/graphs.py | 1 - .../backtest_market_data_source_service.py | 2 +- 11 files changed, 113 insertions(+), 107 deletions(-) diff --git a/investing_algorithm_framework/app/algorithm.py b/investing_algorithm_framework/app/algorithm.py index 18105aed..c8871ce7 100644 --- a/investing_algorithm_framework/app/algorithm.py +++ b/investing_algorithm_framework/app/algorithm.py @@ -24,7 +24,8 @@ class is responsible for managing the strategies and executing :param (optional) name: The name of the algorithm :param (optional) description: The description of the algorithm - :param (optional) context: The context of the algorithm, for backtest references + :param (optional) context: The context of the algorithm, + for backtest references :param (optional) strategy: A single strategy to add to the algorithm :param (optional) data_sources: The list of data sources to add to the algorithm diff --git a/investing_algorithm_framework/app/app.py b/investing_algorithm_framework/app/app.py index 4f562b78..7a4e9981 100644 --- a/investing_algorithm_framework/app/app.py +++ b/investing_algorithm_framework/app/app.py @@ -801,7 +801,8 @@ def run_backtests( print( f"{COLOR_YELLOW}Running backtests for date " - f"range:{COLOR_RESET} {COLOR_GREEN}{date_range.name} {date_range.start_date} - " + f"range:{COLOR_RESET} {COLOR_GREEN}{date_range.name} " + f"{date_range.start_date} - " f"{date_range.end_date} for a " f"total of {len(algorithms)} algorithms.{COLOR_RESET}" ) diff --git a/investing_algorithm_framework/domain/graphs.py b/investing_algorithm_framework/domain/graphs.py index dbfe8f76..78ad2acd 100644 --- a/investing_algorithm_framework/domain/graphs.py +++ b/investing_algorithm_framework/domain/graphs.py @@ -13,7 +13,6 @@ def create_rsi_graph(data: pd.DataFrame): if not isinstance(data.index, pd.DatetimeIndex): raise ValueError("The index of the data should be of type datetime") - # Check if the 'RSI' column exists if 'RSI' not in data.columns: raise ValueError("The data should have a 'RSI' column") @@ -64,6 +63,7 @@ def create_prices_graph( name=graph_name ) + def create_adx_graph(data: pd.DataFrame): """ Create a graph for the ADX metric. @@ -87,6 +87,7 @@ def create_adx_graph(data: pd.DataFrame): name="ADX" ) + def create_di_plus_graph(data: pd.DataFrame): """ Create a graph for the DI+ metric. @@ -110,6 +111,7 @@ def create_di_plus_graph(data: pd.DataFrame): name="+DI" ) + def create_di_minus_graph(data: pd.DataFrame): """ Create a graph for the DI- metric. @@ -133,6 +135,7 @@ def create_di_minus_graph(data: pd.DataFrame): name="-DI" ) + def create_di_plus_di_minus_crossover_graph(data: pd.DataFrame): """ Create a graph for the DI- and DI+ crossover. @@ -147,7 +150,8 @@ def create_di_plus_di_minus_crossover_graph(data: pd.DataFrame): raise ValueError("The data should have a '-DI' and '+DI' column") # Get all crossover indexes - crossover_index = data[(data['+DI'] < data['-DI']) & (data['+DI'].shift(1) > data['-DI'].shift(1))].index + crossover_index = data[(data['+DI'] < data['-DI']) & + (data['+DI'].shift(1) > data['-DI'].shift(1))].index # Use .loc to get the corresponding 'Close' values crossover_close_values = data.loc[crossover_index, '+DI'] @@ -170,7 +174,6 @@ def create_ema_graph(data: pd.DataFrame, key, color="blue"): if key not in data.columns: raise ValueError(f"The data should have a {key} column") - return go.Scatter( x=data.index, y=data[key], @@ -179,6 +182,7 @@ def create_ema_graph(data: pd.DataFrame, key, color="blue"): name=key ) + def create_crossover_graph(data: pd.DataFrame, key_one, key_two, color="blue"): # Check if the index is of type datetime if not isinstance(data.index, pd.DatetimeIndex): @@ -186,10 +190,14 @@ def create_crossover_graph(data: pd.DataFrame, key_one, key_two, color="blue"): # Check if the key columns exist if key_one not in data.columns or key_two not in data.columns: - raise ValueError(f"The data should have a {key_one} and {key_two} column") + raise ValueError(f"The data should have a {key_one} " + f"and {key_two} column") # Get all crossover indexes - crossover_index = data[(data[key_one] <= data[key_two]) & (data[key_one].shift(1) >= data[key_two].shift(1))].index + crossover_index = data[ + (data[key_one] <= data[key_two]) & + (data[key_one].shift(1) >= data[key_two].shift(1)) + ].index # Use .loc to get the corresponding 'Close' values crossover_close_values = data.loc[crossover_index, key_one] @@ -202,7 +210,8 @@ def create_crossover_graph(data: pd.DataFrame, key_one, key_two, color="blue"): name=f'{key_one} {key_two} Crossover' ) -def create_peaks_chart(data: pd.DataFrame, key="Close", order = 5): + +def create_peaks_chart(data: pd.DataFrame, key="Close", order=5): # Check if the index is of type datetime if not isinstance(data.index, pd.DatetimeIndex): @@ -220,17 +229,8 @@ def create_peaks_chart(data: pd.DataFrame, key="Close", order = 5): ll_close_index = data[data[f'{key}_lows'] == 1].index hl_close_index = data[data[f'{key}_lows'] == -1].index - # Subtract for each index 10 hours - # hh_close_index = hh_close_index - pd.Timedelta(hours=2 * order) - # lh_close_index = lh_close_index - pd.Timedelta(hours=2 * order) - # ll_close_index = ll_close_index - pd.Timedelta(hours=2 * order) - # hl_close_index = hl_close_index - pd.Timedelta(hours=2 * order) - # hh_close_index = hh_close_index - # lh_close_index = lh_close_index - # ll_close_index = ll_close_index - # hl_close_index = hl_close_index - - # Use .loc to get the corresponding 'Close' values if the index is in the DataFrame + # Use .loc to get the corresponding 'Close' values if + # the index is in the DataFrame hh_close_values = data.loc[hh_close_index, key] lh_close_values = data.loc[lh_close_index, key] ll_close_values = data.loc[ll_close_index, key] @@ -276,13 +276,18 @@ def create_peaks_chart(data: pd.DataFrame, key="Close", order = 5): return higher_high_graph, lower_high_graph, lower_lows_graph, higher_lows -def create_bullish_divergence_chart(data: pd.DataFrame, key_one, key_two, color = 'red'): +def create_bullish_divergence_chart( + data: pd.DataFrame, key_one, key_two, color='red' +): """ - A bullish divergence occurs when the "_lows" makes a new low but the "_lows" makes a higher low. + A bullish divergence occurs when the "_lows" makes + a new low but the "_lows" makes a higher low. - For example, if the RSI makes a new low but the close price makes a higher low, then we have a bullish divergence. + For example, if the RSI makes a new low but the close price + makes a higher low, then we have a bullish divergence. """ - divergence_index = data[(data[f'{key_one}_lows'] == -1) & (data[f'{key_two}_lows'] == 1)].index + divergence_index = data[(data[f'{key_one}_lows'] == -1) + & (data[f'{key_two}_lows'] == 1)].index divergence_close_values = data.loc[divergence_index, 'Close'] return go.Scatter( @@ -294,15 +299,20 @@ def create_bullish_divergence_chart(data: pd.DataFrame, key_one, key_two, color ) -def create_bearish_divergence_chart(data: pd.DataFrame, key_one, key_two, color = 'red'): +def create_bearish_divergence_chart( + data: pd.DataFrame, key_one, key_two, color='red' +): """ - A bearish divergence occurs when the "_highs" makes a new high but the "_highs" makes a lower high. + A bearish divergence occurs when the "_highs" makes a + new high but the "_highs" makes a lower high. - For example, if the RSI makes a new high but the close price makes a lower high, then we have a bearish divergence. + For example, if the RSI makes a new high but the close price makes + a lower high, then we have a bearish divergence. """ # Add divergence charts - divergence_index = data[(data[f'{key_one}_highs'] == -1) & (data[f'{key_two}_highs'] == 1)].index + divergence_index = data[(data[f'{key_one}_highs'] == -1) + & (data[f'{key_two}_highs'] == 1)].index divergence_close_values = data.loc[divergence_index, 'Close'] return go.Scatter( @@ -315,12 +325,14 @@ def create_bearish_divergence_chart(data: pd.DataFrame, key_one, key_two, color def create_entry_graph(data: pd.DataFrame): - - - # Iterate over each row in the DataFrame and check if there is a bullish divergence between the RSI and the close price - # and if there is a crossover between the DI+ and DI- for the last 12 hours (6 candles) + # Iterate over each row in the DataFrame and check if there is a + # bullish divergence between the RSI and the close price + # and if there is a crossover between the DI+ and DI- for + # the last 12 hours (6 candles) # Get all crossover indexes - crossover_index = data[(data['+DI'] <= data['-DI']) & (data['+DI'].shift(1) >= data['-DI'].shift(1))].index + crossover_index = data[(data['+DI'] <= data['-DI']) & + (data['+DI'].shift(1) >= data['-DI'].shift(1))]\ + .index data['di_crossover'] = 0 data.loc[crossover_index, 'di_crossover'] = 1 @@ -330,11 +342,19 @@ def create_entry_graph(data: pd.DataFrame): if row.di_crossover == 1: match = False - # Check if there was a bullish divergence between the RSI and the close price in the last 2 days - rsi_window = data.loc[row.Index - pd.Timedelta(days=2):row.Index, 'RSI_lows'] - close_window = data.loc[row.Index - pd.Timedelta(days=2):row.Index, 'Close_lows'] - - # Go over each row and check if there is a bullish divergence between the RSI and the close price + # Check if there was a bullish divergence between + # the RSI and the close price in the last 2 days + rsi_window = data.loc[ + row.Index - pd.Timedelta(days=2):row.Index, + 'RSI_lows' + ] + close_window = data.loc[ + row.Index - pd.Timedelta(days=2):row.Index, + 'Close_lows' + ] + + # Go over each row and check if there is a bullish + # divergence between the RSI and the close price for rsi_row, close_row in zip(rsi_window, close_window): if rsi_row == -1 and close_row == 1: @@ -344,31 +364,14 @@ def create_entry_graph(data: pd.DataFrame): if not match: # Check if the RSI had decreased - rsi_window = data.loc[row.Index - pd.Timedelta(days=1):row.Index, 'RSI'] + rsi_window = data.loc[ + row.Index - pd.Timedelta(days=1):row.Index, 'RSI' + ] rsi_diff = rsi_window.diff().mean() if rsi_diff < -2: entry_indexes.append(row.Index) - # If ema 50 < - - # # Check if there is a bullish divergence between the RSI and the close price - # if row.Close_lows == 1 and row.RSI_lows == -1: - # - # # Check if there is a crossover in the last 12 hours - # crossovers = data.loc[row.Index - pd.Timedelta(hours=12):row.Index, 'di_crossover'] - # - # if crossovers.sum() > 0: - # entry_indexes.append(row.Index) - - # adx_window = data.loc[row.Index - pd.Timedelta(hours=4):row.Index, 'ADX'] - # rsi_window = data.loc[row.Index - pd.Timedelta(hours=4):row.Index, 'RSI'] - # adx_diff = adx_window.diff().mean() - # rsi_diff = rsi_window.diff().mean() - # - # if adx_diff > -2 and adx_diff < 0: - # entry_indexes.append(row.Index) - entry_close_values = data.loc[entry_indexes, 'Close'] return go.Scatter( x=entry_indexes, @@ -376,4 +379,4 @@ def create_entry_graph(data: pd.DataFrame): mode='markers', marker=dict(symbol='circle', size=10, color='green'), name='Entry Signal' - ) \ No newline at end of file + ) diff --git a/investing_algorithm_framework/domain/metrics/price_efficiency.py b/investing_algorithm_framework/domain/metrics/price_efficiency.py index e5af09bd..68fd36a0 100644 --- a/investing_algorithm_framework/domain/metrics/price_efficiency.py +++ b/investing_algorithm_framework/domain/metrics/price_efficiency.py @@ -55,4 +55,3 @@ def get_price_efficiency_ratio(data: DataFrame): # Calculate Efficiency Ratio return net_price_change / sum_absolute_changes - diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py index dcc200ec..58f1b47c 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_report.py @@ -1,14 +1,15 @@ -from logging import getLogger from datetime import datetime -from pandas import DataFrame, to_datetime, DatetimeIndex +from logging import getLogger + +from pandas import DataFrame -from investing_algorithm_framework.domain.models.base_model import BaseModel -from investing_algorithm_framework.domain.models.time_unit import TimeUnit -from investing_algorithm_framework.domain.models\ - .backtesting.backtest_date_range import BacktestDateRange from investing_algorithm_framework.domain.constants import DATETIME_FORMAT from investing_algorithm_framework.domain.metrics import \ get_price_efficiency_ratio +from investing_algorithm_framework.domain.models \ + .backtesting.backtest_date_range import BacktestDateRange +from investing_algorithm_framework.domain.models.base_model import BaseModel +from investing_algorithm_framework.domain.models.time_unit import TimeUnit logger = getLogger(__name__) @@ -97,7 +98,6 @@ def __init__( (self.backtest_date_range.end_date - self.backtest_date_range.start_date).days - @property def name(self): return self._name @@ -551,7 +551,7 @@ def traces(self, value): """ self._traces = value - def get_trace(self, symbol, strategy_id = None): + def get_trace(self, symbol, strategy_id=None): """ Get the trace for a given symbol. If a strategy_id is provided, it will return the trace for that strategy. diff --git a/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py b/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py index 5fa4afb1..79f6f271 100644 --- a/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +++ b/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py @@ -179,7 +179,8 @@ def rank( for algorithm in ordered_reports: profit_score += sum( - [report.total_net_gain for report in ordered_reports[algorithm]] + [report.total_net_gain for + report in ordered_reports[algorithm]] ) growth_score += sum( [report.growth for report in @@ -215,7 +216,8 @@ def get_reports( if name is not None: return [ - report for report in self.backtest_reports if report.name == name + report for report in self.backtest_reports + if report.name == name ] if backtest_date_range is not None: @@ -234,7 +236,8 @@ def get_report( reports = self.get_reports(name, backtest_date_range) if len(reports) == 0: - raise OperationalException("No matches for given name and date range") + raise OperationalException( + "No matches for given name and date range" + ) return reports[0] - diff --git a/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py b/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py index cd601560..0aaac06c 100644 --- a/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +++ b/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py @@ -1,25 +1,27 @@ import logging -from datetime import datetime, timedelta +from datetime import datetime import polars from dateutil.parser import parse from investing_algorithm_framework.domain import OHLCVMarketDataSource, \ BacktestMarketDataSource, OperationalException, TickerMarketDataSource, \ - DATETIME_FORMAT, TimeFrame + DATETIME_FORMAT logger = logging.getLogger(__name__) class CSVOHLCVMarketDataSource(OHLCVMarketDataSource): """ - Implementation of a OHLCV data source that reads OHLCV data from a csv file. - Market data source that reads OHLCV data from a csv file. + Implementation of a OHLCV data source that reads OHLCV data + from a csv file. Market data source that reads OHLCV data from a csv file. """ def empty(self, start_date, end_date=None): if end_date is None: - end_date = self.create_end_date(start_date, self.timeframe, self.window_size) + end_date = self.create_end_date( + start_date, self.timeframe, self.window_size + ) data = self.get_data(start_date=start_date, end_date=end_date) return len(data) == 0 diff --git a/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py b/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py index 8702dfb1..0bcdd980 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py @@ -1,6 +1,5 @@ -import csv -import os import json +import os from investing_algorithm_framework.domain import BacktestReport, \ DATETIME_FORMAT_BACKTESTING diff --git a/investing_algorithm_framework/services/backtesting/backtest_service.py b/investing_algorithm_framework/services/backtesting/backtest_service.py index bd5a919c..fa16ff81 100644 --- a/investing_algorithm_framework/services/backtesting/backtest_service.py +++ b/investing_algorithm_framework/services/backtesting/backtest_service.py @@ -282,8 +282,8 @@ def create_backtest_report( backtest_report.total_net_gain_percentage = \ self._performance_service \ .get_total_net_gain_percentage_of_backtest( - portfolio.id, backtest_report - ) + portfolio.id, backtest_report + ) positions = self._position_repository.get_all({ "portfolio": portfolio.id }) @@ -298,18 +298,18 @@ def create_backtest_report( ticker_symbol = \ f"{position.symbol}/{portfolio.trading_symbol}" - if not self._market_data_source_service \ - .has_ticker_market_data_source( - symbol=ticker_symbol, market=portfolio.market - ): + if not self._market_data_source_service\ + .has_ticker_market_data_source( + symbol=ticker_symbol, market=portfolio.market + ): raise OperationalException( f"Ticker market data source for " - f"symbol {ticker_symbol} " - f"and market {portfolio.market} not found, please " - f"make sure you register a ticker market " - f"data source for this symbol and market " - f"in backtest mode. Otherwise, the backtest report" - " cannot be generated." + f"symbol {ticker_symbol} and market " + f"{portfolio.market} not found, please make " + f"sure you register a ticker market data " + f"source for this symbol and market in " + f"backtest mode. Otherwise, the backtest " + f"report cannot be generated." ) tickers[ticker_symbol] = \ self._market_data_source_service.get_ticker( @@ -319,12 +319,12 @@ def create_backtest_report( backtest_report.growth_rate = self._performance_service \ .get_growth_rate_of_backtest( - portfolio.id, tickers, backtest_report - ) + portfolio.id, tickers, backtest_report + ) backtest_report.growth = self._performance_service \ .get_growth_of_backtest( - portfolio.id, tickers, backtest_report - ) + portfolio.id, tickers, backtest_report + ) backtest_report.total_value = self._performance_service \ .get_total_value(portfolio.id, tickers, backtest_report) backtest_report.average_trade_duration = \ @@ -379,10 +379,10 @@ def create_backtest_report( # Probably not needed ticker = self._market_data_source_service \ .get_ticker( - symbol=f"{position.symbol}" - f"/{portfolio.trading_symbol}", - market=portfolio.market - ) + symbol=f"{position.symbol}" + f"/{portfolio.trading_symbol}", + market=portfolio.market + ) backtest_position.price = ticker["bid"] backtest_positions.append(backtest_position) backtest_report.positions = backtest_positions @@ -436,10 +436,9 @@ def _check_if_required_market_data_sources_are_registered(self): symbol=symbol ): raise OperationalException( - f"Ticker market data source for " - f"symbol {symbol} not found, please " - f"make sure you register a ticker market " - f"data source for this symbol " - f"in backtest mode. Otherwise, the backtest report" - " cannot be generated." - ) + f"Ticker market data source for symbol {symbol} not " + f"found, please make sure you register a ticker " + f"market data source for this symbol in backtest " + f"mode. Otherwise, the backtest report " + f"cannot be generated." + ) diff --git a/investing_algorithm_framework/services/backtesting/graphs.py b/investing_algorithm_framework/services/backtesting/graphs.py index 6cfe8828..30d4a11a 100644 --- a/investing_algorithm_framework/services/backtesting/graphs.py +++ b/investing_algorithm_framework/services/backtesting/graphs.py @@ -59,4 +59,3 @@ def create_trade_exit_markers_chart(df, trades: List[Trade]): mode='markers', name='Sell' ) - diff --git a/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py b/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py index 6289e112..73375cec 100644 --- a/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +++ b/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py @@ -147,4 +147,4 @@ def add(self, market_data_source): market_data_source.get_identifier(): return - self._market_data_sources.append(market_data_source) \ No newline at end of file + self._market_data_sources.append(market_data_source) From 0142590c75e5a35bd8ca5ac961b5be4e95cd30e7 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 23:48:22 +0200 Subject: [PATCH 21/31] Fix flake8 warnings --- .../app/algorithm/test_check_order_status.py | 4 +- tests/app/algorithm/test_close_trade.py | 1 - .../algorithm/test_create_limit_buy_order.py | 12 +- .../algorithm/test_create_limit_sell_order.py | 12 +- .../test_create_market_sell_order.py | 4 +- tests/app/algorithm/test_get_allocated.py | 1 - tests/app/algorithm/test_get_closed_trades.py | 4 +- tests/app/algorithm/test_get_data.py | 6 +- tests/app/algorithm/test_get_open_trades.py | 3 +- tests/app/algorithm/test_get_order.py | 4 +- .../algorithm/test_has_open_sell_orders.py | 3 +- tests/app/backtesting/test_backtest_report.py | 35 +- tests/app/backtesting/test_run_backtest.py | 35 +- tests/app/backtesting/test_run_backtests.py | 15 +- tests/app/web/controllers/__init__.py | 2 - .../domain/models/test_backtest_date_range.py | 33 + tests/domain/models/test_backtest_report.py | 11 +- .../test_backtest_reports_evaluation.py | 9 +- tests/domain/models/test_order.py | 1 - tests/domain/models/test_trade.py | 25 +- tests/domain/test_csv.py | 8 +- tests/domain/test_decimal_parsing.py | 4 +- ..._ccxt_ohlcv_backtest_market_data_source.py | 104 +- .../test_ccxt_ohlcv_market_data_source.py | 32 +- .../test_csv_ohlcv_market_data_source.py | 44 +- tests/infrastructure/models/test_portfolio.py | 14 +- .../test_default_order_validator.py | 5 +- .../repositories/test_order_repository.py | 3 +- .../repositories/test_position_repository.py | 3 +- .../services/test_ccxt_market_service.py | 3 +- ...O_2h_2023-07-21:14:00_2024-06-07:10:00.csv | 3857 +++++++++++++++++ tests/resources/settings.py | 2 +- tests/resources/stubs/market_service_stub.py | 6 +- tests/resources/utils.py | 4 +- tests/services/test_order_backtest_service.py | 14 +- tests/services/test_order_service.py | 2 +- tests/services/test_portfolio_sync_service.py | 7 +- tests/test_create_app.py | 4 +- 38 files changed, 4069 insertions(+), 267 deletions(-) create mode 100644 tests/domain/models/test_backtest_date_range.py create mode 100644 tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BITVAVO_2h_2023-07-21:14:00_2024-06-07:10:00.csv diff --git a/tests/app/algorithm/test_check_order_status.py b/tests/app/algorithm/test_check_order_status.py index b063bda8..c18402ea 100644 --- a/tests/app/algorithm/test_check_order_status.py +++ b/tests/app/algorithm/test_check_order_status.py @@ -1,7 +1,7 @@ from decimal import Decimal -from investing_algorithm_framework import PortfolioConfiguration, OrderStatus, \ - MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + OrderStatus, MarketCredential from tests.resources import TestBase diff --git a/tests/app/algorithm/test_close_trade.py b/tests/app/algorithm/test_close_trade.py index 84c0106e..ec2b25b2 100644 --- a/tests/app/algorithm/test_close_trade.py +++ b/tests/app/algorithm/test_close_trade.py @@ -42,7 +42,6 @@ def setUp(self) -> None: ) )) - def test_close_trade(self): trading_symbol_position = self.app.algorithm.get_position("EUR") self.assertEqual(1000, trading_symbol_position.get_amount()) diff --git a/tests/app/algorithm/test_create_limit_buy_order.py b/tests/app/algorithm/test_create_limit_buy_order.py index cadde630..dcf73464 100644 --- a/tests/app/algorithm/test_create_limit_buy_order.py +++ b/tests/app/algorithm/test_create_limit_buy_order.py @@ -1,5 +1,5 @@ -from investing_algorithm_framework import PortfolioConfiguration, OrderStatus, \ - MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + OrderStatus, MarketCredential from tests.resources import TestBase @@ -38,7 +38,10 @@ def test_create_limit_buy_order(self): ) order_repository = self.app.container.order_repository() self.assertEqual( - 1, order_repository.count({"order_type": "LIMIT", "order_side": "BUY"}) + 1, + order_repository.count( + {"order_type": "LIMIT", "order_side": "BUY"} + ) ) order = order_repository.find({"target_symbol": "BTC"}) self.assertEqual(OrderStatus.OPEN.value, order.status) @@ -53,7 +56,8 @@ def test_create_limit_buy_order_with_percentage_of_portfolio(self): ) order_repository = self.app.container.order_repository() self.assertEqual( - 1, order_repository.count({"order_type": "LIMIT", "order_side": "BUY"}) + 1, order_repository + .count({"order_type": "LIMIT", "order_side": "BUY"}) ) order = order_repository.find({"target_symbol": "BTC"}) self.assertEqual(OrderStatus.OPEN.value, order.status) diff --git a/tests/app/algorithm/test_create_limit_sell_order.py b/tests/app/algorithm/test_create_limit_sell_order.py index 75ddf8ba..f23d17b6 100644 --- a/tests/app/algorithm/test_create_limit_sell_order.py +++ b/tests/app/algorithm/test_create_limit_sell_order.py @@ -1,5 +1,5 @@ -from investing_algorithm_framework import PortfolioConfiguration, OrderStatus, \ - MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + OrderStatus, MarketCredential from tests.resources import TestBase @@ -32,7 +32,8 @@ def test_create_limit_sell_order(self): ) order_repository = self.app.container.order_repository() self.assertEqual( - 1, order_repository.count({"order_type": "LIMIT", "order_side": "BUY"}) + 1, order_repository + .count({"order_type": "LIMIT", "order_side": "BUY"}) ) order = order_repository.find({"target_symbol": "BTC"}) self.assertEqual(OrderStatus.OPEN.value, order.status) @@ -43,7 +44,7 @@ def test_create_limit_sell_order(self): self.assertEqual(800, portfolio.get_unallocated()) order_service = self.app.container.order_service() order_service.check_pending_orders() - position = self.app.algorithm.get_position("BTC") + self.app.algorithm.get_position("BTC") order = self.app.algorithm.create_limit_order( target_symbol="BTC", price=10, @@ -63,7 +64,8 @@ def test_create_limit_sell_order_with_percentage_position(self): ) order_repository = self.app.container.order_repository() self.assertEqual( - 1, order_repository.count({"order_type": "LIMIT", "order_side": "BUY"}) + 1, order_repository + .count({"order_type": "LIMIT", "order_side": "BUY"}) ) order = order_repository.find({"target_symbol": "BTC"}) self.assertEqual(OrderStatus.OPEN.value, order.status) diff --git a/tests/app/algorithm/test_create_market_sell_order.py b/tests/app/algorithm/test_create_market_sell_order.py index 8eb4812b..05289e8a 100644 --- a/tests/app/algorithm/test_create_market_sell_order.py +++ b/tests/app/algorithm/test_create_market_sell_order.py @@ -1,5 +1,5 @@ -from investing_algorithm_framework import PortfolioConfiguration, OrderType, OrderSide, \ - OrderStatus, MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + OrderType, OrderSide, OrderStatus, MarketCredential from tests.resources import TestBase diff --git a/tests/app/algorithm/test_get_allocated.py b/tests/app/algorithm/test_get_allocated.py index 8e1754c5..f230c5a5 100644 --- a/tests/app/algorithm/test_get_allocated.py +++ b/tests/app/algorithm/test_get_allocated.py @@ -61,4 +61,3 @@ def test_get_allocated(self): self.assertNotEqual(0, self.app.algorithm.get_allocated()) self.assertNotEqual(0, self.app.algorithm.get_allocated("BITVAVO")) self.assertNotEqual(0, self.app.algorithm.get_allocated("bitvavo")) - diff --git a/tests/app/algorithm/test_get_closed_trades.py b/tests/app/algorithm/test_get_closed_trades.py index c3b84456..f28f8769 100644 --- a/tests/app/algorithm/test_get_closed_trades.py +++ b/tests/app/algorithm/test_get_closed_trades.py @@ -23,8 +23,8 @@ class Test(TestBase): secret_key="secret_key" ) ] - - def setUp(self) -> None: + + def setUp(self) -> None: super(Test, self).setUp() self.app.add_market_data_source(CSVTickerMarketDataSource( identifier="BTC/EUR-ticker", diff --git a/tests/app/algorithm/test_get_data.py b/tests/app/algorithm/test_get_data.py index 8023f592..eaa34407 100644 --- a/tests/app/algorithm/test_get_data.py +++ b/tests/app/algorithm/test_get_data.py @@ -1,8 +1,8 @@ # import os # from datetime import datetime, timedelta -# from investing_algorithm_framework import create_app, TradingStrategy, TimeUnit, \ -# RESOURCE_DIRECTORY, PortfolioConfiguration, TradingDataType, \ -# TradingTimeFrame +# from investing_algorithm_framework import create_app, +# TradingStrategy, TimeUnit, RESOURCE_DIRECTORY, PortfolioConfiguration, +# TradingDataType, TradingTimeFrame # from tests.resources import TestBase, MarketServiceStub # # diff --git a/tests/app/algorithm/test_get_open_trades.py b/tests/app/algorithm/test_get_open_trades.py index 6f74e89a..d8a386f6 100644 --- a/tests/app/algorithm/test_get_open_trades.py +++ b/tests/app/algorithm/test_get_open_trades.py @@ -95,7 +95,8 @@ def test_get_open_trades_with_close_trades(self): self.assertIsNone(trade.closed_at) self.assertEqual( 0, - len(self.app.algorithm.get_orders(order_side="SELL", status="OPEN")) + len(self.app.algorithm + .get_orders(order_side="SELL", status="OPEN")) ) self.app.algorithm.create_limit_order( target_symbol="BTC", diff --git a/tests/app/algorithm/test_get_order.py b/tests/app/algorithm/test_get_order.py index a5195f7c..55db9043 100644 --- a/tests/app/algorithm/test_get_order.py +++ b/tests/app/algorithm/test_get_order.py @@ -1,7 +1,7 @@ from decimal import Decimal -from investing_algorithm_framework import PortfolioConfiguration, OrderStatus, \ - MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + OrderStatus, MarketCredential from tests.resources import TestBase diff --git a/tests/app/algorithm/test_has_open_sell_orders.py b/tests/app/algorithm/test_has_open_sell_orders.py index 32b008ab..196e1059 100644 --- a/tests/app/algorithm/test_has_open_sell_orders.py +++ b/tests/app/algorithm/test_has_open_sell_orders.py @@ -1,4 +1,5 @@ -from investing_algorithm_framework import PortfolioConfiguration, MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + MarketCredential from tests.resources import TestBase diff --git a/tests/app/backtesting/test_backtest_report.py b/tests/app/backtesting/test_backtest_report.py index c5422183..720cccbe 100644 --- a/tests/app/backtesting/test_backtest_report.py +++ b/tests/app/backtesting/test_backtest_report.py @@ -3,8 +3,8 @@ from unittest import TestCase from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \ - TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm -from investing_algorithm_framework.domain import DATETIME_FORMAT_BACKTESTING + TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm, \ + BacktestDateRange from investing_algorithm_framework.services import BacktestReportWriterService @@ -55,10 +55,13 @@ def test_report_csv_creation(self): initial_balance=1000 ) ) + backtest_date_range = BacktestDateRange( + start_date=datetime.utcnow() - timedelta(days=1), + end_date=datetime.utcnow() + ) report = app.run_backtest( algorithm, - start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + backtest_date_range=backtest_date_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") @@ -87,10 +90,13 @@ def test_report_csv_creation_without_strategy_identifier(self): initial_balance=1000 ) ) + backtest_date_range = BacktestDateRange( + start_date=datetime.utcnow() - timedelta(days=1), + end_date=datetime.utcnow() + ) report = app.run_backtest( algorithm=algorithm, - start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + backtest_date_range=backtest_date_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") @@ -126,10 +132,12 @@ def run_strategy(algorithm, market_data): ) self.assertEqual(2, len(algorithm.strategies)) - report = app.run_backtest( - algorithm=algorithm, + backtest_date_range = BacktestDateRange( start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + end_date=datetime.utcnow() + ) + report = app.run_backtest( + algorithm=algorithm, backtest_date_range=backtest_date_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") @@ -161,12 +169,13 @@ def run_strategy(algorithm, market_data): initial_balance=1000 ) ) - self.assertEqual(2, len(algorithm.strategies)) - report = app.run_backtest( - algorithm=algorithm, + backtest_range = BacktestDateRange( start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + end_date=datetime.utcnow() + ) + report = app.run_backtest( + algorithm=algorithm, backtest_date_range=backtest_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") diff --git a/tests/app/backtesting/test_run_backtest.py b/tests/app/backtesting/test_run_backtest.py index 230fb826..33168bbf 100644 --- a/tests/app/backtesting/test_run_backtest.py +++ b/tests/app/backtesting/test_run_backtest.py @@ -3,7 +3,8 @@ from unittest import TestCase from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \ - TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm + TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm, \ + BacktestDateRange from investing_algorithm_framework.services import BacktestReportWriterService @@ -54,11 +55,11 @@ def test_report_csv_creation(self): initial_balance=1000 ) ) - report = app.run_backtest( - algorithm, + backtest_date_range = BacktestDateRange( start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + end_date=datetime.utcnow() ) + report = app.run_backtest(algorithm, backtest_date_range) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") ) @@ -86,10 +87,12 @@ def test_report_csv_creation_without_strategy_identifier(self): initial_balance=1000 ) ) - report = app.run_backtest( - algorithm=algorithm, + backtest_date_range = BacktestDateRange( start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + end_date=datetime.utcnow() + ) + report = app.run_backtest( + algorithm=algorithm, backtest_date_range=backtest_date_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") @@ -123,16 +126,19 @@ def run_strategy(algorithm, market_data): ) self.assertEqual(2, len(algorithm.strategies)) - report = app.run_backtest( - algorithm=algorithm, + backtest_date_range = BacktestDateRange( start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + end_date=datetime.utcnow() + ) + report = app.run_backtest( + algorithm=algorithm, backtest_date_range=backtest_date_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists self.assertTrue(os.path.isfile(file_path)) + def test_report_csv_creation_with_multiple_strategies_with_id(self): """ Test if the backtest report is created as a CSV file @@ -157,13 +163,16 @@ def run_strategy(algorithm, market_data): ) self.assertEqual(2, len(algorithm.strategies)) + backtest_date_range = BacktestDateRange( + start_date=datetime.utcnow() - timedelta(days=1), + end_date=datetime.utcnow() + ) report = app.run_backtest( algorithm=algorithm, - start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + backtest_date_range=backtest_date_range ) file_path = BacktestReportWriterService.create_report_name( report, os.path.join(self.resource_dir, "backtest_reports") ) # Check if the backtest report exists - self.assertTrue(os.path.isfile(file_path)) \ No newline at end of file + self.assertTrue(os.path.isfile(file_path)) diff --git a/tests/app/backtesting/test_run_backtests.py b/tests/app/backtesting/test_run_backtests.py index d42b3a6c..2fd1a159 100644 --- a/tests/app/backtesting/test_run_backtests.py +++ b/tests/app/backtesting/test_run_backtests.py @@ -3,9 +3,9 @@ from unittest import TestCase from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \ - TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm + TradingStrategy, PortfolioConfiguration, TimeUnit, Algorithm, \ + BacktestDateRange from investing_algorithm_framework.services import BacktestReportWriterService -from investing_algorithm_framework.domain import DATETIME_FORMAT_BACKTESTING class TestStrategy(TradingStrategy): @@ -65,16 +65,17 @@ def test_run_backtests(self): ) start_date = datetime.utcnow() - timedelta(days=1) end_date = datetime.utcnow() + backtest_date_range = BacktestDateRange( + start_date=start_date, + end_date=end_date + ) app._initialize_app_for_backtest( - backtest_start_date=start_date, - backtest_end_date=end_date, + backtest_date_range=backtest_date_range, pending_order_check_interval='2h', - market_data_sources=[] ) reports = app.run_backtests( algorithms=[algorithm_one, algorithm_two, algorithm_three], - start_date=datetime.utcnow() - timedelta(days=1), - end_date=datetime.utcnow(), + date_ranges=[backtest_date_range] ) # Check if the backtest reports exist diff --git a/tests/app/web/controllers/__init__.py b/tests/app/web/controllers/__init__.py index 139597f9..e69de29b 100644 --- a/tests/app/web/controllers/__init__.py +++ b/tests/app/web/controllers/__init__.py @@ -1,2 +0,0 @@ - - diff --git a/tests/domain/models/test_backtest_date_range.py b/tests/domain/models/test_backtest_date_range.py new file mode 100644 index 00000000..7ba55678 --- /dev/null +++ b/tests/domain/models/test_backtest_date_range.py @@ -0,0 +1,33 @@ +from unittest import TestCase +from datetime import datetime, timedelta + +from investing_algorithm_framework.domain import BacktestDateRange + + +class Test(TestCase): + + def test_with_datetime(self): + end_date = datetime.utcnow() + start_date = end_date - timedelta(days=10) + date_range = BacktestDateRange( + name="test", + start_date=start_date, + end_date=end_date + ) + self.assertEqual(start_date, date_range.start_date) + self.assertEqual(end_date, date_range.end_date) + self.assertEqual("test", date_range.name) + + def test_with_string(self): + date_range = BacktestDateRange( + name="string based", + start_date="2022-01-01", + end_date="2022-03-01" + ) + self.assertEqual( + datetime(year=2022, day=1, month=1), date_range.start_date + ) + self.assertEqual( + datetime(year=2022, day=1, month=3), date_range.end_date + ) + self.assertEqual("string based", date_range.name) diff --git a/tests/domain/models/test_backtest_report.py b/tests/domain/models/test_backtest_report.py index f3353574..53504906 100644 --- a/tests/domain/models/test_backtest_report.py +++ b/tests/domain/models/test_backtest_report.py @@ -1,6 +1,6 @@ import os from unittest import TestCase - +from datetime import datetime from investing_algorithm_framework import load_backtest_report @@ -28,17 +28,20 @@ def test_backtest_reports_evaluation(self): self.resource_dir, "backtest_reports_for_testing", "report_9-50-100_backtest_start_date_2021-12-21:00:00_" - "backtest_end_date_2022-06-20:00:00_created_at_2024-04-25:13:52.json" + "backtest_end_date_2022-06-20:00:00" + "_created_at_2024-04-25:13:52.json" ) report = load_backtest_report(path) self.assertEqual( report.name, "9-50-100" ) self.assertEqual( - "2021-12-21 00:00:00", report.backtest_start_date + datetime(year=2021, month=12, day=21), + report.backtest_start_date ) self.assertEqual( - "2022-06-20 00:00:00", report.backtest_end_date + datetime(year=2022, month=6, day=20), + report.backtest_end_date ) self.assertEqual(10.713880999999981, report.total_net_gain) self.assertEqual(2.6784702499999753, report.growth_rate) diff --git a/tests/domain/models/test_backtest_reports_evaluation.py b/tests/domain/models/test_backtest_reports_evaluation.py index 5fade969..5b674d0e 100644 --- a/tests/domain/models/test_backtest_reports_evaluation.py +++ b/tests/domain/models/test_backtest_reports_evaluation.py @@ -29,11 +29,4 @@ def test_backtest_reports_evaluation(self): reports = load_backtest_reports(path) evaluation = BacktestReportsEvaluation(reports) self.assertEqual(len(evaluation.backtest_reports), 6) - first_backtest_report = evaluation.backtest_reports[0] - time_frame = ( - first_backtest_report.backtest_start_date, - first_backtest_report.backtest_end_date - ) - self.assertEqual( - "10-50-100", evaluation.profit_order[time_frame][0].name - ) + self.assertEqual("10-50-100", evaluation.profit_order[0].name) diff --git a/tests/domain/models/test_order.py b/tests/domain/models/test_order.py index 137f0bb3..3ee43511 100644 --- a/tests/domain/models/test_order.py +++ b/tests/domain/models/test_order.py @@ -41,4 +41,3 @@ def test_from_ccxt_order(self): self.assertEqual( order.get_created_at(), datetime(2017, 8, 17, 12, 42, 48) ) - diff --git a/tests/domain/models/test_trade.py b/tests/domain/models/test_trade.py index ae2ebfdb..d3ce96da 100644 --- a/tests/domain/models/test_trade.py +++ b/tests/domain/models/test_trade.py @@ -30,6 +30,13 @@ def test_trade(self): self.assertEqual(trade.opened_at, trade_opened_at) def test_stop_loss_manual_with_dataframe(self): + """ + Test for checking if stoplos function works on trade. The test uses + an ohlcv dataset of BTC/EUR with a 15m timeframe. The start date + of the dataset is 2023-08-07 08:00:00+00:00 and the end + date of the dataset is 2023-12-02 00:00:00+00:00. The trade is + opened at 2023-08-17 12:00:00 with a price of 32589. + """ current_datetime = datetime(2023, 8, 26, 00, 00, 0, tzinfo=tzutc()) resource_dir = os.path.abspath( os.path.join( @@ -51,8 +58,6 @@ def test_stop_loss_manual_with_dataframe(self): market="BITVAVO", symbol="BTC/EUR", timeframe="15m", - start_date=current_datetime - timedelta(days=17), - end_date=current_datetime, csv_file_path=f"{resource_dir}/" "market_data_sources_for_testing/" "OHLCV_BTC-EUR_BINANCE_2h_2023-08-07:07" @@ -67,8 +72,8 @@ def test_stop_loss_manual_with_dataframe(self): "TICKER_BTC-EUR_BINANCE_2023-08" "-23:22:00_2023-12-02:00:00.csv" ) - trade_opened_at = datetime(2023, 8, 17, 12, 0, 0, tzinfo=tzutc()) - open_price = 32589 + trade_opened_at = datetime(2023, 8, 24, 22, 0, 0, tzinfo=tzutc()) + open_price = 24167.14 trade = Trade( buy_order_id=1, target_symbol="BTC", @@ -79,19 +84,25 @@ def test_stop_loss_manual_with_dataframe(self): closed_price=None, closed_at=None, ) + end_date = trade_opened_at + timedelta(days=2) ohlcv_data = csv_ohlcv_market_data_source \ - .get_data(market_credential_service=None) + .get_data( + market_credential_service=None, + start_date=trade_opened_at, + end_date=end_date + ) current_price = csv_ticker_market_data_source \ .get_data( - index_datetime=current_datetime, market_credential_service=None + start_date=end_date, market_credential_service=None ) - self.assertTrue( + self.assertFalse( trade.is_manual_stop_loss_trigger( current_price=current_price["bid"], ohlcv_df=ohlcv_data, stop_loss_percentage=2 ) ) + current_datetime = datetime(2023, 11, 21, tzinfo=tzutc()) ohlcv_data = csv_ohlcv_market_data_source \ .get_data( diff --git a/tests/domain/test_csv.py b/tests/domain/test_csv.py index ca3a0f32..564b26fd 100644 --- a/tests/domain/test_csv.py +++ b/tests/domain/test_csv.py @@ -4,9 +4,10 @@ # from unittest import TestCase # # from tests.resources.utils import random_string -# from investing_algorithm_framework.utils.csv import remove_row, csv_to_list, \ +# from investing_algorithm_framework.utils.csv import remove_row, csv_to_list,\ # append_dict_as_row_to_csv, get_total_amount_of_rows -# from investing_algorithm_framework.core.exceptions import OperationalException +# from investing_algorithm_framework.core.exceptions +# import OperationalException # # # class Test(TestCase): @@ -18,7 +19,8 @@ # # records = 200 # fieldnames = ['id', 'name', 'age', 'city'] -# names = ['Deepak', 'Sangeeta', 'Geetika', 'Anubhav', 'Sahil', 'Akshay'] +# names = ['Deepak', 'Sangeeta', +# 'Geetika', 'Anubhav', 'Sahil', 'Akshay'] # cities = ['Delhi', 'Kolkata', 'Chennai', 'Mumbai'] # # # Open file in append mode diff --git a/tests/domain/test_decimal_parsing.py b/tests/domain/test_decimal_parsing.py index a851962e..99012df0 100644 --- a/tests/domain/test_decimal_parsing.py +++ b/tests/domain/test_decimal_parsing.py @@ -14,5 +14,5 @@ def test_decimal_to_string(self): self.assertEqual(string_value, '97.17312522036036245646') def test_string_to_decimal(self): - value = parse_string_to_decimal('97.17312522036036245646') - value = parse_string_to_decimal('2004.5303357979318') + parse_string_to_decimal('97.17312522036036245646') + parse_string_to_decimal('2004.5303357979318') diff --git a/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py b/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py index 76540aec..a79980a6 100644 --- a/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py +++ b/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py @@ -44,7 +44,7 @@ def test_file_path(self): and the end date is the backtest end date. """ correct_file_name = \ - "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:22:00_2023-12-25:00:00.csv" + "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv" data_source = CCXTOHLCVBacktestMarketDataSource( identifier="OHLCV_BTC_EUR_BINANCE_15m", market="BINANCE", @@ -66,7 +66,7 @@ def test_file_path(self): def test_window_size(self): correct_file_name = \ - "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:22:00_2023-12-25:00:00.csv" + "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv" data_source = CCXTOHLCVBacktestMarketDataSource( identifier="OHLCV_BTC_EUR_BINANCE_15m", market="BINANCE", @@ -87,7 +87,7 @@ def test_window_size(self): def test_right_columns(self): correct_file_name = \ - "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:22:00_2023-12-25:00:00.csv" + "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv" csv_file_path = f"{self.resource_dir}/market_data_sources" \ f"/{correct_file_name}" data_source = CCXTOHLCVBacktestMarketDataSource( @@ -97,9 +97,7 @@ def test_right_columns(self): timeframe="15m", window_size=200 ) - data_source.config = { - "DATETIME_FORMAT": DATETIME_FORMAT - } + data_source.config = {"DATETIME_FORMAT": DATETIME_FORMAT} data_source.prepare_data( config={ RESOURCE_DIRECTORY: self.resource_dir, @@ -111,95 +109,11 @@ def test_right_columns(self): self.assertEqual(200, data_source.window_size) self.assertEqual(csv_file_path, data_source._create_file_path()) df = data_source\ - .get_data(datetime(year=2023, month=12, day=17, hour=0, minute=0)) + .get_data( + start_date=datetime( + year=2023, month=12, day=17, hour=0, minute=0 + ) + ) self.assertEqual( ["Datetime", "Open", "High", "Low", "Close", "Volume"], df.columns ) - -# def test_start_date(self): - # start_date = datetime(2023, 12, 1) - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # csv_ohlcv_market_data_source = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}" - # ) - # self.assertEqual( - # start_date, - # csv_ohlcv_market_data_source.start_date.replace(microsecond=0), - # ) - # - # def test_end_date(self): - # end_date = datetime(2023, 12, 25) - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # csv_ohlcv_market_data_source = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}" - # ) - # self.assertEqual( - # end_date, - # csv_ohlcv_market_data_source.end_date.replace(microsecond=0), - # ) - # - # def test_empty(self): - # start_date = datetime(2023, 12, 1) - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # data_source = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}" - # ) - # self.assertFalse(data_source.empty()) - # self.assertEqual(start_date, data_source.start_date) - # data_source.start_date = datetime(2023, 12, 25) - # data_source.end_date = datetime(2023, 12, 16) - # self.assertTrue(data_source.empty()) - - # def test_get_identifier(self): - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # datasource = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}", - # identifier="test" - # ) - # self.assertEqual("test", datasource.get_identifier()) - # - # def test_get_market(self): - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # datasource = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}", - # market="test" - # ) - # self.assertEqual("test", datasource.get_market()) - # - # def test_get_symbol(self): - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # datasource = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}", - # symbol="BTC/EUR" - # ) - # self.assertEqual("BTC/EUR", datasource.get_symbol()) - # - # def test_get_timeframe(self): - # file_name = "OHLCV_BTC-EUR_BINANCE_15m_2023-12-" \ - # "01:00:00_2023-12-25:00:00.csv" - # datasource = CSVOHLCVMarketDataSource( - # csv_file_path=f"{self.resource_dir}/" - # "market_data_sources/" - # f"{file_name}", - # timeframe="15m" - # ) - # self.assertEqual("15m", datasource.get_timeframe()) - diff --git a/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_market_data_source.py b/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_market_data_source.py index b2a243ee..e42e0930 100644 --- a/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_market_data_source.py +++ b/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_market_data_source.py @@ -1,5 +1,4 @@ import os -from datetime import datetime, timedelta from unittest import TestCase from investing_algorithm_framework.infrastructure import \ @@ -35,35 +34,6 @@ def test_window_size(self): ) self.assertEqual(200, ccxt_ohlcv_market_data_source.window_size) - def test_start_date(self): - current_datetime = datetime.utcnow() - ccxt_ohlcv_market_data_source = CCXTOHLCVMarketDataSource( - identifier="BTC/EUR", - window_size=200, - timeframe="15m", - market="BITVAVO", - symbol="BTC/EUR", - ) - self.assertEqual( - (current_datetime - timedelta(minutes=200 * 15)) - .strftime("%Y-%m-%d %H:%M"), - ccxt_ohlcv_market_data_source.start_date.strftime("%Y-%m-%d %H:%M") - ) - - def test_end_date(self): - current_datetime = datetime.utcnow() - ccxt_ohlcv_market_data_source = CCXTOHLCVMarketDataSource( - identifier="BTC/EUR", - window_size=200, - timeframe="15m", - market="BITVAVO", - symbol="BTC/EUR", - ) - self.assertEqual( - current_datetime.strftime("%Y-%m-%d %H:%M"), - ccxt_ohlcv_market_data_source.end_date.strftime("%Y-%m-%d %H:%M") - ) - def test_get_market(self): ccxt_ohlcv_market_data_source = CCXTOHLCVMarketDataSource( identifier="BTC/EUR", @@ -92,4 +62,4 @@ def test_get_timeframe(self): market="BITVAVO", symbol="BTC/EUR", ) - self.assertEqual("15m", ccxt_ohlcv_market_data_source.timeframe) + self.assertEqual("15m", ccxt_ohlcv_market_data_source.timeframe.value) diff --git a/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py b/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py index 40761b19..dc407e09 100644 --- a/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py +++ b/tests/infrastructure/market_data_sources/test_csv_ohlcv_market_data_source.py @@ -71,7 +71,8 @@ def test_start_date(self): ) self.assertEqual( start_date, - csv_ohlcv_market_data_source.start_date.replace(microsecond=0), + csv_ohlcv_market_data_source._start_date_data_source + .replace(microsecond=0), ) def test_start_date_with_window_size(self): @@ -95,27 +96,6 @@ def test_start_date_with_window_size(self): first_date.strftime(DATETIME_FORMAT) ) - def test_start_date_with_backtest_index_date(self): - start_date = datetime(2023, 8, 7, 8, 0, tzinfo=tzutc()) - file_name = "OHLCV_BTC-EUR_BINANCE" \ - "_2h_2023-08-07:07:59_2023-12-02:00:00.csv" - csv_ohlcv_market_data_source = CSVOHLCVMarketDataSource( - csv_file_path=f"{self.resource_dir}/" - "market_data_sources/" - f"{file_name}", - window_size=10, - timeframe=TimeFrame.TWO_HOUR, - ) - data = csv_ohlcv_market_data_source.get_data( - backtest_index_date=datetime(2023, 8, 7, 8, 0, tzinfo=tzutc()) - ) - self.assertEqual(10, len(data)) - first_date = parser.parse(data["Datetime"][0]) - self.assertEqual( - start_date.strftime(DATETIME_FORMAT), - first_date.strftime(DATETIME_FORMAT) - ) - def test_end_date(self): end_date = datetime(2023, 12, 2, 0, 0, tzinfo=tzutc()) file_name = "OHLCV_BTC-EUR_BINANCE" \ @@ -127,7 +107,8 @@ def test_end_date(self): ) self.assertEqual( end_date, - csv_ohlcv_market_data_source.end_date.replace(microsecond=0), + csv_ohlcv_market_data_source + ._end_date_data_source.replace(microsecond=0), ) def test_empty(self): @@ -145,21 +126,22 @@ def test_empty(self): self.assertFalse(data_source.empty(start_date, end_date)) def test_get_data(self): - file_name = "OHLCV_BTC-EUR_BINANCE" \ - "_2h_2023-08-07:07:59_2023-12-02:00:00.csv" + file_name = \ + "OHLCV_BTC-EUR_BITVAVO_2h_2023-07-21:14:00_2024-06-07:10:00.csv" datasource = CSVOHLCVMarketDataSource( csv_file_path=f"{self.resource_dir}/" - "market_data_sources/" + "market_data_sources_for_testing/" f"{file_name}", window_size=200, timeframe="2h", ) number_of_runs = 0 - backtest_index_date = datasource.start_date + backtest_index_date = datasource._start_date_data_source - while not datasource.empty(): - data = datasource.get_data(backtest_index_date=backtest_index_date) - backtest_index_date = parser.parse(data["Datetime"][-1]) + while not datasource.empty(start_date=backtest_index_date): + data = datasource.get_data(start_date=backtest_index_date) + backtest_index_date = \ + backtest_index_date + timedelta(hours=2 * 200) self.assertTrue(len(data) > 0) self.assertTrue(isinstance(data, DataFrame)) number_of_runs += 1 @@ -214,4 +196,4 @@ def test_get_timeframe(self): timeframe="2h", window_size=10, ) - self.assertEqual("2h", datasource.get_timeframe()) + self.assertEqual(TimeFrame.TWO_HOUR, datasource.get_timeframe()) diff --git a/tests/infrastructure/models/test_portfolio.py b/tests/infrastructure/models/test_portfolio.py index b4870d6d..37245d52 100644 --- a/tests/infrastructure/models/test_portfolio.py +++ b/tests/infrastructure/models/test_portfolio.py @@ -160,8 +160,12 @@ # self.assertIsNotNone(position_b) # self.assertIsNotNone(position_c) # -# self.assertEqual(self.TARGET_SYMBOL_B, position_b.get_target_symbol()) -# self.assertEqual(self.TARGET_SYMBOL_C, position_c.get_target_symbol()) +# self.assertEqual( +# self.TARGET_SYMBOL_B, position_b.get_target_symbol() +# ) +# self.assertEqual( +# self.TARGET_SYMBOL_C, position_c.get_target_symbol() +# ) # # def test_get_positions(self): # portfolio_manager = self.algo_app.algorithm \ @@ -337,7 +341,8 @@ # "trading_symbol": "usdt", # "amount": 4, # "price": self.get_price(self.TARGET_SYMBOL_A).price, -# "initial_price": self.get_price(self.TARGET_SYMBOL_A).price, +# "initial_price": self +# .get_price(self.TARGET_SYMBOL_A).price, # "status": OrderStatus.CLOSED.value, # "order_side": OrderSide.BUY.value, # "order_type": OrderType.LIMIT.value @@ -363,7 +368,8 @@ # "amount": 4, # "price": self.get_price(self.TARGET_SYMBOL_A).price, # "status": OrderStatus.CLOSED.value, -# "initial_price": self.get_price(self.TARGET_SYMBOL_A).price, +# "initial_price": self +# .get_price(self.TARGET_SYMBOL_A).price, # "order_side": OrderSide.BUY.value, # "order_type": OrderType.LIMIT.value # } diff --git a/tests/infrastructure/order_validators/test_default_order_validator.py b/tests/infrastructure/order_validators/test_default_order_validator.py index 25c6c44d..cc15da5e 100644 --- a/tests/infrastructure/order_validators/test_default_order_validator.py +++ b/tests/infrastructure/order_validators/test_default_order_validator.py @@ -1,4 +1,5 @@ -# from investing_algorithm_framework.core.exceptions import OperationalException +# from investing_algorithm_framework.core.exceptions import +# OperationalException # from investing_algorithm_framework.core.models import OrderSide, OrderStatus # from investing_algorithm_framework.core.models import OrderType # from tests.resources import TestBase, TestOrderAndPositionsObjectsMixin @@ -92,4 +93,4 @@ # target_symbol=self.TARGET_SYMBOL_A, # price=self.BASE_SYMBOL_A_PRICE, # algorithm_context=None -# ) \ No newline at end of file +# ) diff --git a/tests/infrastructure/repositories/test_order_repository.py b/tests/infrastructure/repositories/test_order_repository.py index 58a19cef..abd270c0 100644 --- a/tests/infrastructure/repositories/test_order_repository.py +++ b/tests/infrastructure/repositories/test_order_repository.py @@ -1,4 +1,5 @@ -from investing_algorithm_framework import PortfolioConfiguration, MarketCredential +from investing_algorithm_framework import PortfolioConfiguration, \ + MarketCredential from tests.resources import TestBase diff --git a/tests/infrastructure/repositories/test_position_repository.py b/tests/infrastructure/repositories/test_position_repository.py index a33f94a8..a2ba0a99 100644 --- a/tests/infrastructure/repositories/test_position_repository.py +++ b/tests/infrastructure/repositories/test_position_repository.py @@ -46,5 +46,6 @@ def test_get_all(self): 2, position_service.count({"portfolio": portfolio.id}) ) self.assertEqual( - 0, position_service.count({"portfolio": f"{portfolio.identifier}aeokgopge"}) + 0, position_service + .count({"portfolio": f"{portfolio.identifier}aeokgopge"}) ) diff --git a/tests/infrastructure/services/test_ccxt_market_service.py b/tests/infrastructure/services/test_ccxt_market_service.py index c9aaabe3..7ff9d349 100644 --- a/tests/infrastructure/services/test_ccxt_market_service.py +++ b/tests/infrastructure/services/test_ccxt_market_service.py @@ -16,5 +16,6 @@ # self.start_algorithm() # # def test(self) -> None: -# market_service = self.algo_app.algorithm.get_market_service("binance") +# market_service = self.algo_app.algorithm +# .get_market_service("binance") # self.assertIsNotNone(market_service.exchange_class) diff --git a/tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BITVAVO_2h_2023-07-21:14:00_2024-06-07:10:00.csv b/tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BITVAVO_2h_2023-07-21:14:00_2024-06-07:10:00.csv new file mode 100644 index 00000000..e789bc29 --- /dev/null +++ b/tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BITVAVO_2h_2023-07-21:14:00_2024-06-07:10:00.csv @@ -0,0 +1,3857 @@ +Datetime,Open,High,Low,Close,Volume +2023-07-21 14:00:00,26838.0,26924.0,26806.0,26883.0,8.76283505 +2023-07-21 16:00:00,26880.0,26923.0,26811.0,26907.0,9.48677559 +2023-07-21 18:00:00,26920.0,27033.0,26770.0,26841.0,19.44459641 +2023-07-21 20:00:00,26865.0,26906.0,26813.0,26858.0,16.41557285 +2023-07-21 22:00:00,26875.0,26932.0,26858.0,26898.0,3.44748452 +2023-07-22 00:00:00,26874.0,26962.0,26874.0,26919.0,0.83525859 +2023-07-22 02:00:00,26917.0,26940.0,26855.0,26897.0,2.2729936 +2023-07-22 04:00:00,26876.0,26906.0,26827.0,26858.0,2.98002492 +2023-07-22 06:00:00,26856.0,26976.0,26825.0,26946.0,8.40437076 +2023-07-22 08:00:00,26946.0,26974.0,26890.0,26895.0,12.93837112 +2023-07-22 10:00:00,26905.0,26916.0,26851.0,26878.0,5.89365438 +2023-07-22 12:00:00,26878.0,26884.0,26830.0,26853.0,7.29788034 +2023-07-22 14:00:00,26873.0,26921.0,26836.0,26914.0,17.05166682 +2023-07-22 16:00:00,26914.0,26914.0,26809.0,26829.0,7.58726743 +2023-07-22 18:00:00,26850.0,26850.0,26786.0,26811.0,11.70052102 +2023-07-22 20:00:00,26808.0,26857.0,26793.0,26819.0,7.95502118 +2023-07-22 22:00:00,26838.0,26844.0,26660.0,26799.0,5.75552375 +2023-07-23 00:00:00,26807.0,26810.0,26749.0,26788.0,0.68356743 +2023-07-23 06:00:00,26810.0,26913.0,26810.0,26906.0,7.96201134 +2023-07-23 08:00:00,26906.0,26978.0,26874.0,26919.0,14.862321 +2023-07-23 10:00:00,26922.0,26933.0,26845.0,26888.0,12.45421048 +2023-07-23 12:00:00,26873.0,26925.0,26850.0,26897.0,9.77049967 +2023-07-23 14:00:00,26896.0,26916.0,26872.0,26876.0,11.72022889 +2023-07-23 16:00:00,26896.0,27072.0,26881.0,27072.0,15.40178982 +2023-07-23 18:00:00,27059.0,27292.0,26975.0,27039.0,50.45072922 +2023-07-23 20:00:00,27039.0,27110.0,26893.0,26902.0,14.67285254 +2023-07-23 22:00:00,26933.0,27061.0,26908.0,27061.0,4.14104734 +2023-07-24 00:00:00,27075.0,27086.0,26871.0,26930.0,4.78180843 +2023-07-24 02:00:00,26897.0,26924.0,26700.0,26738.0,9.16380842 +2023-07-24 04:00:00,26733.0,26835.0,26693.0,26802.0,15.84300166 +2023-07-24 06:00:00,26802.0,26964.0,26683.0,26935.0,14.72259847 +2023-07-24 08:00:00,26936.0,26962.0,26292.0,26385.0,55.7675918 +2023-07-24 10:00:00,26350.0,26537.0,26308.0,26379.0,77.4975739 +2023-07-24 12:00:00,26366.0,26421.0,26270.0,26345.0,42.27419088 +2023-07-24 14:00:00,26344.0,26350.0,26085.0,26271.0,65.60870994 +2023-07-24 16:00:00,26243.0,26323.0,26211.0,26248.0,31.6724772 +2023-07-24 18:00:00,26229.0,26374.0,26202.0,26352.0,23.16188857 +2023-07-24 20:00:00,26344.0,26407.0,26315.0,26384.0,18.70994668 +2023-07-24 22:00:00,26393.0,26417.0,26357.0,26403.0,6.52879523 +2023-07-25 00:00:00,26396.0,26399.0,26274.0,26288.0,2.36480372 +2023-07-25 02:00:00,26294.0,26359.0,26261.0,26299.0,1.96615113 +2023-07-25 04:00:00,26308.0,26339.0,26261.0,26321.0,6.85013593 +2023-07-25 06:00:00,26320.0,26360.0,26280.0,26321.0,16.77560748 +2023-07-25 08:00:00,26342.0,26500.0,26322.0,26425.0,24.57494519 +2023-07-25 10:00:00,26433.0,26455.0,26346.0,26361.0,18.49933393 +2023-07-25 12:00:00,26361.0,26590.0,26323.0,26526.0,17.99263401 +2023-07-25 14:00:00,26540.0,26599.0,26408.0,26408.0,17.54172722 +2023-07-25 16:00:00,26428.0,26546.0,26416.0,26542.0,19.96621378 +2023-07-25 18:00:00,26543.0,26619.0,26423.0,26433.0,21.78106622 +2023-07-25 20:00:00,26440.0,26477.0,26413.0,26456.0,13.89030043 +2023-07-25 22:00:00,26464.0,26480.0,26421.0,26463.0,3.61779466 +2023-07-26 00:00:00,26465.0,26474.0,26364.0,26410.0,3.73152508 +2023-07-26 02:00:00,26389.0,26622.0,26389.0,26455.0,3.61913688 +2023-07-26 04:00:00,26456.0,26494.0,26423.0,26457.0,5.2302312 +2023-07-26 06:00:00,26481.0,26486.0,26373.0,26385.0,19.55385199 +2023-07-26 08:00:00,26385.0,26407.0,26336.0,26338.0,14.51036621 +2023-07-26 10:00:00,26355.0,26396.0,26306.0,26385.0,21.42374784 +2023-07-26 12:00:00,26361.0,26492.0,26358.0,26478.0,25.29327231 +2023-07-26 14:00:00,26479.0,26500.0,26377.0,26491.0,18.57498781 +2023-07-26 16:00:00,26470.0,26520.0,26422.0,26471.0,24.69436411 +2023-07-26 18:00:00,26484.0,26610.0,26356.0,26499.0,32.4139111 +2023-07-26 20:00:00,26500.0,26774.0,26500.0,26571.0,35.51069446 +2023-07-26 22:00:00,26576.0,26632.0,26444.0,26495.0,8.28255503 +2023-07-27 00:00:00,26499.0,26526.0,26435.0,26480.0,3.10348855 +2023-07-27 02:00:00,26508.0,26542.0,26422.0,26492.0,2.10293893 +2023-07-27 04:00:00,26511.0,26600.0,26498.0,26593.0,2.67381652 +2023-07-27 06:00:00,26588.0,26597.0,26444.0,26459.0,9.65213673 +2023-07-27 08:00:00,26459.0,26587.0,26423.0,26555.0,15.41595993 +2023-07-27 10:00:00,26554.0,26554.0,26470.0,26520.0,11.46355143 +2023-07-27 12:00:00,26513.0,26775.0,26500.0,26735.0,32.93247481 +2023-07-27 14:00:00,26729.0,26744.0,26573.0,26608.0,19.74839089 +2023-07-27 16:00:00,26611.0,26665.0,26522.0,26556.0,22.88739306 +2023-07-27 18:00:00,26556.0,26580.0,26454.0,26556.0,29.43584841 +2023-07-27 20:00:00,26580.0,26621.0,26515.0,26582.0,17.32862098 +2023-07-27 22:00:00,26585.0,26617.0,26544.0,26574.0,6.71535711 +2023-07-28 00:00:00,26577.0,26650.0,26565.0,26622.0,0.99438493 +2023-07-28 02:00:00,26622.0,26629.0,26550.0,26597.0,5.30813284 +2023-07-28 04:00:00,26618.0,26650.0,26547.0,26569.0,4.21602606 +2023-07-28 06:00:00,26563.0,26605.0,26531.0,26572.0,10.31146369 +2023-07-28 08:00:00,26572.0,26622.0,26549.0,26603.0,13.13705619 +2023-07-28 10:00:00,26622.0,26634.0,26500.0,26527.0,12.6198605 +2023-07-28 12:00:00,26536.0,26644.0,26498.0,26596.0,13.73144369 +2023-07-28 14:00:00,26591.0,26759.0,26553.0,26602.0,22.99881412 +2023-07-28 16:00:00,26630.0,26633.0,26500.0,26544.0,14.89922437 +2023-07-28 18:00:00,26536.0,26609.0,26528.0,26584.0,7.96989592 +2023-07-28 20:00:00,26604.0,26650.0,26575.0,26618.0,7.58365882 +2023-07-28 22:00:00,26615.0,26619.0,26564.0,26599.0,5.95937699 +2023-07-29 00:00:00,26580.0,26624.0,26575.0,26619.0,2.15013363 +2023-07-29 02:00:00,26619.0,26639.0,26606.0,26634.0,0.9110052 +2023-07-29 04:00:00,26635.0,26648.0,26604.0,26620.0,3.67601372 +2023-07-29 06:00:00,26633.0,26647.0,26575.0,26579.0,6.94554258 +2023-07-29 08:00:00,26579.0,26608.0,26521.0,26551.0,12.77977228 +2023-07-29 10:00:00,26536.0,26572.0,26520.0,26539.0,9.81709004 +2023-07-29 12:00:00,26538.0,26613.0,26519.0,26556.0,7.1251331 +2023-07-29 14:00:00,26578.0,26616.0,26552.0,26588.0,11.33045214 +2023-07-29 16:00:00,26591.0,26622.0,26586.0,26619.0,4.96111364 +2023-07-29 18:00:00,26620.0,26620.0,26575.0,26601.0,5.59549446 +2023-07-29 20:00:00,26619.0,26672.0,26601.0,26640.0,11.02168233 +2023-07-29 22:00:00,26640.0,26649.0,26608.0,26620.0,2.65702322 +2023-07-30 00:00:00,26620.0,26634.0,26583.0,26608.0,0.88411907 +2023-07-30 02:00:00,26607.0,26607.0,26571.0,26593.0,0.51107998 +2023-07-30 04:00:00,26574.0,26614.0,26573.0,26592.0,2.94279923 +2023-07-30 06:00:00,26592.0,26593.0,26530.0,26582.0,10.78308323 +2023-07-30 08:00:00,26580.0,26608.0,26567.0,26573.0,11.33707628 +2023-07-30 10:00:00,26598.0,26630.0,26543.0,26620.0,7.21141879 +2023-07-30 12:00:00,26607.0,26637.0,26590.0,26602.0,6.88263404 +2023-07-30 14:00:00,26604.0,26719.0,26580.0,26622.0,8.06306365 +2023-07-30 16:00:00,26620.0,26664.0,26582.0,26660.0,6.36201903 +2023-07-30 18:00:00,26660.0,26671.0,26450.0,26481.0,16.13715461 +2023-07-30 20:00:00,26482.0,26589.0,26391.0,26511.0,27.12867409 +2023-07-30 22:00:00,26512.0,26557.0,26433.0,26557.0,4.80135311 +2023-07-31 00:00:00,26557.0,26754.0,26529.0,26716.0,5.96392881 +2023-07-31 02:00:00,26716.0,26760.0,26699.0,26716.0,5.1215927 +2023-07-31 04:00:00,26705.0,26715.0,26637.0,26650.0,10.75146062 +2023-07-31 06:00:00,26651.0,26722.0,26630.0,26648.0,14.65846106 +2023-07-31 08:00:00,26646.0,26693.0,26557.0,26604.0,11.1406759 +2023-07-31 10:00:00,26604.0,26670.0,26588.0,26670.0,14.82708336 +2023-07-31 12:00:00,26656.0,26740.0,26558.0,26607.0,15.66963062 +2023-07-31 14:00:00,26609.0,26627.0,26520.0,26530.0,18.72344025 +2023-07-31 16:00:00,26547.0,26582.0,26465.0,26545.0,16.29278447 +2023-07-31 18:00:00,26545.0,26574.0,26461.0,26520.0,10.37114125 +2023-07-31 20:00:00,26512.0,26617.0,26471.0,26581.0,10.38419868 +2023-07-31 22:00:00,26554.0,26583.0,26515.0,26556.0,6.40293673 +2023-08-01 00:00:00,26577.0,26689.0,26545.0,26577.0,0.68271941 +2023-08-01 02:00:00,26576.0,26582.0,26232.0,26256.0,22.1615415 +2023-08-01 04:00:00,26255.0,26329.0,26230.0,26306.0,24.39160042 +2023-08-01 06:00:00,26300.0,26384.0,26276.0,26358.0,15.36354838 +2023-08-01 08:00:00,26359.0,26435.0,26332.0,26350.0,19.17952379 +2023-08-01 10:00:00,26357.0,26357.0,26271.0,26289.0,16.256895 +2023-08-01 12:00:00,26292.0,26360.0,26222.0,26314.0,15.56834148 +2023-08-01 14:00:00,26308.0,26406.0,26115.0,26379.0,20.92325005 +2023-08-01 16:00:00,26384.0,26475.0,26283.0,26405.0,19.09963186 +2023-08-01 18:00:00,26405.0,26700.0,26390.0,26651.0,19.69342571 +2023-08-01 20:00:00,26633.0,26670.0,26485.0,26512.0,12.18169694 +2023-08-01 22:00:00,26529.0,26941.0,26464.0,26941.0,24.26123838 +2023-08-02 00:00:00,26931.0,27247.0,26930.0,27115.0,36.67560952 +2023-08-02 02:00:00,27119.0,27168.0,26922.0,26938.0,15.43527603 +2023-08-02 04:00:00,26939.0,27011.0,26874.0,26909.0,20.79781105 +2023-08-02 06:00:00,26910.0,26966.0,26846.0,26854.0,26.4956681 +2023-08-02 08:00:00,26867.0,26881.0,26721.0,26810.0,18.87438274 +2023-08-02 10:00:00,26780.0,26935.0,26779.0,26921.0,15.6250185 +2023-08-02 12:00:00,26933.0,26950.0,26765.0,26856.0,18.35174785 +2023-08-02 14:00:00,26841.0,26864.0,26672.0,26780.0,20.81384062 +2023-08-02 16:00:00,26773.0,26797.0,26418.0,26629.0,40.31427772 +2023-08-02 18:00:00,26622.0,26704.0,26535.0,26659.0,14.28303652 +2023-08-02 20:00:00,26649.0,26690.0,26565.0,26656.0,9.39701367 +2023-08-02 22:00:00,26670.0,26703.0,26613.0,26630.0,4.82981757 +2023-08-03 00:00:00,26652.0,26720.0,26646.0,26704.0,0.6619431 +2023-08-03 02:00:00,26730.0,26735.0,26611.0,26680.0,1.95934269 +2023-08-03 04:00:00,26675.0,26686.0,26610.0,26633.0,5.84429456 +2023-08-03 06:00:00,26640.0,26653.0,26545.0,26575.0,10.86188913 +2023-08-03 08:00:00,26575.0,26660.0,26511.0,26640.0,20.25038541 +2023-08-03 10:00:00,26641.0,26700.0,26597.0,26623.0,7.62425486 +2023-08-03 12:00:00,26641.0,26727.0,26550.0,26699.0,7.95469246 +2023-08-03 14:00:00,26699.0,26874.0,26640.0,26707.0,15.64420655 +2023-08-03 16:00:00,26681.0,26800.0,26651.0,26710.0,11.81095046 +2023-08-03 18:00:00,26684.0,26772.0,26615.0,26756.0,9.41846279 +2023-08-03 20:00:00,26757.0,26814.0,26692.0,26705.0,10.54822893 +2023-08-03 22:00:00,26705.0,26733.0,26626.0,26658.0,6.60215602 +2023-08-04 00:00:00,26660.0,26681.0,26614.0,26641.0,1.72642395 +2023-08-04 02:00:00,26640.0,26650.0,26572.0,26625.0,5.82186061 +2023-08-04 04:00:00,26625.0,26701.0,26589.0,26691.0,3.62664326 +2023-08-04 06:00:00,26672.0,26705.0,26604.0,26672.0,11.21900743 +2023-08-04 08:00:00,26672.0,26708.0,26633.0,26671.0,13.21989061 +2023-08-04 10:00:00,26672.0,26674.0,26608.0,26665.0,9.12073734 +2023-08-04 12:00:00,26659.0,26683.0,26503.0,26563.0,23.52965968 +2023-08-04 14:00:00,26563.0,26578.0,26500.0,26538.0,9.56094108 +2023-08-04 16:00:00,26526.0,26552.0,26471.0,26488.0,8.1012537 +2023-08-04 18:00:00,26489.0,26491.0,26311.0,26361.0,22.58429967 +2023-08-04 20:00:00,26363.0,26417.0,26186.0,26389.0,33.12760032 +2023-08-04 22:00:00,26372.0,26449.0,26372.0,26419.0,4.10591201 +2023-08-05 00:00:00,26440.0,26475.0,26381.0,26385.0,2.42635116 +2023-08-05 02:00:00,26394.0,26420.0,26382.0,26409.0,0.86820109 +2023-08-05 04:00:00,26396.0,26418.0,26358.0,26411.0,3.79589115 +2023-08-05 06:00:00,26411.0,26414.0,26363.0,26372.0,13.91120507 +2023-08-05 08:00:00,26365.0,26412.0,26362.0,26380.0,17.54105463 +2023-08-05 10:00:00,26377.0,26421.0,26373.0,26392.0,7.88063776 +2023-08-05 12:00:00,26392.0,26392.0,26332.0,26352.0,8.43388023 +2023-08-05 14:00:00,26372.0,26417.0,26336.0,26383.0,8.34091689 +2023-08-05 16:00:00,26383.0,26407.0,26339.0,26407.0,9.53092937 +2023-08-05 18:00:00,26390.0,26443.0,26383.0,26416.0,11.36752284 +2023-08-05 20:00:00,26398.0,26440.0,26381.0,26415.0,5.53769791 +2023-08-05 22:00:00,26425.0,26439.0,26407.0,26423.0,2.69194886 +2023-08-06 00:00:00,26423.0,26423.0,26378.0,26380.0,0.97071147 +2023-08-06 02:00:00,26391.0,26427.0,26379.0,26389.0,1.50521234 +2023-08-06 04:00:00,26408.0,26447.0,26395.0,26434.0,4.05269722 +2023-08-06 06:00:00,26434.0,26450.0,26386.0,26441.0,4.69653268 +2023-08-06 08:00:00,26441.0,26475.0,26406.0,26430.0,7.3907104 +2023-08-06 10:00:00,26430.0,26431.0,26380.0,26403.0,6.96621187 +2023-08-06 12:00:00,26414.0,26414.0,26352.0,26352.0,12.64869542 +2023-08-06 14:00:00,26352.0,26393.0,26344.0,26358.0,10.65935522 +2023-08-06 16:00:00,26356.0,26428.0,26343.0,26423.0,8.48450146 +2023-08-06 18:00:00,26428.0,26436.0,26404.0,26423.0,5.27190012 +2023-08-06 20:00:00,26423.0,26499.0,26358.0,26387.0,16.41311589 +2023-08-06 22:00:00,26396.0,26472.0,26391.0,26416.0,2.31108657 +2023-08-07 00:00:00,26411.0,26519.0,26350.0,26474.0,2.03741779 +2023-08-07 02:00:00,26484.0,26528.0,26458.0,26500.0,1.59086734 +2023-08-07 04:00:00,26494.0,26544.0,26465.0,26487.0,2.15144465 +2023-08-07 06:00:00,26488.0,26494.0,26406.0,26430.0,10.50334555 +2023-08-07 08:00:00,26415.0,26501.0,26391.0,26493.0,13.27277697 +2023-08-07 10:00:00,26491.0,26532.0,26443.0,26453.0,10.98036873 +2023-08-07 12:00:00,26452.0,26479.0,26363.0,26382.0,9.80520816 +2023-08-07 14:00:00,26382.0,26424.0,26177.0,26202.0,24.83261637 +2023-08-07 16:00:00,26202.0,26343.0,26111.0,26320.0,41.93444444 +2023-08-07 18:00:00,26320.0,26500.0,26304.0,26460.0,18.33020852 +2023-08-07 20:00:00,26460.0,26584.0,26442.0,26500.0,17.34126244 +2023-08-07 22:00:00,26481.0,26509.0,26456.0,26495.0,2.942693 +2023-08-08 00:00:00,26494.0,26580.0,26491.0,26519.0,4.627545 +2023-08-08 02:00:00,26515.0,26543.0,26501.0,26533.0,0.41914114 +2023-08-08 04:00:00,26534.0,26610.0,26518.0,26534.0,8.92657975 +2023-08-08 06:00:00,26547.0,26579.0,26523.0,26555.0,9.71082049 +2023-08-08 08:00:00,26541.0,26593.0,26506.0,26577.0,11.99851572 +2023-08-08 10:00:00,26577.0,26842.0,26560.0,26840.0,34.79489252 +2023-08-08 12:00:00,26842.0,27062.0,26759.0,26800.0,78.52701498 +2023-08-08 14:00:00,26799.0,27000.0,26788.0,26950.0,32.13633445 +2023-08-08 16:00:00,26950.0,27212.0,26931.0,27149.0,55.51053341 +2023-08-08 18:00:00,27167.0,27303.0,27119.0,27223.0,58.58192962 +2023-08-08 20:00:00,27248.0,27540.0,27183.0,27220.0,77.41769949 +2023-08-08 22:00:00,27224.0,27243.0,27058.0,27130.0,12.92868776 +2023-08-09 00:00:00,27117.0,27200.0,27117.0,27200.0,1.62147694 +2023-08-09 02:00:00,27198.0,27200.0,27021.0,27074.0,7.59684232 +2023-08-09 04:00:00,27055.0,27130.0,27051.0,27076.0,17.55908325 +2023-08-09 06:00:00,27059.0,27144.0,26989.0,27116.0,32.18144648 +2023-08-09 08:00:00,27117.0,27166.0,27087.0,27113.0,15.53540542 +2023-08-09 10:00:00,27113.0,27243.0,27100.0,27243.0,18.81599507 +2023-08-09 12:00:00,27216.0,27435.0,27173.0,27200.0,35.78829306 +2023-08-09 14:00:00,27196.0,27257.0,27025.0,27101.0,21.53871718 +2023-08-09 16:00:00,27114.0,27123.0,26808.0,26870.0,40.09694409 +2023-08-09 18:00:00,26870.0,26937.0,26761.0,26792.0,25.01718571 +2023-08-09 20:00:00,26769.0,26929.0,26750.0,26883.0,19.62713144 +2023-08-09 22:00:00,26878.0,26986.0,26877.0,26921.0,2.46885031 +2023-08-10 00:00:00,26940.0,27020.0,26919.0,26936.0,5.39105911 +2023-08-10 02:00:00,26977.0,27001.0,26916.0,26935.0,1.52369627 +2023-08-10 04:00:00,26917.0,26930.0,26843.0,26919.0,5.50350322 +2023-08-10 06:00:00,26919.0,26926.0,26763.0,26777.0,8.93049699 +2023-08-10 08:00:00,26777.0,26799.0,26734.0,26773.0,23.65655008 +2023-08-10 10:00:00,26782.0,26792.0,26721.0,26759.0,25.21479112 +2023-08-10 12:00:00,26756.0,26931.0,26702.0,26876.0,27.0876016 +2023-08-10 14:00:00,26881.0,26932.0,26695.0,26726.0,17.57830547 +2023-08-10 16:00:00,26725.0,26800.0,26670.0,26765.0,12.76018282 +2023-08-10 18:00:00,26764.0,26809.0,26731.0,26802.0,8.68654601 +2023-08-10 20:00:00,26802.0,26843.0,26773.0,26802.0,8.23299931 +2023-08-10 22:00:00,26818.0,26841.0,26785.0,26799.0,5.94613286 +2023-08-11 00:00:00,26802.0,26841.0,26752.0,26752.0,4.26248385 +2023-08-11 02:00:00,26772.0,26772.0,26691.0,26745.0,2.35322344 +2023-08-11 04:00:00,26725.0,26792.0,26719.0,26770.0,13.37543109 +2023-08-11 06:00:00,26780.0,26809.0,26721.0,26721.0,17.88743055 +2023-08-11 08:00:00,26721.0,26769.0,26707.0,26751.0,11.06175719 +2023-08-11 10:00:00,26751.0,26770.0,26705.0,26748.0,13.14426384 +2023-08-11 12:00:00,26768.0,26880.0,26732.0,26870.0,10.50442376 +2023-08-11 14:00:00,26855.0,26946.0,26769.0,26818.0,14.87958731 +2023-08-11 16:00:00,26812.0,26839.0,26712.0,26781.0,6.22849036 +2023-08-11 18:00:00,26792.0,26840.0,26775.0,26822.0,6.03767288 +2023-08-11 20:00:00,26811.0,26877.0,26809.0,26830.0,3.94171168 +2023-08-11 22:00:00,26847.0,26873.0,26829.0,26862.0,3.91105104 +2023-08-12 00:00:00,26844.0,26870.0,26821.0,26829.0,0.51840768 +2023-08-12 02:00:00,26829.0,26850.0,26802.0,26827.0,0.65805186 +2023-08-12 04:00:00,26828.0,26869.0,26816.0,26816.0,5.2261735 +2023-08-12 06:00:00,26840.0,26873.0,26803.0,26861.0,7.69361905 +2023-08-12 08:00:00,26862.0,26871.0,26821.0,26849.0,6.70224673 +2023-08-12 10:00:00,26871.0,26897.0,26846.0,26888.0,11.96768617 +2023-08-12 12:00:00,26888.0,26889.0,26851.0,26873.0,8.74904505 +2023-08-12 14:00:00,26852.0,26931.0,26851.0,26909.0,9.76170598 +2023-08-12 16:00:00,26908.0,26950.0,26878.0,26878.0,6.80527148 +2023-08-12 18:00:00,26898.0,26899.0,26849.0,26853.0,4.07386428 +2023-08-12 20:00:00,26870.0,26896.0,26852.0,26892.0,3.95565198 +2023-08-12 22:00:00,26873.0,26907.0,26869.0,26905.0,2.21787729 +2023-08-13 00:00:00,26904.0,26929.0,26877.0,26902.0,4.15864836 +2023-08-13 02:00:00,26920.0,26927.0,26861.0,26870.0,0.20959648 +2023-08-13 04:00:00,26870.0,26886.0,26840.0,26841.0,1.94216871 +2023-08-13 06:00:00,26858.0,26880.0,26836.0,26875.0,3.81798657 +2023-08-13 08:00:00,26875.0,26889.0,26847.0,26862.0,7.03958574 +2023-08-13 10:00:00,26882.0,26890.0,26825.0,26846.0,5.11867565 +2023-08-13 12:00:00,26859.0,26864.0,26813.0,26842.0,11.58742868 +2023-08-13 14:00:00,26828.0,26863.0,26819.0,26826.0,7.42449113 +2023-08-13 16:00:00,26845.0,26856.0,26783.0,26842.0,11.07757768 +2023-08-13 18:00:00,26851.0,26904.0,26832.0,26883.0,9.68829254 +2023-08-13 20:00:00,26889.0,26890.0,26792.0,26798.0,8.20778083 +2023-08-13 22:00:00,26811.0,26835.0,26750.0,26770.0,5.06825207 +2023-08-14 00:00:00,26763.0,26793.0,26720.0,26751.0,1.67895942 +2023-08-14 02:00:00,26744.0,26885.0,26615.0,26839.0,12.70991232 +2023-08-14 04:00:00,26866.0,26906.0,26844.0,26895.0,3.36156264 +2023-08-14 06:00:00,26907.0,26925.0,26811.0,26836.0,9.10462604 +2023-08-14 08:00:00,26839.0,26878.0,26796.0,26830.0,8.12915263 +2023-08-14 10:00:00,26830.0,26869.0,26803.0,26851.0,8.6544177 +2023-08-14 12:00:00,26851.0,26973.0,26831.0,26936.0,13.50558648 +2023-08-14 14:00:00,26940.0,27135.0,26909.0,27073.0,35.17021204 +2023-08-14 16:00:00,27055.0,27117.0,26950.0,26951.0,24.88426131 +2023-08-14 18:00:00,26962.0,26970.0,26783.0,26891.0,25.5859008 +2023-08-14 20:00:00,26891.0,26940.0,26853.0,26932.0,9.67536333 +2023-08-14 22:00:00,26916.0,26990.0,26915.0,26959.0,5.13785183 +2023-08-15 00:00:00,26940.0,26974.0,26900.0,26931.0,0.43395892 +2023-08-15 02:00:00,26926.0,26926.0,26861.0,26898.0,1.67256547 +2023-08-15 04:00:00,26898.0,26919.0,26870.0,26870.0,3.47123148 +2023-08-15 06:00:00,26876.0,26900.0,26828.0,26887.0,9.71352215 +2023-08-15 08:00:00,26887.0,26912.0,26816.0,26829.0,12.1876621 +2023-08-15 10:00:00,26833.0,26861.0,26784.0,26827.0,16.96872053 +2023-08-15 12:00:00,26808.0,26898.0,26790.0,26799.0,8.87485015 +2023-08-15 14:00:00,26798.0,26904.0,26771.0,26802.0,16.11109895 +2023-08-15 16:00:00,26802.0,26842.0,26753.0,26825.0,16.51005175 +2023-08-15 18:00:00,26815.0,26863.0,26620.0,26741.0,31.14318269 +2023-08-15 20:00:00,26723.0,26791.0,26678.0,26758.0,13.14479906 +2023-08-15 22:00:00,26773.0,26781.0,26712.0,26725.0,6.27468235 +2023-08-16 00:00:00,26742.0,26783.0,26706.0,26762.0,1.06704218 +2023-08-16 02:00:00,26762.0,26777.0,26735.0,26754.0,1.33736267 +2023-08-16 04:00:00,26754.0,26757.0,26637.0,26650.0,16.04688353 +2023-08-16 06:00:00,26650.0,26711.0,26620.0,26690.0,25.58917188 +2023-08-16 08:00:00,26685.0,26699.0,26595.0,26641.0,15.92007135 +2023-08-16 10:00:00,26656.0,26700.0,26641.0,26688.0,18.28510692 +2023-08-16 12:00:00,26663.0,26728.0,26595.0,26629.0,15.22401331 +2023-08-16 14:00:00,26603.0,26717.0,26588.0,26645.0,17.09758289 +2023-08-16 16:00:00,26644.0,26749.0,26550.0,26728.0,24.85008052 +2023-08-16 18:00:00,26750.0,26793.0,26712.0,26737.0,10.01732225 +2023-08-16 20:00:00,26720.0,26756.0,26500.0,26539.0,39.92660746 +2023-08-16 22:00:00,26556.0,26599.0,26372.0,26394.0,12.8458067 +2023-08-17 00:00:00,26394.0,26445.0,26100.0,26329.0,33.39805921 +2023-08-17 02:00:00,26330.0,26364.0,26264.0,26344.0,8.20199949 +2023-08-17 04:00:00,26344.0,26380.0,26302.0,26335.0,19.40777326 +2023-08-17 06:00:00,26354.0,26373.0,26237.0,26272.0,37.75476856 +2023-08-17 08:00:00,26271.0,26290.0,26204.0,26268.0,23.03054263 +2023-08-17 10:00:00,26262.0,26276.0,26123.0,26144.0,24.35335457 +2023-08-17 12:00:00,26159.0,26169.0,25998.0,26013.0,70.28745385 +2023-08-17 14:00:00,26004.0,26142.0,25623.0,25668.0,110.41472585 +2023-08-17 16:00:00,25668.0,25793.0,25491.0,25731.0,114.35750262 +2023-08-17 18:00:00,25731.0,25780.0,25607.0,25628.0,41.64171082 +2023-08-17 20:00:00,25627.0,25701.0,23900.0,24335.0,282.51074615 +2023-08-17 22:00:00,24333.0,24815.0,24010.0,24507.0,160.38242013 +2023-08-18 00:00:00,24507.0,24674.0,24414.0,24454.0,32.38774724 +2023-08-18 02:00:00,24449.0,24513.0,24202.0,24267.0,26.331104 +2023-08-18 04:00:00,24267.0,24396.0,24060.0,24304.0,93.68988228 +2023-08-18 06:00:00,24308.0,24471.0,24300.0,24301.0,91.84563904 +2023-08-18 08:00:00,24303.0,24489.0,24291.0,24339.0,80.11342944 +2023-08-18 10:00:00,24345.0,24400.0,24268.0,24381.0,52.37894233 +2023-08-18 12:00:00,24388.0,24390.0,24115.0,24135.0,64.78668232 +2023-08-18 14:00:00,24130.0,24200.0,23838.0,23893.0,123.45341255 +2023-08-18 16:00:00,23895.0,24040.0,23575.0,23898.0,108.96888835 +2023-08-18 18:00:00,23914.0,24164.0,23823.0,23960.0,53.42842686 +2023-08-18 20:00:00,23963.0,24138.0,23948.0,23981.0,36.48532825 +2023-08-18 22:00:00,23976.0,24033.0,23945.0,23988.0,18.36544952 +2023-08-19 00:00:00,23987.0,24079.0,23943.0,23971.0,6.15915621 +2023-08-19 02:00:00,23955.0,23994.0,23874.0,23911.0,5.75517712 +2023-08-19 04:00:00,23909.0,23940.0,23814.0,23833.0,16.83611842 +2023-08-19 06:00:00,23831.0,23872.0,23750.0,23861.0,29.47929862 +2023-08-19 08:00:00,23848.0,23938.0,23826.0,23906.0,22.1789099 +2023-08-19 10:00:00,23893.0,23915.0,23840.0,23859.0,29.42128661 +2023-08-19 12:00:00,23863.0,23924.0,23821.0,23880.0,16.64130685 +2023-08-19 14:00:00,23879.0,24177.0,23879.0,24173.0,50.04446535 +2023-08-19 16:00:00,24173.0,24223.0,24049.0,24067.0,36.9178916 +2023-08-19 18:00:00,24061.0,24139.0,24005.0,24104.0,19.91170915 +2023-08-19 20:00:00,24110.0,24125.0,24006.0,24057.0,12.7508064 +2023-08-19 22:00:00,24045.0,24102.0,24010.0,24076.0,5.88931063 +2023-08-20 00:00:00,24076.0,24160.0,24026.0,24051.0,17.61966085 +2023-08-20 02:00:00,24048.0,24093.0,24021.0,24062.0,2.58381763 +2023-08-20 04:00:00,24071.0,24113.0,24050.0,24052.0,2.84279656 +2023-08-20 06:00:00,24052.0,24072.0,24018.0,24054.0,20.04339048 +2023-08-20 08:00:00,24053.0,24115.0,24027.0,24114.0,13.1529032 +2023-08-20 10:00:00,24102.0,24167.0,24078.0,24147.0,28.79036377 +2023-08-20 12:00:00,24145.0,24178.0,24082.0,24105.0,18.30493198 +2023-08-20 14:00:00,24105.0,24114.0,23959.0,24052.0,25.07366993 +2023-08-20 16:00:00,24063.0,24100.0,23975.0,24076.0,23.312397 +2023-08-20 18:00:00,24084.0,24114.0,24052.0,24100.0,11.21609942 +2023-08-20 20:00:00,24086.0,24200.0,24065.0,24090.0,25.27796424 +2023-08-20 22:00:00,24088.0,24129.0,24070.0,24103.0,2.95380684 +2023-08-21 00:00:00,24095.0,24104.0,24002.0,24056.0,8.37173735 +2023-08-21 02:00:00,24057.0,24064.0,23956.0,23980.0,9.6041325 +2023-08-21 04:00:00,23990.0,24061.0,23932.0,24001.0,8.45687041 +2023-08-21 06:00:00,24000.0,24029.0,23875.0,23905.0,20.28475112 +2023-08-21 08:00:00,23900.0,23961.0,23846.0,23892.0,24.30384102 +2023-08-21 10:00:00,23883.0,23884.0,23750.0,23867.0,44.30580782 +2023-08-21 12:00:00,23867.0,24000.0,23846.0,24000.0,19.74773932 +2023-08-21 14:00:00,23995.0,24064.0,23750.0,23814.0,43.75153489 +2023-08-21 16:00:00,23817.0,23936.0,23817.0,23916.0,13.67438893 +2023-08-21 18:00:00,23915.0,24019.0,23883.0,23954.0,15.86449286 +2023-08-21 20:00:00,23969.0,24100.0,23936.0,24052.0,13.41995403 +2023-08-21 22:00:00,24050.0,24050.0,23969.0,23974.0,7.36505851 +2023-08-22 00:00:00,23991.0,24006.0,23900.0,23900.0,2.86573127 +2023-08-22 02:00:00,23900.0,23907.0,23850.0,23887.0,1.15842724 +2023-08-22 04:00:00,23883.0,23894.0,23835.0,23886.0,5.69517819 +2023-08-22 06:00:00,23886.0,23897.0,23831.0,23895.0,33.11422674 +2023-08-22 08:00:00,23894.0,23926.0,23864.0,23906.0,25.41305583 +2023-08-22 10:00:00,23906.0,23962.0,23877.0,23939.0,20.29695094 +2023-08-22 12:00:00,23934.0,24017.0,23919.0,23985.0,20.33176799 +2023-08-22 14:00:00,23983.0,24015.0,23899.0,23899.0,17.34920014 +2023-08-22 16:00:00,23911.0,24021.0,23700.0,23791.0,29.64249108 +2023-08-22 18:00:00,23800.0,23938.0,23741.0,23765.0,21.13878024 +2023-08-22 20:00:00,23758.0,23881.0,23405.0,23672.0,66.01098849 +2023-08-22 22:00:00,23672.0,24011.0,23630.0,24011.0,18.25363794 +2023-08-23 00:00:00,24011.0,24110.0,23949.0,23999.0,6.583319 +2023-08-23 02:00:00,24003.0,24027.0,23925.0,23949.0,1.63748762 +2023-08-23 04:00:00,23932.0,24005.0,23919.0,23976.0,13.44906796 +2023-08-23 06:00:00,23976.0,24111.0,23958.0,24064.0,27.85323509 +2023-08-23 08:00:00,24067.0,24099.0,24034.0,24089.0,19.490984 +2023-08-23 10:00:00,24090.0,24090.0,23955.0,23993.0,25.08243979 +2023-08-23 12:00:00,23998.0,24034.0,23850.0,24010.0,12.77607415 +2023-08-23 14:00:00,24008.0,24104.0,23900.0,24054.0,31.54713067 +2023-08-23 16:00:00,24077.0,24496.0,24046.0,24447.0,67.83115464 +2023-08-23 18:00:00,24455.0,24688.0,24338.0,24527.0,44.52148545 +2023-08-23 20:00:00,24525.0,24615.0,24132.0,24259.0,47.93748448 +2023-08-23 22:00:00,24225.0,24420.0,24225.0,24322.0,10.16432962 +2023-08-24 00:00:00,24325.0,24414.0,24267.0,24280.0,1.21721007 +2023-08-24 02:00:00,24270.0,24354.0,24266.0,24335.0,4.28426731 +2023-08-24 04:00:00,24317.0,24381.0,24302.0,24320.0,10.32475652 +2023-08-24 06:00:00,24324.0,24431.0,24277.0,24411.0,15.35616811 +2023-08-24 08:00:00,24395.0,24462.0,24323.0,24377.0,18.77086689 +2023-08-24 10:00:00,24379.0,24449.0,24333.0,24372.0,14.06381659 +2023-08-24 12:00:00,24372.0,24415.0,24250.0,24298.0,19.39182716 +2023-08-24 14:00:00,24293.0,24312.0,24000.0,24000.0,44.34871231 +2023-08-24 16:00:00,24000.0,24167.0,23950.0,24090.0,18.66070099 +2023-08-24 18:00:00,24077.0,24170.0,24018.0,24071.0,15.94529779 +2023-08-24 20:00:00,24102.0,24152.0,23985.0,24106.0,14.61685989 +2023-08-24 22:00:00,24134.0,24252.0,24111.0,24223.0,11.7917264 +2023-08-25 00:00:00,24240.0,24240.0,24168.0,24218.0,1.71205273 +2023-08-25 02:00:00,24234.0,24264.0,24150.0,24205.0,5.16681822 +2023-08-25 04:00:00,24212.0,24220.0,24119.0,24147.0,6.0154303 +2023-08-25 06:00:00,24134.0,24170.0,24084.0,24094.0,16.75965195 +2023-08-25 08:00:00,24104.0,24218.0,24104.0,24160.0,15.70050065 +2023-08-25 10:00:00,24159.0,24184.0,24123.0,24155.0,12.89796448 +2023-08-25 12:00:00,24155.0,24249.0,24101.0,24105.0,16.19639204 +2023-08-25 14:00:00,24105.0,24269.0,23938.0,24049.0,45.22015512 +2023-08-25 16:00:00,24057.0,24108.0,23932.0,23981.0,18.31883295 +2023-08-25 18:00:00,23952.0,24117.0,23952.0,24048.0,8.45968179 +2023-08-25 20:00:00,24043.0,24161.0,24018.0,24161.0,16.3204882 +2023-08-25 22:00:00,24139.0,24162.0,24104.0,24148.0,6.94269874 +2023-08-26 00:00:00,24132.0,24162.0,24108.0,24129.0,1.0207855 +2023-08-26 02:00:00,24132.0,24170.0,24113.0,24166.0,1.39407073 +2023-08-26 04:00:00,24160.0,24160.0,24121.0,24143.0,3.07841485 +2023-08-26 06:00:00,24143.0,24170.0,24121.0,24126.0,5.04016944 +2023-08-26 08:00:00,24140.0,24151.0,24078.0,24082.0,14.9636503 +2023-08-26 10:00:00,24081.0,24140.0,24077.0,24137.0,8.46024661 +2023-08-26 12:00:00,24137.0,24138.0,24068.0,24135.0,10.91015731 +2023-08-26 14:00:00,24136.0,24140.0,24104.0,24119.0,6.19680329 +2023-08-26 16:00:00,24138.0,24152.0,24090.0,24126.0,8.43685111 +2023-08-26 18:00:00,24111.0,24126.0,24081.0,24121.0,8.79518846 +2023-08-26 20:00:00,24121.0,24134.0,24095.0,24133.0,6.77933174 +2023-08-26 22:00:00,24131.0,24135.0,24077.0,24111.0,3.58886702 +2023-08-27 00:00:00,24100.0,24122.0,24046.0,24080.0,0.83949737 +2023-08-27 02:00:00,24088.0,24100.0,24066.0,24090.0,0.35094701 +2023-08-27 04:00:00,24095.0,24127.0,24090.0,24120.0,0.83465367 +2023-08-27 06:00:00,24120.0,24138.0,24099.0,24113.0,2.75541308 +2023-08-27 08:00:00,24133.0,24161.0,24112.0,24149.0,5.01384222 +2023-08-27 10:00:00,24149.0,24189.0,24138.0,24158.0,9.11907036 +2023-08-27 12:00:00,24158.0,24173.0,24135.0,24168.0,5.75179939 +2023-08-27 14:00:00,24152.0,24249.0,24150.0,24211.0,12.73987308 +2023-08-27 16:00:00,24211.0,24267.0,24138.0,24162.0,9.86306558 +2023-08-27 18:00:00,24164.0,24250.0,24126.0,24200.0,12.98353841 +2023-08-27 20:00:00,24213.0,24215.0,24134.0,24135.0,13.76706368 +2023-08-27 22:00:00,24153.0,24184.0,24108.0,24171.0,3.69317902 +2023-08-28 00:00:00,24160.0,24172.0,24075.0,24091.0,1.88606575 +2023-08-28 02:00:00,24095.0,24117.0,24057.0,24067.0,1.43958369 +2023-08-28 04:00:00,24057.0,24089.0,23952.0,24008.0,14.36948461 +2023-08-28 06:00:00,24017.0,24039.0,23929.0,23994.0,18.68356157 +2023-08-28 08:00:00,23995.0,24048.0,23953.0,23987.0,13.34833885 +2023-08-28 10:00:00,23989.0,24055.0,23944.0,24055.0,15.87503772 +2023-08-28 12:00:00,24058.0,24270.0,24030.0,24130.0,24.0023644 +2023-08-28 14:00:00,24138.0,24200.0,24097.0,24115.0,15.88764858 +2023-08-28 16:00:00,24132.0,24213.0,24120.0,24167.0,11.11314755 +2023-08-28 18:00:00,24170.0,24180.0,23963.0,24009.0,17.20319938 +2023-08-28 20:00:00,24011.0,24040.0,23970.0,23999.0,9.18315861 +2023-08-28 22:00:00,23998.0,24147.0,23973.0,24091.0,3.14823165 +2023-08-29 00:00:00,24107.0,24151.0,24060.0,24069.0,0.73674363 +2023-08-29 02:00:00,24060.0,24081.0,24034.0,24048.0,1.0442257 +2023-08-29 04:00:00,24035.0,24086.0,24025.0,24047.0,6.98819872 +2023-08-29 06:00:00,24059.0,24062.0,23981.0,24018.0,15.59630793 +2023-08-29 08:00:00,23999.0,24043.0,23976.0,24020.0,15.35716286 +2023-08-29 10:00:00,24005.0,24077.0,23970.0,24029.0,16.08268949 +2023-08-29 12:00:00,24024.0,24149.0,24009.0,24106.0,15.19492164 +2023-08-29 14:00:00,24104.0,25547.0,24085.0,25262.0,292.68913593 +2023-08-29 16:00:00,25284.0,25914.0,25192.0,25649.0,194.9813206 +2023-08-29 18:00:00,25655.0,25782.0,25547.0,25564.0,66.94584767 +2023-08-29 20:00:00,25551.0,25612.0,25311.0,25410.0,60.07777423 +2023-08-29 22:00:00,25426.0,25525.0,25291.0,25497.0,7.07337816 +2023-08-30 00:00:00,25488.0,25533.0,25279.0,25352.0,3.18840172 +2023-08-30 02:00:00,25349.0,25349.0,25088.0,25201.0,6.36899018 +2023-08-30 04:00:00,25203.0,25282.0,25185.0,25277.0,18.01167195 +2023-08-30 06:00:00,25272.0,25272.0,25167.0,25252.0,16.89864746 +2023-08-30 08:00:00,25252.0,25305.0,25087.0,25168.0,36.04767039 +2023-08-30 10:00:00,25181.0,25219.0,25102.0,25111.0,19.35492604 +2023-08-30 12:00:00,25102.0,25167.0,24873.0,25024.0,42.34172967 +2023-08-30 14:00:00,25026.0,25084.0,24731.0,24883.0,59.95113958 +2023-08-30 16:00:00,24894.0,24927.0,24780.0,24885.0,25.6799484 +2023-08-30 18:00:00,24877.0,24977.0,24804.0,24876.0,16.6944645 +2023-08-30 20:00:00,24887.0,25027.0,24884.0,24936.0,24.48234635 +2023-08-30 22:00:00,24958.0,24999.0,24914.0,24957.0,3.11026528 +2023-08-31 00:00:00,24959.0,24968.0,24862.0,24885.0,1.95872771 +2023-08-31 02:00:00,24888.0,24921.0,24874.0,24905.0,0.89434082 +2023-08-31 04:00:00,24922.0,24981.0,24902.0,24959.0,9.35687562 +2023-08-31 06:00:00,24965.0,25056.0,24945.0,25026.0,22.72946377 +2023-08-31 08:00:00,25027.0,25047.0,24997.0,24999.0,13.38776937 +2023-08-31 10:00:00,24999.0,25349.0,24992.0,25126.0,30.69894386 +2023-08-31 12:00:00,25128.0,25129.0,24922.0,25025.0,34.7990573 +2023-08-31 14:00:00,25024.0,25069.0,24732.0,24847.0,18.35125905 +2023-08-31 16:00:00,24824.0,24854.0,24057.0,24271.0,127.61134133 +2023-08-31 18:00:00,24249.0,24305.0,23980.0,24143.0,78.37037182 +2023-08-31 20:00:00,24120.0,24161.0,23657.0,24012.0,77.61381941 +2023-08-31 22:00:00,24012.0,24049.0,23909.0,23928.0,13.01389628 +2023-09-01 00:00:00,23935.0,24049.0,23923.0,23958.0,4.05223808 +2023-09-01 02:00:00,23956.0,24066.0,23956.0,24055.0,2.80479026 +2023-09-01 04:00:00,24060.0,24071.0,23981.0,23983.0,10.55876711 +2023-09-01 06:00:00,24000.0,24027.0,23920.0,23935.0,25.40992168 +2023-09-01 08:00:00,23943.0,24001.0,23913.0,23983.0,17.24465403 +2023-09-01 10:00:00,23997.0,24049.0,23946.0,24040.0,15.56286417 +2023-09-01 12:00:00,24039.0,24111.0,23833.0,23939.0,32.35283674 +2023-09-01 14:00:00,23939.0,24014.0,23670.0,23902.0,39.91660154 +2023-09-01 16:00:00,23922.0,24056.0,23500.0,23616.0,47.96691028 +2023-09-01 18:00:00,23614.0,23929.0,23584.0,23788.0,27.56430782 +2023-09-01 20:00:00,23789.0,24018.0,23708.0,23944.0,39.30216413 +2023-09-01 22:00:00,23949.0,23977.0,23911.0,23954.0,4.98257743 +2023-09-02 00:00:00,23957.0,23981.0,23915.0,23930.0,1.8647907 +2023-09-02 02:00:00,23926.0,23946.0,23895.0,23932.0,0.56859801 +2023-09-02 04:00:00,23943.0,23986.0,23903.0,23969.0,3.84627363 +2023-09-02 06:00:00,23969.0,23977.0,23918.0,23950.0,17.0304858 +2023-09-02 08:00:00,23954.0,23975.0,23914.0,23962.0,17.92981766 +2023-09-02 10:00:00,23963.0,24012.0,23938.0,23972.0,15.71911133 +2023-09-02 12:00:00,23972.0,24000.0,23931.0,23986.0,12.4819306 +2023-09-02 14:00:00,23986.0,24096.0,23951.0,24040.0,26.4307919 +2023-09-02 16:00:00,24042.0,24084.0,23950.0,23967.0,13.63840467 +2023-09-02 18:00:00,23969.0,23999.0,23906.0,23986.0,10.07683699 +2023-09-02 20:00:00,23984.0,24037.0,23962.0,24017.0,7.78774365 +2023-09-02 22:00:00,24014.0,24053.0,23990.0,24003.0,2.75251573 +2023-09-03 00:00:00,24002.0,24036.0,23980.0,24011.0,2.1071115 +2023-09-03 02:00:00,24010.0,24027.0,23992.0,23999.0,1.58083141 +2023-09-03 04:00:00,24009.0,24060.0,24004.0,24039.0,1.86973574 +2023-09-03 06:00:00,24054.0,24098.0,24036.0,24097.0,5.99856099 +2023-09-03 08:00:00,24100.0,24100.0,24020.0,24040.0,9.98196647 +2023-09-03 10:00:00,24060.0,24088.0,24032.0,24075.0,9.95202916 +2023-09-03 12:00:00,24075.0,24200.0,23956.0,24028.0,39.84783225 +2023-09-03 14:00:00,24020.0,24073.0,23975.0,24005.0,12.46210534 +2023-09-03 16:00:00,24005.0,24032.0,23930.0,24027.0,14.05191647 +2023-09-03 18:00:00,24021.0,24155.0,24003.0,24122.0,18.86899761 +2023-09-03 20:00:00,24122.0,24237.0,24073.0,24099.0,11.34726032 +2023-09-03 22:00:00,24079.0,24112.0,24059.0,24083.0,3.94186447 +2023-09-04 00:00:00,24103.0,24103.0,24000.0,24016.0,0.50049948 +2023-09-04 02:00:00,24042.0,24186.0,24001.0,24095.0,1.37598145 +2023-09-04 04:00:00,24095.0,24124.0,24034.0,24052.0,3.547968 +2023-09-04 06:00:00,24047.0,24080.0,24019.0,24044.0,6.81742801 +2023-09-04 08:00:00,24045.0,24080.0,23992.0,24034.0,9.45747296 +2023-09-04 10:00:00,24035.0,24048.0,23930.0,23954.0,23.7628153 +2023-09-04 12:00:00,23966.0,23993.0,23905.0,23966.0,39.00183319 +2023-09-04 14:00:00,23954.0,24047.0,23847.0,23888.0,14.79750196 +2023-09-04 16:00:00,23904.0,24018.0,23892.0,23991.0,11.27417735 +2023-09-04 18:00:00,23978.0,24021.0,23928.0,23983.0,13.09313458 +2023-09-04 20:00:00,23985.0,24004.0,23750.0,23766.0,15.71821891 +2023-09-04 22:00:00,23787.0,23948.0,23750.0,23925.0,6.53497505 +2023-09-05 00:00:00,23925.0,23935.0,23829.0,23864.0,0.77807724 +2023-09-05 02:00:00,23864.0,23872.0,23707.0,23805.0,3.58392856 +2023-09-05 04:00:00,23807.0,23863.0,23778.0,23852.0,7.26235768 +2023-09-05 06:00:00,23859.0,23910.0,23831.0,23909.0,7.82174414 +2023-09-05 08:00:00,23907.0,23970.0,23832.0,23926.0,10.69989842 +2023-09-05 10:00:00,23937.0,23998.0,23932.0,23998.0,12.2011374 +2023-09-05 12:00:00,23999.0,24037.0,23928.0,23980.0,16.47155658 +2023-09-05 14:00:00,23979.0,24147.0,23908.0,23983.0,16.78122335 +2023-09-05 16:00:00,24000.0,24084.0,23942.0,24000.0,12.58746306 +2023-09-05 18:00:00,24007.0,24025.0,23932.0,23932.0,27.47150103 +2023-09-05 20:00:00,23930.0,24012.0,23869.0,23986.0,29.21582312 +2023-09-05 22:00:00,23975.0,24043.0,23963.0,24035.0,3.26686612 +2023-09-06 00:00:00,24043.0,24067.0,24017.0,24039.0,1.60888268 +2023-09-06 02:00:00,24043.0,24071.0,23990.0,24001.0,0.60219988 +2023-09-06 04:00:00,23993.0,24006.0,23945.0,23963.0,7.40377393 +2023-09-06 06:00:00,23962.0,24008.0,23950.0,23963.0,7.45733398 +2023-09-06 08:00:00,23966.0,23997.0,23944.0,23980.0,7.86046118 +2023-09-06 10:00:00,23963.0,23988.0,23914.0,23945.0,10.7954477 +2023-09-06 12:00:00,23931.0,23994.0,23899.0,23966.0,14.61418071 +2023-09-06 14:00:00,23965.0,23997.0,23851.0,23873.0,25.88485671 +2023-09-06 16:00:00,23871.0,24250.0,23707.0,24106.0,35.02305242 +2023-09-06 18:00:00,24105.0,24186.0,23838.0,23941.0,36.50322897 +2023-09-06 20:00:00,23930.0,24022.0,23911.0,23985.0,10.50128448 +2023-09-06 22:00:00,23991.0,24037.0,23976.0,24011.0,2.70414189 +2023-09-07 00:00:00,24012.0,24031.0,23985.0,24003.0,0.13399509 +2023-09-07 02:00:00,23996.0,24079.0,23978.0,24078.0,2.01927308 +2023-09-07 04:00:00,24078.0,24089.0,24034.0,24066.0,6.22228885 +2023-09-07 06:00:00,24061.0,24067.0,24013.0,24042.0,10.19970446 +2023-09-07 08:00:00,24022.0,24041.0,23996.0,24011.0,8.33476796 +2023-09-07 10:00:00,24016.0,24037.0,23972.0,23999.0,15.21657178 +2023-09-07 12:00:00,23997.0,24048.0,23947.0,23966.0,9.31259806 +2023-09-07 14:00:00,23940.0,24127.0,23936.0,24054.0,11.01155667 +2023-09-07 16:00:00,24067.0,24235.0,24048.0,24204.0,35.45514048 +2023-09-07 18:00:00,24221.0,24235.0,24130.0,24184.0,20.50319888 +2023-09-07 20:00:00,24179.0,24692.0,24145.0,24451.0,79.06711932 +2023-09-07 22:00:00,24492.0,24699.0,24425.0,24529.0,20.10602449 +2023-09-08 00:00:00,24535.0,24656.0,24484.0,24493.0,11.48007211 +2023-09-08 02:00:00,24480.0,24515.0,24444.0,24479.0,2.12093082 +2023-09-08 04:00:00,24477.0,24627.0,24448.0,24460.0,21.54488764 +2023-09-08 06:00:00,24460.0,24537.0,24417.0,24513.0,18.59988222 +2023-09-08 08:00:00,24501.0,24518.0,24305.0,24316.0,26.93743194 +2023-09-08 10:00:00,24300.0,24300.0,23982.0,24134.0,42.88018935 +2023-09-08 12:00:00,24142.0,24200.0,24091.0,24138.0,18.26240545 +2023-09-08 14:00:00,24130.0,24181.0,24084.0,24137.0,12.81981149 +2023-09-08 16:00:00,24126.0,24159.0,24035.0,24133.0,12.90275105 +2023-09-08 18:00:00,24113.0,24205.0,24067.0,24201.0,8.07906363 +2023-09-08 20:00:00,24208.0,24228.0,24141.0,24211.0,9.94395384 +2023-09-08 22:00:00,24207.0,24243.0,24193.0,24225.0,6.06757741 +2023-09-09 00:00:00,24225.0,24225.0,24161.0,24186.0,1.15562423 +2023-09-09 02:00:00,24193.0,24201.0,24152.0,24171.0,1.34190547 +2023-09-09 04:00:00,24190.0,24202.0,24139.0,24152.0,3.52800516 +2023-09-09 06:00:00,24152.0,24215.0,24144.0,24204.0,8.2780623 +2023-09-09 08:00:00,24205.0,24212.0,24168.0,24181.0,7.52793262 +2023-09-09 10:00:00,24199.0,24203.0,24154.0,24182.0,7.10362621 +2023-09-09 12:00:00,24184.0,24185.0,24125.0,24129.0,8.44437446 +2023-09-09 14:00:00,24147.0,24233.0,24129.0,24196.0,4.59243386 +2023-09-09 16:00:00,24215.0,24250.0,24178.0,24181.0,7.18191877 +2023-09-09 18:00:00,24196.0,24202.0,24158.0,24196.0,2.37953121 +2023-09-09 20:00:00,24196.0,24211.0,24164.0,24189.0,4.53834463 +2023-09-09 22:00:00,24201.0,24231.0,24183.0,24202.0,2.71420424 +2023-09-10 00:00:00,24218.0,24219.0,24152.0,24168.0,0.81396993 +2023-09-10 02:00:00,24173.0,24188.0,24152.0,24187.0,0.73702925 +2023-09-10 04:00:00,24167.0,24182.0,24100.0,24158.0,4.88391425 +2023-09-10 06:00:00,24174.0,24201.0,24155.0,24174.0,5.55518418 +2023-09-10 08:00:00,24189.0,24199.0,24143.0,24143.0,6.89536216 +2023-09-10 10:00:00,24155.0,24163.0,24111.0,24111.0,9.61235852 +2023-09-10 12:00:00,24111.0,24157.0,24095.0,24124.0,9.23443939 +2023-09-10 14:00:00,24123.0,24154.0,24047.0,24104.0,10.78298389 +2023-09-10 16:00:00,24103.0,24123.0,24005.0,24013.0,9.63828146 +2023-09-10 18:00:00,24019.0,24165.0,23950.0,24129.0,10.10189627 +2023-09-10 20:00:00,24125.0,24197.0,24074.0,24176.0,19.67990015 +2023-09-10 22:00:00,24177.0,24271.0,24093.0,24102.0,4.09739647 +2023-09-11 00:00:00,24117.0,24160.0,23961.0,23969.0,2.41064117 +2023-09-11 02:00:00,23970.0,24026.0,23950.0,24011.0,5.69455884 +2023-09-11 04:00:00,24012.0,24111.0,23975.0,24111.0,5.1361584 +2023-09-11 06:00:00,24142.0,24144.0,24017.0,24065.0,9.4336187 +2023-09-11 08:00:00,24067.0,24083.0,23944.0,23985.0,22.12323343 +2023-09-11 10:00:00,23980.0,23991.0,23855.0,23882.0,27.57016866 +2023-09-11 12:00:00,23875.0,23993.0,23850.0,23850.0,16.65938193 +2023-09-11 14:00:00,23857.0,24380.0,23265.0,23383.0,161.95297966 +2023-09-11 16:00:00,23377.0,23479.0,23342.0,23476.0,49.33127092 +2023-09-11 18:00:00,23467.0,23480.0,23243.0,23279.0,40.23323987 +2023-09-11 20:00:00,23281.0,23454.0,23200.0,23399.0,31.20140971 +2023-09-11 22:00:00,23395.0,23437.0,23351.0,23429.0,6.20564259 +2023-09-12 00:00:00,23403.0,23480.0,23400.0,23423.0,6.97544813 +2023-09-12 02:00:00,23417.0,24140.0,23413.0,23998.0,28.1248866 +2023-09-12 04:00:00,24000.0,24160.0,23840.0,23999.0,24.60194075 +2023-09-12 06:00:00,24002.0,24123.0,23950.0,24099.0,31.11915623 +2023-09-12 08:00:00,24100.0,24133.0,24000.0,24110.0,19.37291549 +2023-09-12 10:00:00,24115.0,24490.0,24084.0,24342.0,68.44187261 +2023-09-12 12:00:00,24338.0,24550.0,24292.0,24525.0,41.24391061 +2023-09-12 14:00:00,24516.0,24600.0,24312.0,24422.0,37.85315848 +2023-09-12 16:00:00,24430.0,24738.0,24154.0,24160.0,75.98567701 +2023-09-12 18:00:00,24150.0,24477.0,24121.0,24306.0,24.83029096 +2023-09-12 20:00:00,24300.0,24345.0,24228.0,24265.0,12.96438083 +2023-09-12 22:00:00,24271.0,24271.0,24004.0,24027.0,8.15012799 +2023-09-13 00:00:00,24028.0,24129.0,23963.0,24126.0,3.59103138 +2023-09-13 02:00:00,24124.0,24156.0,24044.0,24065.0,3.96011345 +2023-09-13 04:00:00,24073.0,24148.0,24047.0,24114.0,8.23898919 +2023-09-13 06:00:00,24119.0,24298.0,24061.0,24069.0,16.29704612 +2023-09-13 08:00:00,24087.0,24415.0,24067.0,24372.0,16.28942065 +2023-09-13 10:00:00,24371.0,24437.0,24298.0,24404.0,23.32149132 +2023-09-13 12:00:00,24414.0,24456.0,24271.0,24338.0,30.54528061 +2023-09-13 14:00:00,24345.0,24560.0,24298.0,24461.0,21.37715537 +2023-09-13 16:00:00,24461.0,24583.0,24286.0,24316.0,35.41423953 +2023-09-13 18:00:00,24293.0,24436.0,24288.0,24376.0,16.49445965 +2023-09-13 20:00:00,24376.0,24490.0,24367.0,24460.0,18.19209656 +2023-09-13 22:00:00,24462.0,24508.0,24413.0,24444.0,6.4871395 +2023-09-14 00:00:00,24425.0,24695.0,24342.0,24390.0,19.08565758 +2023-09-14 02:00:00,24392.0,24488.0,24376.0,24439.0,3.95488377 +2023-09-14 04:00:00,24460.0,24464.0,24337.0,24365.0,5.6084868 +2023-09-14 06:00:00,24376.0,24563.0,24361.0,24526.0,20.56012884 +2023-09-14 08:00:00,24539.0,24544.0,24463.0,24503.0,13.8305216 +2023-09-14 10:00:00,24486.0,24664.0,24480.0,24657.0,27.86891068 +2023-09-14 12:00:00,24634.0,25071.0,24621.0,24915.0,118.29196521 +2023-09-14 14:00:00,24939.0,25114.0,24882.0,25048.0,64.44804964 +2023-09-14 16:00:00,25034.0,25073.0,24915.0,25055.0,27.95904402 +2023-09-14 18:00:00,25041.0,25231.0,24963.0,25049.0,42.19352057 +2023-09-14 20:00:00,25050.0,25076.0,24874.0,24910.0,26.58853066 +2023-09-14 22:00:00,24928.0,25027.0,24891.0,24930.0,10.28260723 +2023-09-15 00:00:00,24932.0,24961.0,24863.0,24901.0,4.26347889 +2023-09-15 02:00:00,24917.0,25006.0,24917.0,24979.0,5.98869551 +2023-09-15 04:00:00,25008.0,25040.0,24937.0,24962.0,18.3502586 +2023-09-15 06:00:00,24954.0,24965.0,24894.0,24900.0,32.78143934 +2023-09-15 08:00:00,24918.0,24999.0,24888.0,24964.0,17.97639007 +2023-09-15 10:00:00,24961.0,25000.0,24769.0,24789.0,19.93717942 +2023-09-15 12:00:00,24789.0,24874.0,24736.0,24742.0,27.4402703 +2023-09-15 14:00:00,24736.0,24747.0,24585.0,24670.0,33.5760456 +2023-09-15 16:00:00,24666.0,24743.0,24641.0,24697.0,13.70049537 +2023-09-15 18:00:00,24692.0,24821.0,24677.0,24759.0,18.50212269 +2023-09-15 20:00:00,24776.0,24870.0,24750.0,24849.0,14.36364557 +2023-09-15 22:00:00,24848.0,25191.0,24833.0,24950.0,22.08814731 +2023-09-16 00:00:00,24938.0,25016.0,24918.0,24973.0,2.33569647 +2023-09-16 02:00:00,24999.0,25100.0,24954.0,24965.0,4.2828931 +2023-09-16 04:00:00,24955.0,24959.0,24859.0,24888.0,8.01055572 +2023-09-16 06:00:00,24880.0,24880.0,24800.0,24827.0,14.71432362 +2023-09-16 08:00:00,24846.0,24929.0,24809.0,24864.0,9.62660506 +2023-09-16 10:00:00,24858.0,24901.0,24816.0,24869.0,11.14517685 +2023-09-16 12:00:00,24869.0,24925.0,24839.0,24904.0,7.72147964 +2023-09-16 14:00:00,24907.0,24915.0,24829.0,24867.0,5.09981397 +2023-09-16 16:00:00,24844.0,24948.0,24833.0,24918.0,9.44421662 +2023-09-16 18:00:00,24900.0,24963.0,24855.0,24891.0,6.14145228 +2023-09-16 20:00:00,24887.0,24932.0,24864.0,24905.0,4.70840657 +2023-09-16 22:00:00,24902.0,24931.0,24855.0,24911.0,2.79514966 +2023-09-17 00:00:00,24910.0,24911.0,24785.0,24867.0,4.1704548 +2023-09-17 02:00:00,24851.0,24890.0,24829.0,24861.0,12.44759192 +2023-09-17 04:00:00,24850.0,24890.0,24842.0,24874.0,1.99955393 +2023-09-17 06:00:00,24874.0,24886.0,24834.0,24848.0,5.73393918 +2023-09-17 08:00:00,24848.0,24926.0,24828.0,24925.0,8.12670253 +2023-09-17 10:00:00,24925.0,24950.0,24891.0,24908.0,7.61996291 +2023-09-17 12:00:00,24908.0,24921.0,24857.0,24878.0,4.16680135 +2023-09-17 14:00:00,24881.0,24937.0,24861.0,24897.0,8.43441927 +2023-09-17 16:00:00,24889.0,24898.0,24824.0,24824.0,5.61174653 +2023-09-17 18:00:00,24832.0,24864.0,24804.0,24859.0,8.1276133 +2023-09-17 20:00:00,24850.0,24864.0,24751.0,24842.0,15.76492795 +2023-09-17 22:00:00,24843.0,24866.0,24801.0,24866.0,2.31610654 +2023-09-18 00:00:00,24862.0,24895.0,24750.0,24824.0,1.34529078 +2023-09-18 02:00:00,24826.0,25069.0,24826.0,25003.0,10.24674221 +2023-09-18 04:00:00,25012.0,25026.0,24899.0,24991.0,13.46670282 +2023-09-18 06:00:00,24991.0,25112.0,24958.0,25036.0,24.00315105 +2023-09-18 08:00:00,25044.0,25245.0,25008.0,25179.0,29.60226518 +2023-09-18 10:00:00,25190.0,25528.0,25190.0,25486.0,73.32242681 +2023-09-18 12:00:00,25500.0,25712.0,25458.0,25558.0,75.43467435 +2023-09-18 14:00:00,25552.0,25591.0,25441.0,25484.0,44.39936755 +2023-09-18 16:00:00,25485.0,25546.0,24945.0,25051.0,62.76007493 +2023-09-18 18:00:00,25046.0,25231.0,24927.0,25103.0,46.7174959 +2023-09-18 20:00:00,25114.0,25123.0,25004.0,25107.0,15.72043802 +2023-09-18 22:00:00,25110.0,25143.0,24995.0,25028.0,6.01350142 +2023-09-19 00:00:00,25037.0,25047.0,24962.0,24985.0,1.4719712 +2023-09-19 02:00:00,24993.0,25113.0,24988.0,25106.0,6.59201736 +2023-09-19 04:00:00,25106.0,25150.0,25086.0,25086.0,12.00427695 +2023-09-19 06:00:00,25096.0,25166.0,25049.0,25119.0,12.80165886 +2023-09-19 08:00:00,25108.0,25692.0,25108.0,25530.0,55.62210521 +2023-09-19 10:00:00,25540.0,25556.0,25298.0,25437.0,33.31575791 +2023-09-19 12:00:00,25422.0,25473.0,25200.0,25238.0,28.98537545 +2023-09-19 14:00:00,25224.0,25745.0,25150.0,25648.0,56.07875077 +2023-09-19 16:00:00,25695.0,25722.0,25380.0,25410.0,43.16966647 +2023-09-19 18:00:00,25417.0,25484.0,25360.0,25448.0,13.57449503 +2023-09-19 20:00:00,25464.0,25487.0,25300.0,25434.0,15.9840507 +2023-09-19 22:00:00,25426.0,25499.0,25383.0,25466.0,4.53757992 +2023-09-20 00:00:00,25466.0,25588.0,25409.0,25586.0,4.19682008 +2023-09-20 02:00:00,25579.0,25630.0,25371.0,25400.0,2.93908732 +2023-09-20 04:00:00,25380.0,25443.0,25300.0,25312.0,5.50032858 +2023-09-20 06:00:00,25312.0,25387.0,25242.0,25363.0,32.62309487 +2023-09-20 08:00:00,25363.0,25441.0,25225.0,25304.0,16.39608912 +2023-09-20 10:00:00,25272.0,25373.0,25186.0,25310.0,28.52065891 +2023-09-20 12:00:00,25328.0,25391.0,25236.0,25354.0,14.77801616 +2023-09-20 14:00:00,25355.0,25389.0,25247.0,25362.0,20.59971127 +2023-09-20 16:00:00,25370.0,25422.0,25278.0,25398.0,17.00891273 +2023-09-20 18:00:00,25387.0,25509.0,25150.0,25268.0,55.34689586 +2023-09-20 20:00:00,25269.0,25550.0,25246.0,25414.0,15.48762628 +2023-09-20 22:00:00,25422.0,25496.0,25365.0,25473.0,1.61911076 +2023-09-21 00:00:00,25472.0,25535.0,25367.0,25399.0,1.12971125 +2023-09-21 02:00:00,25417.0,25432.0,25323.0,25422.0,0.93350854 +2023-09-21 04:00:00,25397.0,25493.0,25370.0,25464.0,6.98303345 +2023-09-21 06:00:00,25444.0,25462.0,25314.0,25318.0,6.45242643 +2023-09-21 08:00:00,25325.0,25358.0,25032.0,25102.0,46.53139191 +2023-09-21 10:00:00,25096.0,25165.0,25018.0,25138.0,25.46804859 +2023-09-21 12:00:00,25130.0,25182.0,24761.0,24838.0,43.8950492 +2023-09-21 14:00:00,24812.0,24990.0,24777.0,24930.0,32.89541552 +2023-09-21 16:00:00,24932.0,25039.0,24895.0,24996.0,19.13081096 +2023-09-21 18:00:00,24994.0,25019.0,24900.0,24960.0,13.97210117 +2023-09-21 20:00:00,24950.0,24989.0,24864.0,24965.0,15.45495128 +2023-09-21 22:00:00,24966.0,24977.0,24895.0,24933.0,2.1643403 +2023-09-22 00:00:00,24924.0,25051.0,24865.0,25010.0,1.81097429 +2023-09-22 02:00:00,25034.0,25041.0,24927.0,25004.0,5.46249943 +2023-09-22 04:00:00,25012.0,25035.0,24966.0,25035.0,7.04727049 +2023-09-22 06:00:00,25043.0,25068.0,24945.0,25031.0,21.414659 +2023-09-22 08:00:00,25049.0,25128.0,25025.0,25049.0,23.76793538 +2023-09-22 10:00:00,25046.0,25062.0,24980.0,25047.0,12.26208661 +2023-09-22 12:00:00,25053.0,25054.0,24914.0,24967.0,13.35949224 +2023-09-22 14:00:00,24960.0,25044.0,24929.0,24992.0,22.81479283 +2023-09-22 16:00:00,24974.0,25008.0,24897.0,24954.0,15.92688436 +2023-09-22 18:00:00,24935.0,25014.0,24911.0,24930.0,12.62875332 +2023-09-22 20:00:00,24919.0,24965.0,24866.0,24956.0,10.08307272 +2023-09-22 22:00:00,24958.0,24981.0,24927.0,24968.0,1.53361975 +2023-09-23 00:00:00,24969.0,24995.0,24938.0,24974.0,1.88581142 +2023-09-23 02:00:00,24972.0,24973.0,24910.0,24931.0,1.08755771 +2023-09-23 04:00:00,24926.0,24955.0,24904.0,24943.0,2.652144 +2023-09-23 06:00:00,24943.0,24983.0,24922.0,24979.0,15.03980423 +2023-09-23 08:00:00,24982.0,24988.0,24936.0,24974.0,5.8641851 +2023-09-23 10:00:00,24978.0,24984.0,24940.0,24977.0,6.73410497 +2023-09-23 12:00:00,24979.0,24988.0,24943.0,24981.0,5.44690446 +2023-09-23 14:00:00,24976.0,24992.0,24942.0,24991.0,5.26756904 +2023-09-23 16:00:00,24987.0,25016.0,24947.0,25010.0,2.97558987 +2023-09-23 18:00:00,25010.0,25040.0,24994.0,25019.0,7.10686533 +2023-09-23 20:00:00,24998.0,25021.0,24960.0,24962.0,1.91353742 +2023-09-23 22:00:00,24982.0,24993.0,24953.0,24991.0,2.09819844 +2023-09-24 00:00:00,24990.0,25000.0,24953.0,24999.0,0.42777931 +2023-09-24 02:00:00,24998.0,25000.0,24968.0,24976.0,0.3758857 +2023-09-24 04:00:00,24977.0,24985.0,24954.0,24974.0,0.73610059 +2023-09-24 06:00:00,24974.0,24978.0,24948.0,24975.0,3.25095841 +2023-09-24 08:00:00,24975.0,25018.0,24954.0,24976.0,7.23470432 +2023-09-24 10:00:00,24998.0,25018.0,24967.0,25001.0,6.86949048 +2023-09-24 12:00:00,25001.0,25028.0,24975.0,25003.0,7.71447146 +2023-09-24 14:00:00,24999.0,25011.0,24966.0,24976.0,4.06987308 +2023-09-24 16:00:00,24995.0,25110.0,24962.0,25062.0,9.60289792 +2023-09-24 18:00:00,25070.0,25134.0,24820.0,24871.0,13.93498731 +2023-09-24 20:00:00,24865.0,24916.0,24806.0,24916.0,18.47840101 +2023-09-24 22:00:00,24905.0,24905.0,24561.0,24664.0,14.47312511 +2023-09-25 00:00:00,24640.0,24728.0,24442.0,24576.0,25.60122172 +2023-09-25 02:00:00,24579.0,24657.0,24550.0,24568.0,2.36412103 +2023-09-25 04:00:00,24569.0,24602.0,24501.0,24534.0,20.89342688 +2023-09-25 06:00:00,24536.0,24626.0,24464.0,24612.0,17.55815727 +2023-09-25 08:00:00,24600.0,24646.0,24500.0,24501.0,33.34489525 +2023-09-25 10:00:00,24501.0,24554.0,24459.0,24509.0,19.11569224 +2023-09-25 12:00:00,24525.0,24696.0,24459.0,24677.0,27.8587414 +2023-09-25 14:00:00,24676.0,24834.0,24643.0,24777.0,35.78527658 +2023-09-25 16:00:00,24767.0,24918.0,24727.0,24859.0,24.69379123 +2023-09-25 18:00:00,24878.0,24907.0,24797.0,24858.0,17.21918163 +2023-09-25 20:00:00,24865.0,24950.0,24773.0,24786.0,9.50773568 +2023-09-25 22:00:00,24791.0,24826.0,24771.0,24809.0,5.75517475 +2023-09-26 00:00:00,24809.0,24828.0,24758.0,24806.0,0.90217063 +2023-09-26 02:00:00,24833.0,24915.0,24814.0,24884.0,4.31448629 +2023-09-26 04:00:00,24884.0,24894.0,24832.0,24848.0,3.41372984 +2023-09-26 06:00:00,24850.0,24864.0,24789.0,24812.0,8.18533068 +2023-09-26 08:00:00,24814.0,24826.0,24726.0,24777.0,5.47061943 +2023-09-26 10:00:00,24782.0,24791.0,24717.0,24785.0,8.22067868 +2023-09-26 12:00:00,24783.0,24794.0,24681.0,24697.0,10.96441352 +2023-09-26 14:00:00,24690.0,24744.0,24615.0,24700.0,34.86766862 +2023-09-26 16:00:00,24695.0,24857.0,24674.0,24727.0,10.03296512 +2023-09-26 18:00:00,24750.0,24842.0,24725.0,24828.0,10.74008212 +2023-09-26 20:00:00,24815.0,24847.0,24678.0,24742.0,7.64508053 +2023-09-26 22:00:00,24736.0,24804.0,24709.0,24803.0,3.95180365 +2023-09-27 00:00:00,24795.0,24849.0,24779.0,24822.0,0.91753532 +2023-09-27 02:00:00,24838.0,24866.0,24800.0,24851.0,1.9070316 +2023-09-27 04:00:00,24864.0,24864.0,24802.0,24819.0,2.634063 +2023-09-27 06:00:00,24843.0,24853.0,24778.0,24816.0,15.44131974 +2023-09-27 08:00:00,24796.0,24984.0,24777.0,24984.0,17.86630011 +2023-09-27 10:00:00,24982.0,25423.0,24943.0,25339.0,45.25530167 +2023-09-27 12:00:00,25364.0,25449.0,25206.0,25259.0,55.28553432 +2023-09-27 14:00:00,25260.0,25291.0,24856.0,24984.0,41.32645492 +2023-09-27 16:00:00,24999.0,25034.0,24906.0,24938.0,15.32957747 +2023-09-27 18:00:00,24948.0,25001.0,24851.0,24965.0,12.62074974 +2023-09-27 20:00:00,24961.0,25023.0,24933.0,25001.0,10.8238494 +2023-09-27 22:00:00,25004.0,25099.0,24990.0,25084.0,2.98055453 +2023-09-28 00:00:00,25097.0,25223.0,25055.0,25109.0,8.12017817 +2023-09-28 02:00:00,25148.0,25223.0,25055.0,25093.0,1.14895825 +2023-09-28 04:00:00,25106.0,25196.0,25057.0,25145.0,10.48333599 +2023-09-28 06:00:00,25149.0,25217.0,25108.0,25160.0,9.80362654 +2023-09-28 08:00:00,25156.0,25175.0,25027.0,25050.0,14.89159677 +2023-09-28 10:00:00,25050.0,25241.0,25034.0,25061.0,15.36517605 +2023-09-28 12:00:00,25090.0,25174.0,25072.0,25174.0,16.49870852 +2023-09-28 14:00:00,25161.0,25543.0,25131.0,25515.0,110.40772237 +2023-09-28 16:00:00,25532.0,25799.0,25532.0,25730.0,143.04115079 +2023-09-28 18:00:00,25730.0,25798.0,25417.0,25630.0,88.05122781 +2023-09-28 20:00:00,25655.0,25700.0,25428.0,25539.0,50.12997128 +2023-09-28 22:00:00,25549.0,25608.0,25477.0,25555.0,5.96367167 +2023-09-29 00:00:00,25558.0,25650.0,25536.0,25562.0,2.00733653 +2023-09-29 02:00:00,25563.0,25599.0,25392.0,25482.0,2.37116969 +2023-09-29 04:00:00,25482.0,25508.0,25403.0,25507.0,19.20684413 +2023-09-29 06:00:00,25505.0,25678.0,25441.0,25619.0,47.27280749 +2023-09-29 08:00:00,25599.0,25622.0,25419.0,25453.0,19.32765854 +2023-09-29 10:00:00,25458.0,25512.0,25434.0,25457.0,17.25080932 +2023-09-29 12:00:00,25451.0,25565.0,25357.0,25407.0,32.27872067 +2023-09-29 14:00:00,25418.0,25627.0,25249.0,25403.0,30.41282309 +2023-09-29 16:00:00,25388.0,25439.0,25322.0,25403.0,20.6792292 +2023-09-29 18:00:00,25394.0,25488.0,25308.0,25470.0,16.14266697 +2023-09-29 20:00:00,25463.0,25501.0,25406.0,25416.0,14.00901332 +2023-09-29 22:00:00,25416.0,25465.0,25397.0,25439.0,4.03573956 +2023-09-30 00:00:00,25435.0,25485.0,25422.0,25439.0,1.11428088 +2023-09-30 02:00:00,25442.0,25475.0,25419.0,25469.0,1.7799399 +2023-09-30 04:00:00,25470.0,25511.0,25454.0,25467.0,10.55828399 +2023-09-30 06:00:00,25484.0,25507.0,25461.0,25484.0,7.83813154 +2023-09-30 08:00:00,25466.0,25515.0,25458.0,25509.0,9.90012806 +2023-09-30 10:00:00,25510.0,25545.0,25466.0,25484.0,9.29352109 +2023-09-30 12:00:00,25487.0,25522.0,25450.0,25520.0,6.91795183 +2023-09-30 14:00:00,25505.0,25634.0,25487.0,25544.0,12.30638256 +2023-09-30 16:00:00,25523.0,25591.0,25508.0,25574.0,6.39327567 +2023-09-30 18:00:00,25567.0,25584.0,25522.0,25552.0,9.70199456 +2023-09-30 20:00:00,25552.0,25640.0,25500.0,25530.0,19.11889737 +2023-09-30 22:00:00,25528.0,25582.0,25500.0,25517.0,2.63761452 +2023-10-01 00:00:00,25514.0,25578.0,25501.0,25578.0,2.59564426 +2023-10-01 02:00:00,25574.0,25600.0,25547.0,25599.0,0.38440607 +2023-10-01 04:00:00,25598.0,25624.0,25557.0,25623.0,5.85277052 +2023-10-01 06:00:00,25623.0,25706.0,25606.0,25647.0,8.47228202 +2023-10-01 08:00:00,25647.0,25769.0,25630.0,25763.0,24.88325766 +2023-10-01 10:00:00,25740.0,25822.0,25705.0,25720.0,28.68693154 +2023-10-01 12:00:00,25714.0,25720.0,25644.0,25718.0,19.74507164 +2023-10-01 14:00:00,25718.0,25738.0,25609.0,25678.0,9.10694785 +2023-10-01 16:00:00,25658.0,25683.0,25575.0,25587.0,9.23929086 +2023-10-01 18:00:00,25583.0,25644.0,25583.0,25637.0,10.58838502 +2023-10-01 20:00:00,25637.0,25715.0,25593.0,25715.0,14.16482041 +2023-10-01 22:00:00,25710.0,26512.0,25695.0,26472.0,107.35432366 +2023-10-02 00:00:00,26476.0,26527.0,26309.0,26389.0,17.35050785 +2023-10-02 02:00:00,26409.0,26601.0,26389.0,26586.0,23.24536754 +2023-10-02 04:00:00,26590.0,26611.0,26423.0,26469.0,44.54678416 +2023-10-02 06:00:00,26488.0,26870.0,26449.0,26762.0,101.23464892 +2023-10-02 08:00:00,26781.0,26959.0,26701.0,26831.0,88.99767549 +2023-10-02 10:00:00,26849.0,26924.0,26752.0,26764.0,77.39780155 +2023-10-02 12:00:00,26756.0,27107.0,26755.0,27107.0,60.72505789 +2023-10-02 14:00:00,27110.0,27150.0,26640.0,26717.0,91.80666238 +2023-10-02 16:00:00,26696.0,26788.0,26528.0,26719.0,83.57015194 +2023-10-02 18:00:00,26700.0,26755.0,26320.0,26659.0,63.97160066 +2023-10-02 20:00:00,26659.0,26668.0,26040.0,26217.0,51.06506503 +2023-10-02 22:00:00,26219.0,26356.0,26118.0,26251.0,20.52892513 +2023-10-03 00:00:00,26261.0,26336.0,26147.0,26328.0,5.97463534 +2023-10-03 02:00:00,26327.0,26400.0,26291.0,26357.0,5.09134928 +2023-10-03 04:00:00,26370.0,26415.0,26327.0,26350.0,17.24859643 +2023-10-03 06:00:00,26349.0,26441.0,26256.0,26275.0,17.35168442 +2023-10-03 08:00:00,26274.0,26363.0,26255.0,26283.0,14.47351535 +2023-10-03 10:00:00,26283.0,26383.0,26245.0,26316.0,23.07567199 +2023-10-03 12:00:00,26316.0,26324.0,26160.0,26289.0,21.22140356 +2023-10-03 14:00:00,26288.0,26293.0,26050.0,26147.0,54.20499121 +2023-10-03 16:00:00,26147.0,26248.0,26113.0,26214.0,21.45806291 +2023-10-03 18:00:00,26213.0,26220.0,26021.0,26047.0,33.61726528 +2023-10-03 20:00:00,26060.0,26216.0,25950.0,26178.0,34.32427527 +2023-10-03 22:00:00,26178.0,26239.0,26040.0,26189.0,6.13719754 +2023-10-04 00:00:00,26189.0,26195.0,26000.0,26119.0,8.10615062 +2023-10-04 02:00:00,26117.0,26263.0,26091.0,26228.0,5.78996867 +2023-10-04 04:00:00,26202.0,26222.0,26117.0,26167.0,9.54569561 +2023-10-04 06:00:00,26194.0,26254.0,26138.0,26186.0,17.98113395 +2023-10-04 08:00:00,26186.0,26319.0,26142.0,26301.0,22.0987216 +2023-10-04 10:00:00,26319.0,26320.0,26182.0,26254.0,15.2993341 +2023-10-04 12:00:00,26264.0,26285.0,26076.0,26108.0,21.93092852 +2023-10-04 14:00:00,26117.0,26169.0,26052.0,26052.0,23.45103736 +2023-10-04 16:00:00,26052.0,26253.0,26052.0,26237.0,11.78477693 +2023-10-04 18:00:00,26239.0,26499.0,26182.0,26285.0,26.51841773 +2023-10-04 20:00:00,26266.0,26463.0,26225.0,26350.0,12.07054395 +2023-10-04 22:00:00,26364.0,26498.0,26329.0,26462.0,4.37338993 +2023-10-05 00:00:00,26437.0,26521.0,26322.0,26337.0,3.96923856 +2023-10-05 02:00:00,26355.0,26361.0,26275.0,26275.0,2.11623238 +2023-10-05 04:00:00,26287.0,26337.0,26274.0,26274.0,4.87136092 +2023-10-05 06:00:00,26289.0,26340.0,26213.0,26269.0,14.49317188 +2023-10-05 08:00:00,26281.0,26365.0,26235.0,26353.0,13.76928881 +2023-10-05 10:00:00,26353.0,26400.0,26309.0,26358.0,8.32151086 +2023-10-05 12:00:00,26346.0,26681.0,26315.0,26588.0,30.08565311 +2023-10-05 14:00:00,26584.0,26706.0,26055.0,26210.0,65.35158783 +2023-10-05 16:00:00,26190.0,26250.0,26000.0,26097.0,43.19542954 +2023-10-05 18:00:00,26097.0,26134.0,26010.0,26063.0,34.40216005 +2023-10-05 20:00:00,26064.0,26097.0,26000.0,26045.0,18.94092917 +2023-10-05 22:00:00,26026.0,26064.0,26000.0,26014.0,12.73114285 +2023-10-06 00:00:00,26003.0,26138.0,26000.0,26121.0,3.55808891 +2023-10-06 02:00:00,26124.0,26190.0,26124.0,26160.0,9.72321227 +2023-10-06 04:00:00,26163.0,26163.0,26072.0,26101.0,5.5868563 +2023-10-06 06:00:00,26119.0,26227.0,26075.0,26212.0,19.95619088 +2023-10-06 08:00:00,26194.0,26271.0,26155.0,26258.0,13.74504218 +2023-10-06 10:00:00,26263.0,26335.0,26190.0,26286.0,17.38733539 +2023-10-06 12:00:00,26296.0,26358.0,25908.0,26193.0,55.02901019 +2023-10-06 14:00:00,26193.0,26483.0,26148.0,26377.0,28.57761707 +2023-10-06 16:00:00,26381.0,26475.0,26283.0,26410.0,29.40400059 +2023-10-06 18:00:00,26413.0,26483.0,26305.0,26401.0,22.38216843 +2023-10-06 20:00:00,26401.0,26654.0,26354.0,26477.0,38.81610835 +2023-10-06 22:00:00,26511.0,26590.0,26350.0,26408.0,12.25814409 +2023-10-07 00:00:00,26405.0,26430.0,26333.0,26378.0,4.99785622 +2023-10-07 02:00:00,26380.0,26411.0,26350.0,26380.0,0.51161547 +2023-10-07 04:00:00,26385.0,26412.0,26355.0,26360.0,8.13786863 +2023-10-07 06:00:00,26379.0,26398.0,26344.0,26357.0,10.09653739 +2023-10-07 08:00:00,26378.0,26497.0,26346.0,26438.0,10.06382179 +2023-10-07 10:00:00,26424.0,26492.0,26398.0,26431.0,10.50673225 +2023-10-07 12:00:00,26430.0,26469.0,26387.0,26422.0,13.68619012 +2023-10-07 14:00:00,26416.0,26448.0,26371.0,26423.0,7.93390341 +2023-10-07 16:00:00,26404.0,26454.0,26374.0,26422.0,9.74814215 +2023-10-07 18:00:00,26402.0,26433.0,26333.0,26337.0,7.48638739 +2023-10-07 20:00:00,26351.0,26442.0,26344.0,26415.0,4.44649999 +2023-10-07 22:00:00,26419.0,26441.0,26393.0,26435.0,3.33734585 +2023-10-08 00:00:00,26418.0,26484.0,26417.0,26481.0,1.47338011 +2023-10-08 02:00:00,26487.0,26568.0,26453.0,26520.0,5.5940935 +2023-10-08 04:00:00,26523.0,26543.0,26361.0,26412.0,1.56993134 +2023-10-08 06:00:00,26412.0,26432.0,26364.0,26395.0,10.80992116 +2023-10-08 08:00:00,26395.0,26422.0,26331.0,26354.0,9.48573812 +2023-10-08 10:00:00,26370.0,26388.0,26258.0,26302.0,14.71370988 +2023-10-08 12:00:00,26293.0,26487.0,26200.0,26411.0,11.40776797 +2023-10-08 14:00:00,26389.0,26450.0,26356.0,26372.0,8.39113354 +2023-10-08 16:00:00,26374.0,26426.0,26350.0,26370.0,9.19212818 +2023-10-08 18:00:00,26369.0,26408.0,26300.0,26385.0,11.78789344 +2023-10-08 20:00:00,26391.0,26536.0,26381.0,26469.0,18.83404172 +2023-10-08 22:00:00,26461.0,26487.0,26360.0,26444.0,5.66105603 +2023-10-09 00:00:00,26444.0,26521.0,26314.0,26488.0,8.39719136 +2023-10-09 02:00:00,26493.0,26506.0,26442.0,26454.0,0.57751454 +2023-10-09 04:00:00,26479.0,26503.0,26393.0,26410.0,4.19599019 +2023-10-09 06:00:00,26393.0,26504.0,26393.0,26432.0,18.42107828 +2023-10-09 08:00:00,26449.0,26458.0,26118.0,26160.0,33.87863397 +2023-10-09 10:00:00,26160.0,26226.0,26061.0,26106.0,38.90859141 +2023-10-09 12:00:00,26092.0,26176.0,26001.0,26091.0,46.36550121 +2023-10-09 14:00:00,26066.0,26152.0,26032.0,26057.0,31.21031183 +2023-10-09 16:00:00,26054.0,26145.0,25900.0,26125.0,58.99644206 +2023-10-09 18:00:00,26125.0,26270.0,26088.0,26122.0,25.97451839 +2023-10-09 20:00:00,26138.0,26174.0,26083.0,26156.0,9.0766992 +2023-10-09 22:00:00,26157.0,26158.0,26059.0,26069.0,14.52734966 +2023-10-10 00:00:00,26086.0,26139.0,26008.0,26096.0,1.87100646 +2023-10-10 02:00:00,26118.0,26203.0,26077.0,26138.0,3.08602259 +2023-10-10 04:00:00,26159.0,26159.0,26095.0,26150.0,1.90506672 +2023-10-10 06:00:00,26153.0,26243.0,26125.0,26171.0,15.25988118 +2023-10-10 08:00:00,26170.0,26222.0,26055.0,26102.0,14.52726492 +2023-10-10 10:00:00,26108.0,26130.0,26002.0,26021.0,18.84336716 +2023-10-10 12:00:00,26002.0,26039.0,25817.0,25861.0,31.71670661 +2023-10-10 14:00:00,25861.0,26065.0,25806.0,25835.0,31.13010982 +2023-10-10 16:00:00,25834.0,25922.0,25764.0,25839.0,27.14273059 +2023-10-10 18:00:00,25830.0,25887.0,25751.0,25850.0,24.60163261 +2023-10-10 20:00:00,25846.0,25911.0,25763.0,25876.0,10.68282884 +2023-10-10 22:00:00,25891.0,25917.0,25819.0,25819.0,3.44782733 +2023-10-11 00:00:00,25841.0,25915.0,25818.0,25883.0,1.35884128 +2023-10-11 02:00:00,25883.0,25883.0,25500.0,25500.0,29.05851816 +2023-10-11 04:00:00,25500.0,25613.0,25460.0,25594.0,30.54598141 +2023-10-11 06:00:00,25598.0,25599.0,25466.0,25500.0,17.7723107 +2023-10-11 08:00:00,25502.0,25720.0,25484.0,25717.0,31.21823666 +2023-10-11 10:00:00,25720.0,25780.0,25650.0,25660.0,17.53183879 +2023-10-11 12:00:00,25660.0,25727.0,25520.0,25533.0,25.8029044 +2023-10-11 14:00:00,25533.0,25565.0,25209.0,25250.0,44.85971075 +2023-10-11 16:00:00,25241.0,25254.0,25075.0,25148.0,66.3181282 +2023-10-11 18:00:00,25125.0,25246.0,25083.0,25205.0,43.94581457 +2023-10-11 20:00:00,25221.0,25235.0,25120.0,25174.0,19.16301942 +2023-10-11 22:00:00,25174.0,25300.0,25154.0,25300.0,9.51558775 +2023-10-12 00:00:00,25289.0,25296.0,25160.0,25199.0,7.13378709 +2023-10-12 02:00:00,25210.0,25373.0,25178.0,25267.0,2.90023965 +2023-10-12 04:00:00,25269.0,25286.0,25182.0,25286.0,7.36436781 +2023-10-12 06:00:00,25284.0,25322.0,25224.0,25249.0,15.62200145 +2023-10-12 08:00:00,25257.0,25257.0,25115.0,25187.0,18.96479922 +2023-10-12 10:00:00,25176.0,25304.0,25156.0,25265.0,22.64506008 +2023-10-12 12:00:00,25263.0,25399.0,25224.0,25347.0,27.31556869 +2023-10-12 14:00:00,25352.0,25368.0,25229.0,25279.0,12.23308109 +2023-10-12 16:00:00,25277.0,25390.0,25190.0,25278.0,20.84197188 +2023-10-12 18:00:00,25276.0,25382.0,25236.0,25368.0,20.74491216 +2023-10-12 20:00:00,25344.0,25408.0,25341.0,25406.0,34.77970655 +2023-10-12 22:00:00,25388.0,25413.0,25338.0,25401.0,3.95118422 +2023-10-13 00:00:00,25399.0,25488.0,25376.0,25423.0,2.4822918 +2023-10-13 02:00:00,25421.0,25443.0,25383.0,25400.0,1.94653146 +2023-10-13 04:00:00,25385.0,25441.0,25379.0,25408.0,13.00650482 +2023-10-13 06:00:00,25435.0,25527.0,25400.0,25471.0,25.50915661 +2023-10-13 08:00:00,25468.0,25481.0,25378.0,25396.0,21.75589679 +2023-10-13 10:00:00,25399.0,25521.0,25388.0,25491.0,23.05223674 +2023-10-13 12:00:00,25491.0,25580.0,25453.0,25507.0,15.63570708 +2023-10-13 14:00:00,25517.0,25539.0,25392.0,25417.0,19.48274278 +2023-10-13 16:00:00,25433.0,25503.0,25400.0,25469.0,12.62190906 +2023-10-13 18:00:00,25481.0,25485.0,25415.0,25475.0,14.95094318 +2023-10-13 20:00:00,25475.0,25807.0,25446.0,25720.0,40.70949345 +2023-10-13 22:00:00,25721.0,25776.0,25473.0,25576.0,15.19757748 +2023-10-14 00:00:00,25565.0,25637.0,25545.0,25628.0,2.60456375 +2023-10-14 02:00:00,25628.0,25677.0,25591.0,25643.0,1.02822921 +2023-10-14 04:00:00,25645.0,25649.0,25581.0,25581.0,5.87555921 +2023-10-14 06:00:00,25601.0,25612.0,25544.0,25578.0,11.31487216 +2023-10-14 08:00:00,25568.0,25600.0,25539.0,25591.0,16.23342146 +2023-10-14 10:00:00,25597.0,25606.0,25546.0,25563.0,11.75616307 +2023-10-14 12:00:00,25582.0,25613.0,25540.0,25600.0,9.50532656 +2023-10-14 14:00:00,25613.0,25650.0,25566.0,25634.0,11.17279396 +2023-10-14 16:00:00,25650.0,25662.0,25588.0,25612.0,14.71770553 +2023-10-14 18:00:00,25612.0,25612.0,25554.0,25580.0,9.40195391 +2023-10-14 20:00:00,25580.0,25602.0,25512.0,25539.0,9.71374707 +2023-10-14 22:00:00,25523.0,25583.0,25522.0,25559.0,5.49316969 +2023-10-15 00:00:00,25571.0,25613.0,25532.0,25587.0,1.17897065 +2023-10-15 02:00:00,25606.0,25620.0,25572.0,25591.0,0.42024091 +2023-10-15 04:00:00,25593.0,25599.0,25566.0,25574.0,2.91611008 +2023-10-15 06:00:00,25595.0,25597.0,25564.0,25583.0,5.70602469 +2023-10-15 08:00:00,25600.0,25636.0,25581.0,25622.0,8.97668857 +2023-10-15 10:00:00,25622.0,25623.0,25545.0,25567.0,12.26617582 +2023-10-15 12:00:00,25567.0,25656.0,25510.0,25557.0,13.88503973 +2023-10-15 14:00:00,25557.0,25623.0,25555.0,25596.0,11.93942569 +2023-10-15 16:00:00,25597.0,25716.0,25588.0,25684.0,12.25681912 +2023-10-15 18:00:00,25666.0,25772.0,25647.0,25713.0,20.28781135 +2023-10-15 20:00:00,25742.0,25918.0,25707.0,25824.0,32.22557501 +2023-10-15 22:00:00,25825.0,25937.0,25717.0,25809.0,7.80288182 +2023-10-16 00:00:00,25825.0,25929.0,25775.0,25842.0,6.27906895 +2023-10-16 02:00:00,25866.0,25934.0,25812.0,25882.0,1.75561581 +2023-10-16 04:00:00,25887.0,26566.0,25850.0,26495.0,96.38234068 +2023-10-16 06:00:00,26505.0,26557.0,26361.0,26422.0,78.31316115 +2023-10-16 08:00:00,26441.0,26497.0,26219.0,26353.0,46.22005777 +2023-10-16 10:00:00,26369.0,26387.0,26276.0,26344.0,24.84918241 +2023-10-16 12:00:00,26324.0,28348.0,26291.0,26615.0,383.46107416 +2023-10-16 14:00:00,26615.0,26948.0,26483.0,26630.0,135.07835856 +2023-10-16 16:00:00,26615.0,26786.0,26614.0,26744.0,44.36701304 +2023-10-16 18:00:00,26763.0,27286.0,26750.0,26945.0,107.81645995 +2023-10-16 20:00:00,26933.0,27127.0,26723.0,26926.0,63.04534776 +2023-10-16 22:00:00,26928.0,27040.0,26884.0,27003.0,16.90414146 +2023-10-17 00:00:00,27019.0,27032.0,26792.0,26864.0,15.83821065 +2023-10-17 02:00:00,26863.0,26914.0,26795.0,26814.0,3.06921088 +2023-10-17 04:00:00,26803.0,26803.0,26642.0,26777.0,18.37304869 +2023-10-17 06:00:00,26782.0,27000.0,26678.0,26954.0,38.5045132 +2023-10-17 08:00:00,26967.0,27059.0,26884.0,26949.0,29.71095792 +2023-10-17 10:00:00,26950.0,27111.0,26874.0,26898.0,29.24586513 +2023-10-17 12:00:00,26875.0,26955.0,26676.0,26845.0,54.58831152 +2023-10-17 14:00:00,26826.0,27009.0,26812.0,26905.0,34.4172248 +2023-10-17 16:00:00,26877.0,27062.0,26848.0,26929.0,33.65029461 +2023-10-17 18:00:00,26929.0,26986.0,26800.0,26978.0,22.97016006 +2023-10-17 20:00:00,26977.0,27000.0,26849.0,26939.0,20.75947066 +2023-10-17 22:00:00,26932.0,26947.0,26831.0,26885.0,4.54896369 +2023-10-18 00:00:00,26851.0,26914.0,26807.0,26846.0,1.8624548 +2023-10-18 02:00:00,26838.0,26978.0,26837.0,26958.0,4.89499927 +2023-10-18 04:00:00,26977.0,27399.0,26891.0,27125.0,51.94759152 +2023-10-18 06:00:00,27130.0,27162.0,26921.0,26946.0,43.27703625 +2023-10-18 08:00:00,26930.0,27051.0,26750.0,26750.0,32.49184812 +2023-10-18 10:00:00,26750.0,26932.0,26750.0,26864.0,28.04722937 +2023-10-18 12:00:00,26860.0,26925.0,26801.0,26885.0,22.24721748 +2023-10-18 14:00:00,26864.0,26888.0,26736.0,26848.0,21.87789326 +2023-10-18 16:00:00,26829.0,26966.0,26822.0,26872.0,21.01176653 +2023-10-18 18:00:00,26871.0,26921.0,26813.0,26841.0,12.0061167 +2023-10-18 20:00:00,26833.0,26884.0,26777.0,26855.0,9.2976035 +2023-10-18 22:00:00,26851.0,26930.0,26816.0,26891.0,9.05366762 +2023-10-19 00:00:00,26877.0,26976.0,26717.0,26802.0,7.75890705 +2023-10-19 02:00:00,26819.0,26845.0,26733.0,26808.0,4.88292085 +2023-10-19 04:00:00,26817.0,26925.0,26800.0,26891.0,7.88507566 +2023-10-19 06:00:00,26891.0,26901.0,26786.0,26892.0,17.03732088 +2023-10-19 08:00:00,26894.0,26970.0,26829.0,26940.0,16.39062482 +2023-10-19 10:00:00,26942.0,27050.0,26908.0,26960.0,29.17606261 +2023-10-19 12:00:00,26967.0,27056.0,26904.0,26959.0,19.98612445 +2023-10-19 14:00:00,26945.0,27271.0,26920.0,27159.0,45.80111746 +2023-10-19 16:00:00,27133.0,27294.0,26892.0,26965.0,53.17901358 +2023-10-19 18:00:00,26950.0,27192.0,26938.0,27181.0,22.01484944 +2023-10-19 20:00:00,27181.0,27295.0,27036.0,27036.0,28.73039186 +2023-10-19 22:00:00,27067.0,27148.0,27042.0,27148.0,7.72544943 +2023-10-20 00:00:00,27148.0,27200.0,27051.0,27120.0,8.78688447 +2023-10-20 02:00:00,27130.0,27750.0,27092.0,27642.0,60.3921334 +2023-10-20 04:00:00,27649.0,27744.0,27520.0,27634.0,37.30236674 +2023-10-20 06:00:00,27630.0,27800.0,27587.0,27676.0,63.31944938 +2023-10-20 08:00:00,27676.0,28193.0,27656.0,28157.0,144.88575445 +2023-10-20 10:00:00,28151.0,28390.0,28115.0,28175.0,162.03971556 +2023-10-20 12:00:00,28177.0,28251.0,27758.0,28043.0,138.70554687 +2023-10-20 14:00:00,28039.0,28100.0,27818.0,27908.0,55.71233045 +2023-10-20 16:00:00,27890.0,27956.0,27705.0,27865.0,44.04506023 +2023-10-20 18:00:00,27848.0,27916.0,27752.0,27916.0,30.48576119 +2023-10-20 20:00:00,27916.0,27999.0,27852.0,27962.0,27.26939823 +2023-10-20 22:00:00,27944.0,28101.0,27931.0,28018.0,15.32730975 +2023-10-21 00:00:00,28017.0,28035.0,27865.0,27865.0,10.89448825 +2023-10-21 02:00:00,27876.0,27972.0,27805.0,27959.0,2.46956245 +2023-10-21 04:00:00,27959.0,27977.0,27876.0,27905.0,7.74892154 +2023-10-21 06:00:00,27919.0,28081.0,27919.0,28058.0,42.38723065 +2023-10-21 08:00:00,28056.0,28200.0,27965.0,28179.0,28.26866815 +2023-10-21 10:00:00,28160.0,28200.0,28086.0,28176.0,34.39720413 +2023-10-21 12:00:00,28167.0,28172.0,28050.0,28124.0,17.62075644 +2023-10-21 14:00:00,28132.0,28292.0,28093.0,28246.0,28.03460107 +2023-10-21 16:00:00,28287.0,28466.0,28163.0,28424.0,83.19182327 +2023-10-21 18:00:00,28454.0,28581.0,28252.0,28441.0,92.14574993 +2023-10-21 20:00:00,28453.0,28471.0,28230.0,28291.0,26.1199692 +2023-10-21 22:00:00,28291.0,28359.0,28167.0,28214.0,13.76404794 +2023-10-22 00:00:00,28215.0,28376.0,28176.0,28244.0,6.13151319 +2023-10-22 02:00:00,28261.0,28261.0,28175.0,28253.0,13.26998447 +2023-10-22 04:00:00,28254.0,28517.0,28236.0,28417.0,20.92766696 +2023-10-22 06:00:00,28439.0,28522.0,28000.0,28139.0,26.9246169 +2023-10-22 08:00:00,28164.0,28314.0,28106.0,28198.0,25.39921226 +2023-10-22 10:00:00,28222.0,28282.0,28171.0,28251.0,18.36361697 +2023-10-22 12:00:00,28246.0,28301.0,28207.0,28260.0,19.94871643 +2023-10-22 14:00:00,28261.0,28274.0,28122.0,28143.0,15.71929784 +2023-10-22 16:00:00,28163.0,28261.0,28124.0,28235.0,15.88697128 +2023-10-22 18:00:00,28240.0,28254.0,28134.0,28164.0,16.81153037 +2023-10-22 20:00:00,28164.0,28206.0,28057.0,28057.0,17.83538039 +2023-10-22 22:00:00,28078.0,28355.0,28050.0,28318.0,13.35525822 +2023-10-23 00:00:00,28312.0,28875.0,28219.0,28624.0,65.62301102 +2023-10-23 02:00:00,28665.0,29047.0,28503.0,29006.0,77.92233054 +2023-10-23 04:00:00,29037.0,29222.0,28868.0,29090.0,76.03764249 +2023-10-23 06:00:00,29099.0,29259.0,28750.0,28785.0,129.49495298 +2023-10-23 08:00:00,28789.0,28947.0,28567.0,28776.0,97.12359785 +2023-10-23 10:00:00,28765.0,29022.0,28753.0,28916.0,42.39865374 +2023-10-23 12:00:00,28927.0,29010.0,28727.0,28875.0,50.55403025 +2023-10-23 14:00:00,28887.0,29100.0,28833.0,29043.0,42.58585893 +2023-10-23 16:00:00,29042.0,29385.0,28901.0,29058.0,127.6600223 +2023-10-23 18:00:00,29072.0,29495.0,28862.0,29449.0,113.63970431 +2023-10-23 20:00:00,29445.0,29844.0,29393.0,29676.0,181.83722751 +2023-10-23 22:00:00,29661.0,32474.0,29627.0,31026.0,365.54653987 +2023-10-24 00:00:00,30999.0,32068.0,30767.0,32010.0,90.89041773 +2023-10-24 02:00:00,32052.0,32997.0,31803.0,31818.0,157.14145729 +2023-10-24 04:00:00,31833.0,32353.0,31609.0,31693.0,199.42872697 +2023-10-24 06:00:00,31693.0,31907.0,31522.0,31888.0,181.49023869 +2023-10-24 08:00:00,31888.0,32425.0,31855.0,32295.0,163.90534631 +2023-10-24 10:00:00,32281.0,32869.0,32208.0,32503.0,163.71327148 +2023-10-24 12:00:00,32504.0,32799.0,32224.0,32468.0,139.52737443 +2023-10-24 14:00:00,32452.0,32623.0,31277.0,31773.0,242.20585692 +2023-10-24 16:00:00,31780.0,32424.0,31581.0,31898.0,132.48308406 +2023-10-24 18:00:00,31905.0,31994.0,31506.0,31904.0,99.29086379 +2023-10-24 20:00:00,31905.0,32290.0,31606.0,32232.0,99.86778256 +2023-10-24 22:00:00,32213.0,32287.0,31820.0,32026.0,32.45388346 +2023-10-25 00:00:00,32036.0,32432.0,31882.0,32239.0,15.12009271 +2023-10-25 02:00:00,32281.0,32296.0,31989.0,32040.0,13.95860614 +2023-10-25 04:00:00,32074.0,32258.0,31986.0,32094.0,35.95812603 +2023-10-25 06:00:00,32096.0,32322.0,31839.0,31965.0,88.5942813 +2023-10-25 08:00:00,31994.0,32456.0,31882.0,32286.0,79.97715327 +2023-10-25 10:00:00,32286.0,32534.0,32219.0,32345.0,63.49717163 +2023-10-25 12:00:00,32336.0,32750.0,32336.0,32603.0,98.20604705 +2023-10-25 14:00:00,32604.0,33070.0,32479.0,32941.0,145.07056271 +2023-10-25 16:00:00,32930.0,33250.0,32551.0,32808.0,149.76526479 +2023-10-25 18:00:00,32821.0,32940.0,32600.0,32906.0,54.73990076 +2023-10-25 20:00:00,32873.0,33007.0,32678.0,32726.0,70.51596181 +2023-10-25 22:00:00,32706.0,32825.0,32500.0,32675.0,15.94959854 +2023-10-26 00:00:00,32673.0,32986.0,32608.0,32874.0,14.31097597 +2023-10-26 02:00:00,32886.0,33033.0,32850.0,32988.0,10.90592733 +2023-10-26 04:00:00,33010.0,33028.0,32724.0,32765.0,15.53344165 +2023-10-26 06:00:00,32766.0,33018.0,32663.0,32877.0,47.91221426 +2023-10-26 08:00:00,32835.0,32944.0,32630.0,32677.0,58.00965585 +2023-10-26 10:00:00,32677.0,32697.0,32219.0,32356.0,113.15986212 +2023-10-26 12:00:00,32357.0,32563.0,32328.0,32404.0,61.66401182 +2023-10-26 14:00:00,32435.0,32600.0,32136.0,32293.0,83.63627408 +2023-10-26 16:00:00,32316.0,32348.0,31897.0,32144.0,97.11246657 +2023-10-26 18:00:00,32146.0,32300.0,32126.0,32275.0,63.6751001 +2023-10-26 20:00:00,32244.0,32414.0,32231.0,32291.0,36.3701522 +2023-10-26 22:00:00,32315.0,32469.0,32292.0,32349.0,13.96816479 +2023-10-27 00:00:00,32332.0,32339.0,32023.0,32054.0,9.19682337 +2023-10-27 02:00:00,32076.0,32327.0,32041.0,32265.0,16.27814581 +2023-10-27 04:00:00,32297.0,32356.0,32142.0,32247.0,17.46789266 +2023-10-27 06:00:00,32247.0,32454.0,32145.0,32166.0,36.33579002 +2023-10-27 08:00:00,32177.0,32378.0,32149.0,32334.0,26.80324619 +2023-10-27 10:00:00,32334.0,32376.0,32219.0,32296.0,26.20334639 +2023-10-27 12:00:00,32318.0,32421.0,32200.0,32284.0,34.12556332 +2023-10-27 14:00:00,32306.0,32327.0,32023.0,32125.0,40.97196511 +2023-10-27 16:00:00,32100.0,32157.0,31700.0,31787.0,64.00067132 +2023-10-27 18:00:00,31783.0,31894.0,31600.0,31887.0,84.23720586 +2023-10-27 20:00:00,31887.0,32078.0,31846.0,32027.0,40.00717224 +2023-10-27 22:00:00,32052.0,32142.0,31976.0,32088.0,11.5243588 +2023-10-28 00:00:00,32081.0,32134.0,32056.0,32088.0,5.78325923 +2023-10-28 02:00:00,32114.0,32309.0,32085.0,32258.0,3.48888377 +2023-10-28 04:00:00,32260.0,32377.0,32191.0,32279.0,22.99832554 +2023-10-28 06:00:00,32297.0,32318.0,32219.0,32251.0,15.26487465 +2023-10-28 08:00:00,32263.0,32321.0,32216.0,32301.0,37.6257876 +2023-10-28 10:00:00,32282.0,32655.0,32275.0,32380.0,48.52148436 +2023-10-28 12:00:00,32380.0,32413.0,32121.0,32320.0,38.95775099 +2023-10-28 14:00:00,32352.0,32448.0,32241.0,32374.0,17.95589216 +2023-10-28 16:00:00,32409.0,32411.0,32300.0,32331.0,16.24027853 +2023-10-28 18:00:00,32319.0,32403.0,32263.0,32333.0,24.11282941 +2023-10-28 20:00:00,32301.0,32404.0,32300.0,32395.0,7.94558734 +2023-10-28 22:00:00,32374.0,32395.0,32260.0,32291.0,7.91167737 +2023-10-29 00:00:00,32290.0,32309.0,32175.0,32225.0,6.009042 +2023-10-29 02:00:00,32212.0,32248.0,32166.0,32189.0,2.5025987 +2023-10-29 04:00:00,32189.0,32248.0,32150.0,32237.0,2.98893577 +2023-10-29 06:00:00,32239.0,32334.0,32202.0,32291.0,10.62386394 +2023-10-29 08:00:00,32288.0,32471.0,32273.0,32398.0,25.03078004 +2023-10-29 10:00:00,32400.0,32500.0,32347.0,32463.0,22.46327503 +2023-10-29 12:00:00,32442.0,32700.0,32442.0,32566.0,34.58393833 +2023-10-29 14:00:00,32566.0,32750.0,32500.0,32616.0,35.13467276 +2023-10-29 16:00:00,32616.0,32922.0,32541.0,32752.0,42.04345878 +2023-10-29 18:00:00,32737.0,32930.0,32706.0,32737.0,39.30629079 +2023-10-29 20:00:00,32736.0,32834.0,32578.0,32647.0,25.21404184 +2023-10-29 22:00:00,32619.0,32900.0,32619.0,32710.0,29.12736436 +2023-10-30 00:00:00,32718.0,32773.0,32598.0,32598.0,4.14191107 +2023-10-30 02:00:00,32598.0,32598.0,32425.0,32472.0,10.59927399 +2023-10-30 04:00:00,32472.0,32552.0,32432.0,32460.0,10.95555312 +2023-10-30 06:00:00,32460.0,32534.0,32350.0,32398.0,28.57778653 +2023-10-30 08:00:00,32421.0,32780.0,32387.0,32646.0,35.2682534 +2023-10-30 10:00:00,32627.0,32746.0,32552.0,32709.0,27.5308694 +2023-10-30 12:00:00,32697.0,32927.0,32526.0,32704.0,48.41953526 +2023-10-30 14:00:00,32707.0,32894.0,32601.0,32640.0,47.71928258 +2023-10-30 16:00:00,32638.0,32656.0,32185.0,32367.0,66.25048239 +2023-10-30 18:00:00,32367.0,32485.0,32300.0,32446.0,32.80808033 +2023-10-30 20:00:00,32468.0,32612.0,32353.0,32540.0,27.71416179 +2023-10-30 22:00:00,32543.0,32575.0,32461.0,32515.0,12.56350452 +2023-10-31 00:00:00,32520.0,32637.0,32448.0,32486.0,6.48711372 +2023-10-31 02:00:00,32485.0,32523.0,32302.0,32302.0,7.92522956 +2023-10-31 04:00:00,32324.0,32424.0,32270.0,32376.0,12.13986615 +2023-10-31 06:00:00,32377.0,32447.0,32153.0,32185.0,37.28044346 +2023-10-31 08:00:00,32187.0,32387.0,32105.0,32295.0,40.9903835 +2023-10-31 10:00:00,32306.0,32437.0,32254.0,32405.0,35.92734056 +2023-10-31 12:00:00,32401.0,32420.0,32218.0,32278.0,25.62570865 +2023-10-31 14:00:00,32278.0,32471.0,32220.0,32469.0,27.91595164 +2023-10-31 16:00:00,32469.0,32685.0,32400.0,32520.0,39.11969334 +2023-10-31 18:00:00,32520.0,32700.0,32484.0,32675.0,22.64896174 +2023-10-31 20:00:00,32663.0,32850.0,32562.0,32624.0,50.75177768 +2023-10-31 22:00:00,32593.0,32784.0,32564.0,32749.0,24.65596794 +2023-11-01 00:00:00,32768.0,32788.0,32610.0,32648.0,16.88833066 +2023-11-01 02:00:00,32649.0,32668.0,32562.0,32601.0,9.12634959 +2023-11-01 04:00:00,32591.0,32643.0,32500.0,32527.0,6.71090283 +2023-11-01 06:00:00,32520.0,32695.0,32475.0,32641.0,19.39514916 +2023-11-01 08:00:00,32636.0,32728.0,32584.0,32687.0,27.86609827 +2023-11-01 10:00:00,32690.0,32713.0,32570.0,32673.0,29.20240699 +2023-11-01 12:00:00,32655.0,33442.0,32577.0,32850.0,166.53941148 +2023-11-01 14:00:00,32850.0,32887.0,32357.0,32576.0,95.10409603 +2023-11-01 16:00:00,32575.0,32824.0,32556.0,32797.0,41.88766102 +2023-11-01 18:00:00,32800.0,32957.0,32648.0,32739.0,49.81796549 +2023-11-01 20:00:00,32706.0,33744.0,32693.0,33490.0,208.68910933 +2023-11-01 22:00:00,33490.0,33624.0,33273.0,33495.0,64.3093117 +2023-11-02 00:00:00,33490.0,33680.0,33376.0,33605.0,30.01014597 +2023-11-02 02:00:00,33575.0,33946.0,33542.0,33585.0,27.61551823 +2023-11-02 04:00:00,33616.0,33619.0,33204.0,33257.0,46.15019059 +2023-11-02 06:00:00,33222.0,33359.0,33123.0,33309.0,55.46154612 +2023-11-02 08:00:00,33309.0,33388.0,33200.0,33343.0,42.36413275 +2023-11-02 10:00:00,33342.0,33438.0,33250.0,33316.0,50.77856858 +2023-11-02 12:00:00,33303.0,33323.0,32744.0,32831.0,87.39253087 +2023-11-02 14:00:00,32842.0,32948.0,32566.0,32666.0,94.98150999 +2023-11-02 16:00:00,32659.0,32766.0,32356.0,32741.0,85.70775709 +2023-11-02 18:00:00,32752.0,33018.0,32740.0,32968.0,56.95793682 +2023-11-02 20:00:00,32999.0,33100.0,32805.0,32894.0,45.41593749 +2023-11-02 22:00:00,32922.0,32941.0,32731.0,32939.0,13.83936181 +2023-11-03 00:00:00,32924.0,32942.0,32418.0,32610.0,30.80097346 +2023-11-03 02:00:00,32564.0,32691.0,32564.0,32688.0,3.80376686 +2023-11-03 04:00:00,32652.0,32688.0,32337.0,32510.0,32.62641207 +2023-11-03 06:00:00,32526.0,32546.0,32360.0,32456.0,25.60129808 +2023-11-03 08:00:00,32453.0,32604.0,32134.0,32202.0,96.75305635 +2023-11-03 10:00:00,32200.0,32231.0,32050.0,32185.0,88.7107635 +2023-11-03 12:00:00,32196.0,32323.0,32078.0,32293.0,47.52892246 +2023-11-03 14:00:00,32282.0,32570.0,32269.0,32438.0,88.66391518 +2023-11-03 16:00:00,32416.0,32496.0,32048.0,32128.0,37.44881979 +2023-11-03 18:00:00,32113.0,32294.0,32036.0,32247.0,24.77142113 +2023-11-03 20:00:00,32246.0,32397.0,32182.0,32308.0,19.07970761 +2023-11-03 22:00:00,32320.0,32420.0,32240.0,32383.0,18.23945701 +2023-11-04 00:00:00,32381.0,32472.0,32331.0,32467.0,6.38738749 +2023-11-04 02:00:00,32474.0,32474.0,32322.0,32406.0,3.38844472 +2023-11-04 04:00:00,32407.0,32445.0,32269.0,32445.0,4.98521731 +2023-11-04 06:00:00,32446.0,32635.0,32420.0,32428.0,33.54732146 +2023-11-04 08:00:00,32454.0,32552.0,32420.0,32454.0,35.03612874 +2023-11-04 10:00:00,32454.0,32510.0,32378.0,32405.0,22.01683447 +2023-11-04 12:00:00,32429.0,32487.0,32361.0,32416.0,22.97904323 +2023-11-04 14:00:00,32417.0,32483.0,32336.0,32417.0,16.42774814 +2023-11-04 16:00:00,32394.0,32493.0,32382.0,32458.0,17.16515663 +2023-11-04 18:00:00,32486.0,32500.0,32421.0,32424.0,12.8610468 +2023-11-04 20:00:00,32406.0,32594.0,32397.0,32505.0,15.7882004 +2023-11-04 22:00:00,32531.0,32923.0,32489.0,32733.0,52.0057916 +2023-11-05 00:00:00,32719.0,32756.0,32596.0,32741.0,5.25702711 +2023-11-05 02:00:00,32741.0,32934.0,32609.0,32900.0,6.36599377 +2023-11-05 04:00:00,32901.0,32939.0,32761.0,32821.0,15.70454027 +2023-11-05 06:00:00,32821.0,32837.0,32688.0,32828.0,12.66701702 +2023-11-05 08:00:00,32830.0,32849.0,32668.0,32737.0,17.85573289 +2023-11-05 10:00:00,32768.0,32812.0,32682.0,32753.0,28.10174445 +2023-11-05 12:00:00,32753.0,32835.0,32497.0,32511.0,30.46655517 +2023-11-05 14:00:00,32514.0,32618.0,32487.0,32550.0,42.93242696 +2023-11-05 16:00:00,32550.0,32900.0,32536.0,32711.0,39.52580485 +2023-11-05 18:00:00,32729.0,32776.0,32624.0,32634.0,24.74721739 +2023-11-05 20:00:00,32656.0,32737.0,32215.0,32363.0,58.75392581 +2023-11-05 22:00:00,32362.0,33016.0,32351.0,32683.0,45.71587577 +2023-11-06 00:00:00,32682.0,32786.0,32508.0,32566.0,5.52309107 +2023-11-06 02:00:00,32559.0,32649.0,32500.0,32615.0,2.19730658 +2023-11-06 04:00:00,32620.0,32674.0,32375.0,32446.0,20.45920551 +2023-11-06 06:00:00,32470.0,32572.0,32408.0,32543.0,19.93337851 +2023-11-06 08:00:00,32571.0,32717.0,32449.0,32710.0,30.37430963 +2023-11-06 10:00:00,32699.0,32846.0,32650.0,32790.0,36.41979849 +2023-11-06 12:00:00,32807.0,32811.0,32522.0,32669.0,39.87401206 +2023-11-06 14:00:00,32661.0,32853.0,32641.0,32681.0,39.10852489 +2023-11-06 16:00:00,32691.0,32717.0,32520.0,32623.0,33.10578599 +2023-11-06 18:00:00,32624.0,32746.0,32471.0,32698.0,37.12984444 +2023-11-06 20:00:00,32731.0,32739.0,32578.0,32707.0,28.93484333 +2023-11-06 22:00:00,32717.0,32820.0,32610.0,32734.0,15.67045486 +2023-11-07 00:00:00,32718.0,32744.0,32534.0,32643.0,2.42695703 +2023-11-07 02:00:00,32668.0,32691.0,32502.0,32646.0,5.34279332 +2023-11-07 04:00:00,32616.0,32646.0,32549.0,32635.0,6.72815763 +2023-11-07 06:00:00,32634.0,32719.0,32582.0,32691.0,17.06093182 +2023-11-07 08:00:00,32702.0,32725.0,32510.0,32559.0,24.28137299 +2023-11-07 10:00:00,32562.0,32584.0,32370.0,32502.0,45.14447569 +2023-11-07 12:00:00,32502.0,32617.0,32352.0,32617.0,36.04072977 +2023-11-07 14:00:00,32616.0,32675.0,32422.0,32521.0,35.91248418 +2023-11-07 16:00:00,32515.0,32665.0,32395.0,32664.0,27.89310917 +2023-11-07 18:00:00,32664.0,33250.0,32626.0,33159.0,199.76842568 +2023-11-07 20:00:00,33174.0,33567.0,33066.0,33177.0,126.46073066 +2023-11-07 22:00:00,33163.0,33186.0,32922.0,33130.0,50.38048965 +2023-11-08 00:00:00,33130.0,33155.0,32980.0,33123.0,10.78605769 +2023-11-08 02:00:00,33121.0,33128.0,32984.0,33003.0,4.47415036 +2023-11-08 04:00:00,33007.0,33110.0,32987.0,33006.0,9.19249695 +2023-11-08 06:00:00,33027.0,33090.0,32930.0,33017.0,21.52826207 +2023-11-08 08:00:00,33000.0,33150.0,32980.0,33104.0,33.36412308 +2023-11-08 10:00:00,33115.0,33242.0,33084.0,33118.0,34.4782737 +2023-11-08 12:00:00,33096.0,33250.0,33086.0,33213.0,27.2283977 +2023-11-08 14:00:00,33220.0,33226.0,32867.0,32916.0,59.74356145 +2023-11-08 16:00:00,32910.0,33142.0,32859.0,32980.0,38.27156427 +2023-11-08 18:00:00,32978.0,33405.0,32967.0,33313.0,66.3395791 +2023-11-08 20:00:00,33323.0,33525.0,33077.0,33268.0,88.27883066 +2023-11-08 22:00:00,33268.0,33718.0,33246.0,33284.0,99.38473605 +2023-11-09 00:00:00,33254.0,33690.0,33205.0,33553.0,22.68733147 +2023-11-09 02:00:00,33547.0,34108.0,33474.0,34019.0,73.55903457 +2023-11-09 04:00:00,34077.0,34404.0,34003.0,34180.0,80.79090305 +2023-11-09 06:00:00,34176.0,34403.0,34146.0,34167.0,102.22538736 +2023-11-09 08:00:00,34165.0,34490.0,34141.0,34490.0,85.42098669 +2023-11-09 10:00:00,34485.0,34610.0,34332.0,34484.0,98.42236377 +2023-11-09 12:00:00,34464.0,34779.0,34420.0,34751.0,100.98812553 +2023-11-09 14:00:00,34768.0,35473.0,33538.0,34615.0,412.52885907 +2023-11-09 16:00:00,34627.0,34752.0,33300.0,34265.0,353.25559291 +2023-11-09 18:00:00,34265.0,34265.0,33914.0,34145.0,91.39691151 +2023-11-09 20:00:00,34143.0,34485.0,33900.0,34289.0,86.68468078 +2023-11-09 22:00:00,34287.0,34504.0,34240.0,34441.0,30.46482893 +2023-11-10 00:00:00,34440.0,34505.0,34200.0,34393.0,15.66849653 +2023-11-10 02:00:00,34417.0,34600.0,34334.0,34461.0,5.7848179 +2023-11-10 04:00:00,34432.0,34543.0,34357.0,34489.0,26.7347954 +2023-11-10 06:00:00,34462.0,34499.0,34161.0,34191.0,54.75957259 +2023-11-10 08:00:00,34190.0,34273.0,34064.0,34260.0,39.68280339 +2023-11-10 10:00:00,34263.0,34822.0,34205.0,34737.0,81.90427546 +2023-11-10 12:00:00,34768.0,34910.0,34542.0,34616.0,72.41410423 +2023-11-10 14:00:00,34601.0,34850.0,34500.0,34776.0,105.40728389 +2023-11-10 16:00:00,34761.0,35100.0,34754.0,34865.0,122.37866333 +2023-11-10 18:00:00,34861.0,35054.0,34808.0,34895.0,58.87886709 +2023-11-10 20:00:00,34912.0,35031.0,34763.0,34927.0,56.21724157 +2023-11-10 22:00:00,34902.0,35136.0,34804.0,34942.0,56.72555667 +2023-11-11 00:00:00,34950.0,35043.0,34655.0,34690.0,35.82739687 +2023-11-11 02:00:00,34690.0,34776.0,34580.0,34692.0,8.17375555 +2023-11-11 04:00:00,34727.0,34784.0,34587.0,34734.0,9.99359569 +2023-11-11 06:00:00,34737.0,34805.0,34628.0,34707.0,31.91423943 +2023-11-11 08:00:00,34707.0,34748.0,34622.0,34738.0,21.55514176 +2023-11-11 10:00:00,34738.0,34752.0,34631.0,34707.0,37.988403 +2023-11-11 12:00:00,34681.0,34902.0,34656.0,34827.0,39.57285034 +2023-11-11 14:00:00,34827.0,34972.0,34713.0,34754.0,49.23241917 +2023-11-11 16:00:00,34754.0,34868.0,34730.0,34788.0,28.72076113 +2023-11-11 18:00:00,34812.0,34861.0,34753.0,34842.0,17.84491329 +2023-11-11 20:00:00,34816.0,34844.0,34630.0,34673.0,34.03989541 +2023-11-11 22:00:00,34673.0,34850.0,34500.0,34841.0,37.48912444 +2023-11-12 00:00:00,34841.0,34869.0,34453.0,34680.0,11.79087084 +2023-11-12 02:00:00,34650.0,34698.0,34580.0,34698.0,7.26273874 +2023-11-12 04:00:00,34667.0,34799.0,34612.0,34767.0,4.26476471 +2023-11-12 06:00:00,34768.0,34857.0,34747.0,34790.0,23.01090359 +2023-11-12 08:00:00,34815.0,34834.0,34713.0,34725.0,21.00297066 +2023-11-12 10:00:00,34748.0,34834.0,34713.0,34752.0,22.92411531 +2023-11-12 12:00:00,34735.0,34817.0,34630.0,34758.0,27.74596592 +2023-11-12 14:00:00,34742.0,34883.0,34737.0,34835.0,27.40498452 +2023-11-12 16:00:00,34834.0,34867.0,34724.0,34749.0,27.97527631 +2023-11-12 18:00:00,34740.0,34885.0,34708.0,34798.0,26.24109142 +2023-11-12 20:00:00,34797.0,34898.0,34748.0,34836.0,35.91831565 +2023-11-12 22:00:00,34836.0,34875.0,34614.0,34731.0,20.55489521 +2023-11-13 00:00:00,34718.0,35028.0,34619.0,34843.0,17.53670593 +2023-11-13 02:00:00,34843.0,34906.0,34550.0,34601.0,6.33025851 +2023-11-13 04:00:00,34599.0,34626.0,34500.0,34603.0,13.46040667 +2023-11-13 06:00:00,34600.0,34697.0,34457.0,34619.0,33.66807849 +2023-11-13 08:00:00,34619.0,34686.0,34545.0,34643.0,28.8039452 +2023-11-13 10:00:00,34621.0,34653.0,34370.0,34477.0,59.11365163 +2023-11-13 12:00:00,34479.0,34653.0,34316.0,34542.0,45.97767708 +2023-11-13 14:00:00,34524.0,34615.0,34277.0,34472.0,67.87454042 +2023-11-13 16:00:00,34462.0,34650.0,34259.0,34310.0,49.56055916 +2023-11-13 18:00:00,34305.0,34460.0,34230.0,34458.0,47.04748974 +2023-11-13 20:00:00,34462.0,34486.0,33982.0,34124.0,138.06434445 +2023-11-13 22:00:00,34123.0,34251.0,34070.0,34102.0,49.26173334 +2023-11-14 00:00:00,34102.0,34103.0,33832.0,33968.0,44.43921921 +2023-11-14 02:00:00,33964.0,34139.0,33953.0,34071.0,6.78132984 +2023-11-14 04:00:00,34094.0,34287.0,34021.0,34286.0,15.47761784 +2023-11-14 06:00:00,34286.0,34363.0,34230.0,34300.0,33.44633961 +2023-11-14 08:00:00,34300.0,34385.0,34060.0,34060.0,35.45521446 +2023-11-14 10:00:00,34060.0,34090.0,33830.0,33868.0,68.22731539 +2023-11-14 16:00:00,33909.0,33909.0,33173.0,33200.0,69.68058834 +2023-11-14 18:00:00,33185.0,33247.0,32155.0,32438.0,323.03325827 +2023-11-14 20:00:00,32431.0,32782.0,32370.0,32736.0,107.19393461 +2023-11-14 22:00:00,32715.0,32839.0,32627.0,32718.0,47.63951584 +2023-11-15 00:00:00,32711.0,32826.0,32622.0,32659.0,12.72949364 +2023-11-15 02:00:00,32600.0,32694.0,32540.0,32540.0,6.7046959 +2023-11-15 04:00:00,32540.0,32787.0,32536.0,32780.0,11.51026357 +2023-11-15 06:00:00,32780.0,32888.0,32710.0,32761.0,54.02509699 +2023-11-15 08:00:00,32762.0,33171.0,32760.0,33016.0,82.21971369 +2023-11-15 10:00:00,33005.0,33438.0,32968.0,33363.0,69.82872212 +2023-11-15 12:00:00,33383.0,33553.0,33158.0,33268.0,71.94857125 +2023-11-15 14:00:00,33283.0,33534.0,33217.0,33520.0,37.14535873 +2023-11-15 16:00:00,33538.0,33691.0,33430.0,33670.0,57.31285186 +2023-11-15 18:00:00,33670.0,34850.0,33623.0,34602.0,229.14042853 +2023-11-15 20:00:00,34581.0,34898.0,34407.0,34704.0,136.89501438 +2023-11-15 22:00:00,34721.0,35000.0,34571.0,34920.0,65.58213854 +2023-11-16 00:00:00,34924.0,34971.0,34505.0,34544.0,23.1211326 +2023-11-16 02:00:00,34552.0,34673.0,34449.0,34592.0,10.31478293 +2023-11-16 04:00:00,34592.0,34646.0,34456.0,34592.0,14.88014268 +2023-11-16 06:00:00,34564.0,34739.0,34522.0,34561.0,27.40642183 +2023-11-16 08:00:00,34561.0,34602.0,34264.0,34457.0,76.02201021 +2023-11-16 10:00:00,34445.0,34600.0,34246.0,34334.0,30.80567566 +2023-11-16 12:00:00,34342.0,34430.0,33745.0,33832.0,121.24080725 +2023-11-16 14:00:00,33831.0,33925.0,33400.0,33511.0,156.05197059 +2023-11-16 16:00:00,33507.0,33806.0,33441.0,33490.0,60.18107227 +2023-11-16 18:00:00,33468.0,33538.0,32725.0,33112.0,174.62523172 +2023-11-16 20:00:00,33122.0,33291.0,32919.0,33200.0,77.57139059 +2023-11-16 22:00:00,33200.0,33486.0,33200.0,33330.0,51.81656252 +2023-11-17 00:00:00,33357.0,33710.0,33286.0,33691.0,14.41082379 +2023-11-17 02:00:00,33700.0,33817.0,33463.0,33644.0,5.4830411 +2023-11-17 04:00:00,33651.0,33685.0,33354.0,33505.0,13.91662347 +2023-11-17 06:00:00,33523.0,33612.0,33408.0,33456.0,25.39320334 +2023-11-17 08:00:00,33441.0,33634.0,33402.0,33479.0,24.54059636 +2023-11-17 10:00:00,33468.0,33591.0,33256.0,33503.0,53.22868312 +2023-11-17 12:00:00,33503.0,33712.0,33399.0,33478.0,26.58610559 +2023-11-17 14:00:00,33477.0,33502.0,33017.0,33119.0,86.91774982 +2023-11-17 16:00:00,33129.0,33826.0,33023.0,33543.0,87.17477961 +2023-11-17 18:00:00,33532.0,33590.0,33269.0,33324.0,34.56357301 +2023-11-17 20:00:00,33362.0,33510.0,33322.0,33381.0,27.13670251 +2023-11-17 22:00:00,33393.0,33668.0,33390.0,33600.0,19.15129966 +2023-11-18 00:00:00,33599.0,33599.0,33384.0,33416.0,2.88751369 +2023-11-18 02:00:00,33394.0,33448.0,33357.0,33363.0,1.2064717 +2023-11-18 04:00:00,33370.0,33427.0,33309.0,33354.0,2.41891966 +2023-11-18 06:00:00,33352.0,33445.0,33201.0,33411.0,14.43495124 +2023-11-18 08:00:00,33411.0,33493.0,33379.0,33400.0,12.57819365 +2023-11-18 10:00:00,33400.0,33559.0,33398.0,33435.0,15.65258552 +2023-11-18 12:00:00,33409.0,33510.0,33372.0,33465.0,9.11013904 +2023-11-18 14:00:00,33465.0,33680.0,33428.0,33675.0,18.44790689 +2023-11-18 16:00:00,33675.0,33826.0,33594.0,33630.0,27.51868022 +2023-11-18 18:00:00,33609.0,33777.0,33601.0,33685.0,18.16638026 +2023-11-18 20:00:00,33671.0,33720.0,33541.0,33552.0,14.50199976 +2023-11-18 22:00:00,33552.0,33596.0,33447.0,33592.0,7.07371475 +2023-11-19 00:00:00,33598.0,33599.0,33421.0,33521.0,3.78380011 +2023-11-19 02:00:00,33521.0,33535.0,33429.0,33535.0,0.74875769 +2023-11-19 04:00:00,33499.0,33562.0,33484.0,33509.0,2.33921678 +2023-11-19 06:00:00,33526.0,33657.0,33504.0,33600.0,8.89550296 +2023-11-19 08:00:00,33600.0,33711.0,33582.0,33646.0,15.39231321 +2023-11-19 10:00:00,33648.0,33655.0,33410.0,33475.0,19.55930062 +2023-11-19 12:00:00,33461.0,33534.0,33432.0,33515.0,11.03604698 +2023-11-19 14:00:00,33515.0,33594.0,33395.0,33594.0,13.25700723 +2023-11-19 16:00:00,33593.0,33654.0,33519.0,33621.0,17.35088271 +2023-11-19 18:00:00,33626.0,33954.0,33591.0,33945.0,45.75325725 +2023-11-19 20:00:00,33954.0,34016.0,33782.0,33927.0,33.66589987 +2023-11-19 22:00:00,33962.0,34400.0,33871.0,34286.0,34.57708667 +2023-11-20 00:00:00,34277.0,34316.0,34097.0,34199.0,15.89709856 +2023-11-20 02:00:00,34207.0,34225.0,33947.0,34011.0,5.78185277 +2023-11-20 04:00:00,34016.0,34112.0,33928.0,34033.0,8.07976995 +2023-11-20 06:00:00,34057.0,34174.0,33980.0,34133.0,20.64046019 +2023-11-20 08:00:00,34149.0,34164.0,33944.0,34056.0,24.75530271 +2023-11-20 10:00:00,34050.0,34285.0,34004.0,34055.0,39.22427578 +2023-11-20 12:00:00,34049.0,34116.0,33944.0,33996.0,23.46596322 +2023-11-20 14:00:00,33971.0,34305.0,33700.0,34273.0,45.55203643 +2023-11-20 16:00:00,34294.0,34555.0,33721.0,34395.0,90.64672418 +2023-11-20 18:00:00,34396.0,34517.0,34097.0,34356.0,59.47262279 +2023-11-20 20:00:00,34376.0,34392.0,34100.0,34206.0,24.74621545 +2023-11-20 22:00:00,34207.0,34384.0,34171.0,34238.0,22.93437362 +2023-11-21 00:00:00,34238.0,34384.0,34111.0,34356.0,5.22694162 +2023-11-21 02:00:00,34384.0,34384.0,34169.0,34215.0,3.11243756 +2023-11-21 04:00:00,34226.0,34228.0,34076.0,34136.0,10.53292724 +2023-11-21 06:00:00,34137.0,34185.0,34001.0,34062.0,15.57503446 +2023-11-21 08:00:00,34045.0,34222.0,34022.0,34128.0,23.81132444 +2023-11-21 10:00:00,34116.0,34193.0,33970.0,33982.0,24.79320806 +2023-11-21 12:00:00,34005.0,34028.0,33821.0,33821.0,40.13306896 +2023-11-21 14:00:00,33841.0,34000.0,33151.0,33815.0,221.73713016 +2023-11-21 16:00:00,33829.0,34368.0,33538.0,33789.0,147.77064524 +2023-11-21 18:00:00,33816.0,34015.0,33625.0,33870.0,74.53084758 +2023-11-21 20:00:00,33896.0,34060.0,33636.0,33745.0,47.01747128 +2023-11-21 22:00:00,33767.0,33824.0,32781.0,32781.0,161.48344908 +2023-11-22 00:00:00,32779.0,33166.0,32666.0,33085.0,39.91797318 +2023-11-22 02:00:00,33080.0,33362.0,33032.0,33335.0,11.75807378 +2023-11-22 04:00:00,33350.0,33445.0,33305.0,33346.0,10.71386333 +2023-11-22 06:00:00,33346.0,33600.0,33346.0,33405.0,23.5381283 +2023-11-22 08:00:00,33409.0,33672.0,33386.0,33652.0,30.35242135 +2023-11-22 10:00:00,33672.0,33747.0,33424.0,33448.0,31.91292309 +2023-11-22 12:00:00,33453.0,33650.0,33402.0,33623.0,31.17650448 +2023-11-22 14:00:00,33614.0,33721.0,33355.0,33601.0,50.04679022 +2023-11-22 16:00:00,33601.0,33687.0,33480.0,33612.0,29.94334033 +2023-11-22 18:00:00,33639.0,34385.0,33607.0,34272.0,167.25657408 +2023-11-22 20:00:00,34248.0,34759.0,34196.0,34533.0,102.56642255 +2023-11-22 22:00:00,34549.0,34677.0,34161.0,34358.0,70.40905984 +2023-11-23 00:00:00,34363.0,34469.0,34251.0,34355.0,15.03511379 +2023-11-23 02:00:00,34351.0,34372.0,34179.0,34228.0,6.5044358 +2023-11-23 04:00:00,34219.0,34336.0,34186.0,34236.0,12.78140665 +2023-11-23 06:00:00,34236.0,34294.0,34140.0,34262.0,23.23372605 +2023-11-23 08:00:00,34262.0,34512.0,34226.0,34482.0,50.83502322 +2023-11-23 10:00:00,34479.0,34482.0,34067.0,34264.0,29.06333144 +2023-11-23 12:00:00,34265.0,34408.0,34146.0,34175.0,25.56484734 +2023-11-23 14:00:00,34180.0,34259.0,33843.0,33929.0,37.06196629 +2023-11-23 16:00:00,33910.0,34175.0,33852.0,34121.0,23.86231786 +2023-11-23 18:00:00,34120.0,34265.0,34099.0,34229.0,21.12902396 +2023-11-23 20:00:00,34202.0,34300.0,34164.0,34192.0,21.31560431 +2023-11-23 22:00:00,34201.0,34300.0,34150.0,34233.0,16.32677493 +2023-11-24 00:00:00,34237.0,34400.0,34191.0,34309.0,10.30316661 +2023-11-24 02:00:00,34309.0,34386.0,34256.0,34256.0,7.78556084 +2023-11-24 04:00:00,34273.0,34328.0,34221.0,34326.0,6.4089915 +2023-11-24 06:00:00,34332.0,34467.0,34254.0,34439.0,22.76193927 +2023-11-24 08:00:00,34439.0,34600.0,34293.0,34500.0,36.75731372 +2023-11-24 10:00:00,34525.0,34900.0,34450.0,34633.0,104.73097674 +2023-11-24 12:00:00,34624.0,34784.0,34500.0,34615.0,55.52225633 +2023-11-24 14:00:00,34585.0,35135.0,34454.0,34952.0,131.09823519 +2023-11-24 16:00:00,34949.0,35100.0,34408.0,34640.0,85.5898527 +2023-11-24 18:00:00,34645.0,34677.0,34387.0,34547.0,31.15077928 +2023-11-24 20:00:00,34539.0,34711.0,34515.0,34616.0,20.58461285 +2023-11-24 22:00:00,34630.0,34631.0,34400.0,34514.0,13.74881892 +2023-11-25 00:00:00,34497.0,34605.0,34477.0,34588.0,2.47574299 +2023-11-25 02:00:00,34583.0,34626.0,34498.0,34583.0,2.53629712 +2023-11-25 04:00:00,34586.0,34612.0,34507.0,34608.0,1.35942814 +2023-11-25 06:00:00,34608.0,34638.0,34526.0,34604.0,7.74807816 +2023-11-25 08:00:00,34597.0,34623.0,34495.0,34539.0,23.42780251 +2023-11-25 10:00:00,34550.0,34617.0,34415.0,34465.0,33.6042387 +2023-11-25 12:00:00,34465.0,34553.0,34453.0,34542.0,12.28312054 +2023-11-25 14:00:00,34542.0,34553.0,34446.0,34527.0,12.88835849 +2023-11-25 16:00:00,34528.0,34634.0,34512.0,34594.0,14.37781548 +2023-11-25 18:00:00,34580.0,34652.0,34564.0,34624.0,13.2612731 +2023-11-25 20:00:00,34610.0,34687.0,34551.0,34589.0,16.7763644 +2023-11-25 22:00:00,34581.0,34634.0,34532.0,34577.0,8.82554782 +2023-11-26 00:00:00,34575.0,34599.0,34505.0,34520.0,1.73907822 +2023-11-26 02:00:00,34507.0,34567.0,34505.0,34547.0,1.23914368 +2023-11-26 04:00:00,34548.0,34588.0,34516.0,34587.0,0.92461084 +2023-11-26 06:00:00,34585.0,34600.0,34532.0,34593.0,8.43229692 +2023-11-26 08:00:00,34589.0,34611.0,34533.0,34548.0,10.61619914 +2023-11-26 10:00:00,34572.0,34578.0,34483.0,34494.0,11.0622024 +2023-11-26 12:00:00,34494.0,34496.0,34200.0,34340.0,38.03609609 +2023-11-26 14:00:00,34341.0,34354.0,34125.0,34261.0,29.26232138 +2023-11-26 16:00:00,34281.0,34343.0,34023.0,34148.0,38.898849 +2023-11-26 18:00:00,34148.0,34262.0,34056.0,34240.0,24.19349882 +2023-11-26 20:00:00,34235.0,34500.0,34225.0,34477.0,32.96699294 +2023-11-26 22:00:00,34450.0,34573.0,34124.0,34264.0,19.23433987 +2023-11-27 00:00:00,34253.0,34389.0,34211.0,34289.0,3.07861251 +2023-11-27 02:00:00,34270.0,34294.0,34075.0,34115.0,5.99479446 +2023-11-27 04:00:00,34119.0,34209.0,34079.0,34116.0,14.41595643 +2023-11-27 06:00:00,34106.0,34212.0,33932.0,34075.0,25.0727331 +2023-11-27 08:00:00,34102.0,34257.0,34073.0,34200.0,28.73842833 +2023-11-27 10:00:00,34191.0,34191.0,33800.0,33837.0,54.76243116 +2023-11-27 12:00:00,33839.0,33919.0,33644.0,33774.0,54.73150483 +2023-11-27 14:00:00,33792.0,33921.0,33621.0,33673.0,66.12685619 +2023-11-27 16:00:00,33673.0,34024.0,33650.0,33771.0,46.30133606 +2023-11-27 18:00:00,33793.0,33927.0,33613.0,33701.0,42.5066341 +2023-11-27 20:00:00,33688.0,33850.0,33600.0,33828.0,23.88389712 +2023-11-27 22:00:00,33832.0,34038.0,33758.0,33982.0,12.10556026 +2023-11-28 00:00:00,34011.0,34103.0,33933.0,33980.0,7.36992512 +2023-11-28 02:00:00,33971.0,33974.0,33870.0,33893.0,1.43324874 +2023-11-28 04:00:00,33921.0,33938.0,33700.0,33713.0,3.5289831 +2023-11-28 06:00:00,33733.0,33991.0,33702.0,33962.0,11.23752548 +2023-11-28 08:00:00,33935.0,33967.0,33759.0,33872.0,23.24325451 +2023-11-28 10:00:00,33863.0,34069.0,33789.0,34045.0,19.23372766 +2023-11-28 12:00:00,34052.0,34183.0,33933.0,34129.0,24.93105278 +2023-11-28 14:00:00,34122.0,34209.0,34012.0,34180.0,26.52716893 +2023-11-28 16:00:00,34198.0,34800.0,34198.0,34785.0,112.72155663 +2023-11-28 18:00:00,34799.0,34930.0,34501.0,34710.0,107.49019208 +2023-11-28 20:00:00,34737.0,34892.0,34517.0,34557.0,46.97209832 +2023-11-28 22:00:00,34550.0,34631.0,34288.0,34403.0,25.87470109 +2023-11-29 00:00:00,34408.0,34623.0,34300.0,34514.0,5.22033557 +2023-11-29 02:00:00,34506.0,34577.0,34407.0,34498.0,2.36370095 +2023-11-29 04:00:00,34544.0,34605.0,34450.0,34605.0,9.57300665 +2023-11-29 06:00:00,34605.0,34779.0,34548.0,34698.0,23.42228561 +2023-11-29 08:00:00,34731.0,35000.0,34681.0,34896.0,83.6251041 +2023-11-29 10:00:00,34892.0,34919.0,34581.0,34727.0,36.98537835 +2023-11-29 12:00:00,34703.0,34882.0,34675.0,34748.0,45.29931625 +2023-11-29 14:00:00,34766.0,34832.0,34300.0,34511.0,61.7167494 +2023-11-29 16:00:00,34497.0,34538.0,34350.0,34445.0,29.35767234 +2023-11-29 18:00:00,34445.0,34550.0,34337.0,34519.0,25.4223085 +2023-11-29 20:00:00,34523.0,34552.0,34304.0,34403.0,32.03995457 +2023-11-29 22:00:00,34429.0,34539.0,34408.0,34527.0,6.32020981 +2023-11-30 00:00:00,34528.0,34528.0,34361.0,34425.0,9.62531747 +2023-11-30 02:00:00,34397.0,34691.0,34383.0,34665.0,2.49609777 +2023-11-30 04:00:00,34695.0,34770.0,34519.0,34559.0,9.72568621 +2023-11-30 06:00:00,34558.0,34599.0,34429.0,34514.0,9.67714788 +2023-11-30 08:00:00,34535.0,34557.0,34418.0,34522.0,23.56143999 +2023-11-30 10:00:00,34523.0,34735.0,34505.0,34730.0,23.48569771 +2023-11-30 12:00:00,34711.0,34749.0,34499.0,34587.0,22.02529866 +2023-11-30 14:00:00,34586.0,34641.0,34404.0,34505.0,34.41419369 +2023-11-30 16:00:00,34504.0,34684.0,34426.0,34683.0,18.84331134 +2023-11-30 18:00:00,34663.0,34740.0,34615.0,34695.0,23.38359904 +2023-11-30 20:00:00,34692.0,34736.0,34623.0,34662.0,12.05969094 +2023-11-30 22:00:00,34662.0,34750.0,34539.0,34650.0,12.60174578 +2023-12-01 00:00:00,34647.0,34800.0,34522.0,34800.0,6.30389691 +2023-12-01 02:00:00,34800.0,34900.0,34721.0,34893.0,9.91146034 +2023-12-01 04:00:00,34897.0,35038.0,34883.0,34940.0,57.3228664 +2023-12-01 06:00:00,34949.0,35179.0,34886.0,35108.0,56.49921078 +2023-12-01 08:00:00,35128.0,35540.0,35106.0,35528.0,146.62572564 +2023-12-01 10:00:00,35540.0,35650.0,35375.0,35435.0,79.34724966 +2023-12-01 12:00:00,35435.0,35469.0,35200.0,35299.0,43.26139451 +2023-12-01 14:00:00,35328.0,35481.0,35201.0,35461.0,30.72857125 +2023-12-01 16:00:00,35461.0,35860.0,35428.0,35679.0,81.92890416 +2023-12-01 18:00:00,35679.0,35748.0,35501.0,35678.0,53.41965415 +2023-12-01 20:00:00,35665.0,35766.0,35598.0,35661.0,32.53073594 +2023-12-01 22:00:00,35656.0,35726.0,35525.0,35561.0,24.41904908 +2023-12-02 00:00:00,35560.0,35687.0,35524.0,35643.0,7.49622676 +2023-12-02 02:00:00,35647.0,35662.0,35550.0,35632.0,3.32905002 +2023-12-02 04:00:00,35657.0,35702.0,35586.0,35642.0,5.86873192 +2023-12-02 06:00:00,35641.0,35705.0,35576.0,35601.0,9.30171069 +2023-12-02 08:00:00,35601.0,35697.0,35570.0,35676.0,29.89614704 +2023-12-02 10:00:00,35678.0,35690.0,35600.0,35626.0,13.72621692 +2023-12-02 12:00:00,35644.0,35747.0,35614.0,35683.0,19.30503295 +2023-12-02 14:00:00,35709.0,35731.0,35600.0,35707.0,15.15164909 +2023-12-02 16:00:00,35675.0,35705.0,35582.0,35674.0,14.46792772 +2023-12-02 18:00:00,35651.0,36399.0,35651.0,36234.0,139.02698184 +2023-12-02 20:00:00,36222.0,36498.0,36093.0,36385.0,74.66767484 +2023-12-02 22:00:00,36409.0,36417.0,36097.0,36275.0,43.10858398 +2023-12-03 00:00:00,36277.0,36340.0,36197.0,36265.0,11.70204567 +2023-12-03 02:00:00,36296.0,36345.0,36087.0,36167.0,5.83189899 +2023-12-03 04:00:00,36190.0,36262.0,36142.0,36212.0,8.2245048 +2023-12-03 06:00:00,36243.0,36336.0,36187.0,36274.0,16.55395163 +2023-12-03 08:00:00,36312.0,36321.0,36205.0,36292.0,22.97702637 +2023-12-03 10:00:00,36265.0,36372.0,36238.0,36311.0,28.55779294 +2023-12-03 12:00:00,36312.0,36520.0,36201.0,36449.0,46.85782699 +2023-12-03 14:00:00,36448.0,36588.0,36314.0,36551.0,38.42907214 +2023-12-03 16:00:00,36530.0,36602.0,36300.0,36346.0,43.28130265 +2023-12-03 18:00:00,36351.0,36426.0,36295.0,36371.0,26.00163589 +2023-12-03 20:00:00,36399.0,36569.0,36360.0,36529.0,21.5443433 +2023-12-03 22:00:00,36530.0,36998.0,36483.0,36717.0,102.35965351 +2023-12-04 00:00:00,36722.0,37600.0,36721.0,37342.0,69.96892518 +2023-12-04 02:00:00,37341.0,37579.0,37200.0,37415.0,18.98013842 +2023-12-04 04:00:00,37443.0,38226.0,37419.0,38184.0,88.44533258 +2023-12-04 06:00:00,38199.0,38380.0,38010.0,38199.0,126.09297819 +2023-12-04 08:00:00,38179.0,38476.0,38050.0,38203.0,141.76687623 +2023-12-04 10:00:00,38205.0,38797.0,37967.0,38303.0,283.69107157 +2023-12-04 12:00:00,38303.0,38597.0,38194.0,38450.0,107.76873552 +2023-12-04 14:00:00,38465.0,38555.0,38067.0,38187.0,114.90232384 +2023-12-04 16:00:00,38186.0,38587.0,38085.0,38414.0,62.24584371 +2023-12-04 18:00:00,38439.0,38830.0,38318.0,38747.0,105.79751079 +2023-12-04 20:00:00,38777.0,38830.0,38501.0,38777.0,63.10336584 +2023-12-04 22:00:00,38806.0,39150.0,38567.0,38736.0,91.9898032 +2023-12-05 00:00:00,38754.0,38754.0,38405.0,38593.0,22.89774557 +2023-12-05 02:00:00,38576.0,38585.0,38401.0,38569.0,8.85769799 +2023-12-05 04:00:00,38591.0,38672.0,38460.0,38648.0,18.03288908 +2023-12-05 06:00:00,38647.0,38663.0,38299.0,38433.0,54.24703208 +2023-12-05 08:00:00,38433.0,38530.0,38271.0,38516.0,43.76137631 +2023-12-05 10:00:00,38488.0,38593.0,38350.0,38580.0,38.10645793 +2023-12-05 12:00:00,38580.0,38891.0,38539.0,38602.0,59.76651047 +2023-12-05 14:00:00,38602.0,39290.0,38600.0,39105.0,121.72297463 +2023-12-05 16:00:00,39106.0,40800.0,38969.0,40178.0,330.14350797 +2023-12-05 18:00:00,40178.0,40960.0,40109.0,40628.0,213.48206042 +2023-12-05 20:00:00,40606.0,40950.0,40186.0,40647.0,148.09592514 +2023-12-05 22:00:00,40664.0,41200.0,40565.0,40848.0,139.48406312 +2023-12-06 00:00:00,40835.0,40902.0,40566.0,40644.0,33.64330754 +2023-12-06 02:00:00,40668.0,40709.0,40365.0,40500.0,16.72742059 +2023-12-06 04:00:00,40501.0,40637.0,40307.0,40441.0,34.12500163 +2023-12-06 06:00:00,40444.0,40569.0,40241.0,40475.0,74.24823638 +2023-12-06 08:00:00,40499.0,40789.0,40447.0,40642.0,88.84207305 +2023-12-06 10:00:00,40672.0,41051.0,40173.0,40663.0,124.85572687 +2023-12-06 12:00:00,40693.0,41048.0,40620.0,40870.0,77.03681726 +2023-12-06 14:00:00,40871.0,41004.0,40569.0,40617.0,83.731306 +2023-12-06 16:00:00,40627.0,40933.0,40546.0,40807.0,56.3307515 +2023-12-06 18:00:00,40818.0,40986.0,40672.0,40836.0,49.0944978 +2023-12-06 20:00:00,40837.0,40963.0,40502.0,40695.0,88.19835656 +2023-12-06 22:00:00,40720.0,40863.0,40500.0,40666.0,39.53546098 +2023-12-07 00:00:00,40666.0,40800.0,40571.0,40787.0,12.00373765 +2023-12-07 02:00:00,40800.0,40878.0,40773.0,40842.0,7.39261913 +2023-12-07 04:00:00,40840.0,40950.0,40797.0,40910.0,12.14983124 +2023-12-07 06:00:00,40910.0,40925.0,40706.0,40735.0,25.77954207 +2023-12-07 08:00:00,40735.0,40750.0,38633.0,40219.0,296.25808813 +2023-12-07 10:00:00,40226.0,40315.0,39920.0,40096.0,110.66559348 +2023-12-07 12:00:00,40095.0,40428.0,39922.0,40144.0,80.96792011 +2023-12-07 14:00:00,40126.0,40735.0,40100.0,40517.0,81.8637369 +2023-12-07 16:00:00,40511.0,40589.0,39964.0,40145.0,67.46918308 +2023-12-07 18:00:00,40160.0,40254.0,39857.0,40031.0,78.40047579 +2023-12-07 20:00:00,40031.0,40289.0,39889.0,40182.0,56.92521319 +2023-12-07 22:00:00,40189.0,40248.0,39965.0,40114.0,36.87735688 +2023-12-08 00:00:00,40145.0,40269.0,40112.0,40269.0,11.85976054 +2023-12-08 02:00:00,40268.0,40378.0,40200.0,40214.0,6.94259844 +2023-12-08 04:00:00,40215.0,40382.0,40182.0,40293.0,14.58844254 +2023-12-08 06:00:00,40268.0,40365.0,40014.0,40066.0,42.53104371 +2023-12-08 08:00:00,40065.0,40194.0,40003.0,40055.0,48.98455564 +2023-12-08 10:00:00,40055.0,40587.0,40000.0,40506.0,56.8369412 +2023-12-08 12:00:00,40490.0,40676.0,40348.0,40548.0,88.96235927 +2023-12-08 14:00:00,40577.0,40970.0,40549.0,40670.0,78.17724682 +2023-12-08 16:00:00,40670.0,40898.0,40625.0,40693.0,61.48165793 +2023-12-08 18:00:00,40696.0,40902.0,40660.0,40857.0,36.80500073 +2023-12-08 20:00:00,40875.0,41619.0,40856.0,41416.0,164.52333537 +2023-12-08 22:00:00,41412.0,41468.0,41011.0,41095.0,65.42634661 +2023-12-09 00:00:00,41075.0,41200.0,40954.0,41025.0,17.78456498 +2023-12-09 02:00:00,41036.0,41144.0,40996.0,41030.0,10.44823961 +2023-12-09 04:00:00,41066.0,41251.0,41038.0,41170.0,15.81046644 +2023-12-09 06:00:00,41194.0,41248.0,41008.0,41113.0,50.63578306 +2023-12-09 08:00:00,41107.0,41119.0,40654.0,40812.0,93.67286418 +2023-12-09 10:00:00,40808.0,40869.0,40714.0,40779.0,30.20408036 +2023-12-09 12:00:00,40749.0,41017.0,40682.0,40937.0,48.21626697 +2023-12-09 14:00:00,40974.0,41103.0,40706.0,40967.0,53.62941519 +2023-12-09 16:00:00,40994.0,41042.0,40789.0,40789.0,34.01881656 +2023-12-09 18:00:00,40789.0,40940.0,40789.0,40859.0,28.6874996 +2023-12-09 20:00:00,40873.0,40990.0,40761.0,40870.0,25.17321288 +2023-12-09 22:00:00,40870.0,40955.0,40515.0,40626.0,29.41441369 +2023-12-10 00:00:00,40661.0,40791.0,40601.0,40706.0,17.39516427 +2023-12-10 02:00:00,40732.0,40775.0,40632.0,40775.0,10.01136431 +2023-12-10 04:00:00,40764.0,40878.0,40732.0,40784.0,8.46553261 +2023-12-10 06:00:00,40811.0,40904.0,40759.0,40856.0,18.15122878 +2023-12-10 08:00:00,40882.0,40945.0,40500.0,40510.0,37.20636545 +2023-12-10 10:00:00,40511.0,40691.0,40508.0,40654.0,42.76055904 +2023-12-10 12:00:00,40645.0,40834.0,40637.0,40769.0,33.09026857 +2023-12-10 14:00:00,40769.0,40900.0,40708.0,40833.0,33.40439283 +2023-12-10 16:00:00,40837.0,40837.0,40693.0,40734.0,33.24235425 +2023-12-10 18:00:00,40733.0,40841.0,40687.0,40750.0,21.29606715 +2023-12-10 20:00:00,40740.0,40950.0,40696.0,40717.0,50.31747269 +2023-12-10 22:00:00,40716.0,40823.0,40481.0,40706.0,34.12281683 +2023-12-11 00:00:00,40708.0,40712.0,40131.0,40205.0,24.01758319 +2023-12-11 02:00:00,40157.0,40173.0,37555.0,39335.0,148.24902035 +2023-12-11 04:00:00,39324.0,39363.0,38694.0,39096.0,78.75775616 +2023-12-11 06:00:00,39107.0,39368.0,38750.0,39189.0,138.18537774 +2023-12-11 08:00:00,39195.0,39472.0,39013.0,39411.0,104.73637713 +2023-12-11 10:00:00,39411.0,39480.0,39175.0,39371.0,70.78011111 +2023-12-11 12:00:00,39361.0,39395.0,38912.0,39007.0,86.89898484 +2023-12-11 14:00:00,39019.0,39120.0,38774.0,38891.0,113.71289078 +2023-12-11 16:00:00,38887.0,38932.0,38392.0,38414.0,218.19602593 +2023-12-11 18:00:00,38437.0,38437.0,37301.0,37832.0,465.82602321 +2023-12-11 20:00:00,37827.0,38375.0,37619.0,38312.0,225.11204796 +2023-12-11 22:00:00,38310.0,38452.0,38221.0,38320.0,82.09207837 +2023-12-12 00:00:00,38312.0,38927.0,38244.0,38686.0,56.6750132 +2023-12-12 02:00:00,38713.0,38948.0,38701.0,38763.0,33.36570137 +2023-12-12 04:00:00,38760.0,38774.0,38431.0,38614.0,53.70742159 +2023-12-12 06:00:00,38614.0,39094.0,38439.0,38948.0,107.83327701 +2023-12-12 08:00:00,38948.0,39043.0,38733.0,38740.0,96.89624208 +2023-12-12 10:00:00,38727.0,38761.0,38472.0,38503.0,73.66362059 +2023-12-12 12:00:00,38513.0,38898.0,38503.0,38780.0,74.57637839 +2023-12-12 14:00:00,38780.0,38825.0,38137.0,38340.0,102.36832854 +2023-12-12 16:00:00,38343.0,38428.0,37682.0,37691.0,131.59532006 +2023-12-12 18:00:00,37681.0,38377.0,37672.0,38118.0,120.72425726 +2023-12-12 20:00:00,38119.0,38300.0,38014.0,38071.0,64.38677488 +2023-12-12 22:00:00,38074.0,38481.0,38050.0,38390.0,32.62775144 +2023-12-13 00:00:00,38425.0,38438.0,37928.0,38049.0,16.95885016 +2023-12-13 02:00:00,38018.0,38108.0,37700.0,37840.0,28.52320727 +2023-12-13 04:00:00,37811.0,38012.0,37664.0,37998.0,44.41371527 +2023-12-13 06:00:00,38009.0,38221.0,37819.0,38092.0,58.75087021 +2023-12-13 08:00:00,38104.0,38289.0,38065.0,38192.0,45.86711539 +2023-12-13 10:00:00,38188.0,38243.0,37967.0,38018.0,39.92777858 +2023-12-13 12:00:00,38011.0,38422.0,37996.0,38405.0,62.043021 +2023-12-13 14:00:00,38406.0,38888.0,38254.0,38847.0,103.1434111 +2023-12-13 16:00:00,38847.0,39150.0,38672.0,39074.0,141.02657116 +2023-12-13 18:00:00,39076.0,39497.0,38934.0,39288.0,175.98353347 +2023-12-13 20:00:00,39301.0,39783.0,39170.0,39562.0,111.93574731 +2023-12-13 22:00:00,39569.0,40500.0,39430.0,39430.0,92.0002164 +2023-12-14 00:00:00,39439.0,39501.0,39195.0,39338.0,25.26944772 +2023-12-14 02:00:00,39346.0,39368.0,39141.0,39197.0,16.97623941 +2023-12-14 04:00:00,39200.0,39326.0,39178.0,39326.0,34.44209579 +2023-12-14 06:00:00,39324.0,39594.0,39279.0,39461.0,39.35749287 +2023-12-14 08:00:00,39465.0,39532.0,39203.0,39373.0,37.16042789 +2023-12-14 10:00:00,39373.0,39678.0,39256.0,39615.0,48.49902292 +2023-12-14 12:00:00,39609.0,39682.0,38255.0,38939.0,122.58297178 +2023-12-14 14:00:00,38938.0,39042.0,38475.0,38634.0,70.18733827 +2023-12-14 16:00:00,38645.0,39474.0,38637.0,39292.0,61.15380471 +2023-12-14 18:00:00,39285.0,39302.0,38967.0,39237.0,45.93065187 +2023-12-14 20:00:00,39233.0,39273.0,38989.0,39114.0,49.49534222 +2023-12-14 22:00:00,39122.0,39298.0,39070.0,39143.0,20.5104147 +2023-12-15 00:00:00,39151.0,39235.0,39048.0,39115.0,15.77815038 +2023-12-15 02:00:00,39128.0,39150.0,38700.0,38920.0,9.31484639 +2023-12-15 04:00:00,38918.0,38999.0,38758.0,38796.0,9.88720171 +2023-12-15 06:00:00,38793.0,38913.0,38727.0,38865.0,32.97599457 +2023-12-15 08:00:00,38869.0,39277.0,38791.0,39083.0,61.8108318 +2023-12-15 10:00:00,39097.0,39139.0,38972.0,39015.0,20.62707374 +2023-12-15 12:00:00,39019.0,39039.0,38682.0,38747.0,33.4916964 +2023-12-15 14:00:00,38756.0,38836.0,38222.0,38399.0,79.68008203 +2023-12-15 16:00:00,38399.0,38579.0,38251.0,38360.0,40.42959278 +2023-12-15 18:00:00,38363.0,38740.0,38344.0,38657.0,29.08617587 +2023-12-15 20:00:00,38646.0,38811.0,38636.0,38784.0,30.73533427 +2023-12-15 22:00:00,38800.0,38811.0,38484.0,38507.0,19.80531484 +2023-12-16 00:00:00,38517.0,38700.0,38255.0,38628.0,15.21899827 +2023-12-16 02:00:00,38638.0,38918.0,38638.0,38887.0,7.89049608 +2023-12-16 04:00:00,38871.0,38884.0,38753.0,38803.0,5.13856013 +2023-12-16 06:00:00,38814.0,38855.0,38712.0,38783.0,9.42776342 +2023-12-16 08:00:00,38792.0,38847.0,38682.0,38774.0,18.29405208 +2023-12-16 10:00:00,38780.0,38891.0,38764.0,38883.0,20.13727735 +2023-12-16 12:00:00,38886.0,39085.0,38813.0,38952.0,23.71228108 +2023-12-16 14:00:00,38952.0,39136.0,38872.0,39125.0,33.31889102 +2023-12-16 16:00:00,39138.0,39292.0,39005.0,39030.0,39.68804238 +2023-12-16 18:00:00,39041.0,39053.0,38846.0,38900.0,33.72616285 +2023-12-16 20:00:00,38900.0,38948.0,38816.0,38839.0,17.10816519 +2023-12-16 22:00:00,38845.0,38881.0,38710.0,38812.0,10.59487248 +2023-12-17 00:00:00,38814.0,38837.0,38690.0,38784.0,8.15431376 +2023-12-17 04:00:00,38753.0,38766.0,38381.0,38473.0,16.32342641 +2023-12-17 06:00:00,38484.0,38605.0,38390.0,38475.0,20.28677779 +2023-12-17 08:00:00,38474.0,38561.0,38300.0,38552.0,33.7888731 +2023-12-17 10:00:00,38558.0,38585.0,38420.0,38525.0,26.35664167 +2023-12-17 12:00:00,38524.0,38568.0,38361.0,38440.0,24.56474893 +2023-12-17 14:00:00,38440.0,38518.0,38175.0,38404.0,48.9583251 +2023-12-17 16:00:00,38403.0,38950.0,38294.0,38655.0,44.55773025 +2023-12-17 18:00:00,38655.0,38761.0,38387.0,38645.0,30.66394416 +2023-12-17 20:00:00,38643.0,38725.0,38443.0,38465.0,29.151048 +2023-12-17 22:00:00,38465.0,38473.0,37903.0,37979.0,65.13259986 +2023-12-18 00:00:00,37983.0,38053.0,37546.0,37619.0,41.44572665 +2023-12-18 02:00:00,37609.0,37716.0,37428.0,37648.0,46.90674506 +2023-12-18 04:00:00,37648.0,37751.0,37555.0,37555.0,34.84293389 +2023-12-18 06:00:00,37558.0,37833.0,37552.0,37642.0,55.74320417 +2023-12-18 08:00:00,37650.0,37759.0,37330.0,37563.0,109.76070783 +2023-12-18 10:00:00,37562.0,37776.0,37143.0,37644.0,121.79308824 +2023-12-18 12:00:00,37644.0,37900.0,37451.0,37853.0,62.21621904 +2023-12-18 14:00:00,37852.0,38209.0,37751.0,37811.0,66.45602622 +2023-12-18 16:00:00,37824.0,38127.0,37689.0,37876.0,39.78196116 +2023-12-18 18:00:00,37875.0,38226.0,37844.0,38211.0,37.95364562 +2023-12-18 20:00:00,38210.0,39140.0,38100.0,39019.0,120.31354848 +2023-12-18 22:00:00,39028.0,39123.0,38868.0,39056.0,81.28607912 +2023-12-19 00:00:00,39054.0,39686.0,38952.0,39622.0,52.53548061 +2023-12-19 02:00:00,39632.0,39767.0,39311.0,39389.0,20.34554384 +2023-12-19 04:00:00,39389.0,39437.0,39202.0,39284.0,25.49006042 +2023-12-19 06:00:00,39286.0,39448.0,39158.0,39379.0,44.73271453 +2023-12-19 08:00:00,39384.0,39520.0,39261.0,39327.0,79.43358095 +2023-12-19 10:00:00,39328.0,39556.0,39250.0,39302.0,48.80296755 +2023-12-19 12:00:00,39301.0,39332.0,39067.0,39089.0,45.48634937 +2023-12-19 14:00:00,39085.0,39129.0,38447.0,38687.0,91.93100167 +2023-12-19 16:00:00,38687.0,38857.0,38106.0,38125.0,86.69618917 +2023-12-19 18:00:00,38137.0,38713.0,38090.0,38603.0,59.65785033 +2023-12-19 20:00:00,38603.0,38745.0,38421.0,38737.0,36.72449021 +2023-12-19 22:00:00,38737.0,38744.0,38472.0,38524.0,17.43239118 +2023-12-20 00:00:00,38528.0,38733.0,38501.0,38575.0,10.0153624 +2023-12-20 02:00:00,38595.0,38717.0,38501.0,38672.0,6.0703472 +2023-12-20 04:00:00,38671.0,39066.0,38645.0,38952.0,21.3190237 +2023-12-20 06:00:00,38958.0,39256.0,38881.0,39134.0,38.21786457 +2023-12-20 08:00:00,39123.0,39197.0,39000.0,39040.0,49.74200222 +2023-12-20 10:00:00,39045.0,39270.0,38950.0,39181.0,53.25198939 +2023-12-20 12:00:00,39181.0,39940.0,39072.0,39908.0,110.04604429 +2023-12-20 14:00:00,39920.0,40378.0,39750.0,40071.0,219.4419893 +2023-12-20 16:00:00,40083.0,40163.0,39635.0,40124.0,99.74716541 +2023-12-20 18:00:00,40126.0,40355.0,39916.0,39916.0,78.65818479 +2023-12-20 20:00:00,39913.0,39987.0,39434.0,39631.0,91.86699139 +2023-12-20 22:00:00,39636.0,39928.0,39621.0,39860.0,19.60212493 +2023-12-21 00:00:00,39874.0,39906.0,39570.0,39643.0,19.78560742 +2023-12-21 02:00:00,39633.0,39876.0,39529.0,39843.0,10.8036286 +2023-12-21 04:00:00,39848.0,39900.0,39673.0,39715.0,17.44279998 +2023-12-21 06:00:00,39713.0,40090.0,39684.0,39986.0,37.16529392 +2023-12-21 08:00:00,39986.0,40119.0,39833.0,39961.0,44.74527283 +2023-12-21 10:00:00,39961.0,40265.0,39957.0,40040.0,55.6233969 +2023-12-21 12:00:00,40040.0,40273.0,40034.0,40185.0,51.38223724 +2023-12-21 14:00:00,40186.0,40230.0,39555.0,39926.0,83.90827111 +2023-12-21 16:00:00,39944.0,40000.0,39500.0,39561.0,75.1993545 +2023-12-21 18:00:00,39570.0,39951.0,39500.0,39685.0,63.72228256 +2023-12-21 20:00:00,39681.0,40100.0,39660.0,39981.0,64.82699901 +2023-12-21 22:00:00,39985.0,40046.0,39822.0,39905.0,40.93461115 +2023-12-22 00:00:00,39911.0,40235.0,39790.0,40118.0,23.10669375 +2023-12-22 02:00:00,40110.0,40145.0,39926.0,40027.0,16.00688112 +2023-12-22 04:00:00,40031.0,40245.0,39972.0,40168.0,14.79923651 +2023-12-22 06:00:00,40164.0,40417.0,39588.0,39633.0,69.5615224 +2023-12-22 08:00:00,39635.0,39879.0,39521.0,39781.0,84.61992997 +2023-12-22 10:00:00,39773.0,39817.0,39662.0,39784.0,35.14191072 +2023-12-22 12:00:00,39785.0,39818.0,39556.0,39701.0,49.32431506 +2023-12-22 14:00:00,39701.0,39761.0,39453.0,39730.0,62.08122695 +2023-12-22 16:00:00,39735.0,39850.0,39575.0,39788.0,33.28043855 +2023-12-22 18:00:00,39783.0,40015.0,39680.0,39692.0,50.76290916 +2023-12-22 20:00:00,39690.0,39832.0,39688.0,39756.0,21.33714869 +2023-12-22 22:00:00,39764.0,40050.0,39726.0,39985.0,27.39166734 +2023-12-23 00:00:00,39985.0,40002.0,39680.0,39680.0,8.96754692 +2023-12-23 02:00:00,39678.0,39725.0,39552.0,39612.0,14.41417614 +2023-12-23 04:00:00,39580.0,39707.0,39400.0,39707.0,19.01747412 +2023-12-23 06:00:00,39698.0,39791.0,39635.0,39667.0,15.76009349 +2023-12-23 08:00:00,39667.0,39800.0,39657.0,39751.0,21.72452542 +2023-12-23 10:00:00,39750.0,39757.0,39650.0,39675.0,20.6540492 +2023-12-23 12:00:00,39680.0,39980.0,39673.0,39853.0,39.71178992 +2023-12-23 14:00:00,39853.0,39946.0,39807.0,39857.0,25.70253774 +2023-12-23 16:00:00,39856.0,39948.0,39814.0,39874.0,22.33824675 +2023-12-23 18:00:00,39871.0,39950.0,39770.0,39779.0,40.43894222 +2023-12-23 20:00:00,39782.0,39863.0,39723.0,39854.0,36.46119902 +2023-12-23 22:00:00,39854.0,39900.0,39800.0,39804.0,42.83926101 +2023-12-24 00:00:00,39803.0,39968.0,39713.0,39858.0,27.54475493 +2023-12-24 02:00:00,39858.0,39983.0,39852.0,39921.0,19.28993454 +2023-12-24 04:00:00,39922.0,40000.0,39520.0,39549.0,24.93167453 +2023-12-24 06:00:00,39561.0,39736.0,39513.0,39732.0,38.14604441 +2023-12-24 08:00:00,39731.0,39809.0,39678.0,39786.0,46.95769285 +2023-12-24 10:00:00,39792.0,39800.0,39534.0,39745.0,48.44841362 +2023-12-24 12:00:00,39746.0,39902.0,39678.0,39893.0,41.24682536 +2023-12-24 14:00:00,39893.0,39992.0,39781.0,39790.0,40.65221456 +2023-12-24 16:00:00,39781.0,39815.0,39678.0,39738.0,21.51143273 +2023-12-24 18:00:00,39735.0,39773.0,39669.0,39733.0,27.25464152 +2023-12-24 20:00:00,39728.0,39730.0,39574.0,39619.0,38.25333833 +2023-12-24 22:00:00,39611.0,39676.0,38943.0,39200.0,138.13998768 +2023-12-25 00:00:00,39196.0,39297.0,38912.0,39245.0,33.04012957 +2023-12-25 02:00:00,39238.0,39340.0,39077.0,39333.0,6.8201253 +2023-12-25 04:00:00,39332.0,39400.0,39280.0,39400.0,11.02565393 +2023-12-25 06:00:00,39407.0,39500.0,39331.0,39376.0,21.20655298 +2023-12-25 08:00:00,39394.0,39496.0,39239.0,39307.0,38.61451787 +2023-12-25 10:00:00,39307.0,39425.0,39256.0,39343.0,34.14520368 +2023-12-25 12:00:00,39343.0,39872.0,39235.0,39711.0,66.05259059 +2023-12-25 14:00:00,39716.0,39799.0,39599.0,39611.0,36.91604292 +2023-12-25 16:00:00,39627.0,39688.0,39435.0,39526.0,33.55937782 +2023-12-25 18:00:00,39527.0,39641.0,39379.0,39483.0,15.41980781 +2023-12-25 20:00:00,39500.0,39581.0,39350.0,39554.0,28.34730982 +2023-12-25 22:00:00,39552.0,40156.0,39518.0,39600.0,77.22565243 +2023-12-26 00:00:00,39601.0,39617.0,39432.0,39517.0,13.65278549 +2023-12-26 02:00:00,39517.0,39529.0,39367.0,39434.0,6.26457689 +2023-12-26 04:00:00,39439.0,39458.0,38741.0,38842.0,49.60528357 +2023-12-26 06:00:00,38841.0,38928.0,38638.0,38865.0,85.89767927 +2023-12-26 08:00:00,38869.0,38890.0,38425.0,38525.0,78.52694986 +2023-12-26 10:00:00,38525.0,38832.0,38490.0,38773.0,71.39373695 +2023-12-26 12:00:00,38773.0,38874.0,38713.0,38791.0,36.437955 +2023-12-26 14:00:00,38794.0,38850.0,38367.0,38425.0,56.90986844 +2023-12-26 16:00:00,38444.0,38485.0,37800.0,38047.0,155.11697782 +2023-12-26 18:00:00,38053.0,38329.0,37877.0,38144.0,70.49447226 +2023-12-26 20:00:00,38143.0,38364.0,38100.0,38364.0,48.90476233 +2023-12-26 22:00:00,38363.0,38608.0,38353.0,38529.0,50.09559127 +2023-12-27 00:00:00,38529.0,38559.0,38362.0,38487.0,14.88122027 +2023-12-27 02:00:00,38484.0,38514.0,38200.0,38295.0,8.13483661 +2023-12-27 04:00:00,38296.0,38470.0,38267.0,38458.0,12.21330476 +2023-12-27 06:00:00,38463.0,38537.0,38390.0,38481.0,15.15291996 +2023-12-27 08:00:00,38481.0,38750.0,38429.0,38703.0,60.1015542 +2023-12-27 10:00:00,38703.0,39116.0,38659.0,38908.0,89.10699095 +2023-12-27 12:00:00,38907.0,38927.0,38606.0,38782.0,36.04586589 +2023-12-27 14:00:00,38782.0,38969.0,38568.0,38748.0,71.45998512 +2023-12-27 16:00:00,38740.0,38900.0,38637.0,38783.0,39.48892465 +2023-12-27 18:00:00,38783.0,38963.0,38712.0,38928.0,53.4832953 +2023-12-27 20:00:00,38932.0,39255.0,38887.0,39097.0,76.20140534 +2023-12-27 22:00:00,39092.0,39375.0,39015.0,39139.0,44.94816875 +2023-12-28 00:00:00,39145.0,39439.0,39096.0,39101.0,30.58642656 +2023-12-28 02:00:00,39096.0,39140.0,39001.0,39089.0,8.84422106 +2023-12-28 04:00:00,39093.0,39300.0,38855.0,38929.0,17.71157951 +2023-12-28 06:00:00,38933.0,38933.0,38563.0,38770.0,45.88352165 +2023-12-28 08:00:00,38771.0,38824.0,38616.0,38746.0,62.15810013 +2023-12-28 10:00:00,38746.0,38910.0,38725.0,38772.0,42.32649298 +2023-12-28 12:00:00,38773.0,38834.0,38387.0,38645.0,71.96251605 +2023-12-28 14:00:00,38651.0,38664.0,38196.0,38225.0,89.14694206 +2023-12-28 16:00:00,38226.0,38544.0,38155.0,38453.0,51.75066054 +2023-12-28 18:00:00,38453.0,38620.0,38371.0,38546.0,39.90117242 +2023-12-28 20:00:00,38545.0,38549.0,38299.0,38403.0,40.28809701 +2023-12-28 22:00:00,38406.0,38664.0,38336.0,38503.0,49.09664504 +2023-12-29 00:00:00,38502.0,38595.0,38010.0,38219.0,76.4158859 +2023-12-29 02:00:00,38219.0,38668.0,38170.0,38595.0,13.95443616 +2023-12-29 04:00:00,38602.0,38647.0,38438.0,38574.0,6.31250085 +2023-12-29 06:00:00,38579.0,38587.0,38166.0,38226.0,27.33696152 +2023-12-29 08:00:00,38232.0,38650.0,38227.0,38623.0,42.37071608 +2023-12-29 10:00:00,38622.0,38861.0,38597.0,38750.0,51.85091465 +2023-12-29 12:00:00,38753.0,38862.0,38671.0,38817.0,38.8612247 +2023-12-29 14:00:00,38822.0,39057.0,38160.0,38383.0,90.89887435 +2023-12-29 16:00:00,38356.0,38447.0,37771.0,37916.0,141.83241472 +2023-12-29 18:00:00,37903.0,38554.0,37877.0,38273.0,66.98738358 +2023-12-29 20:00:00,38273.0,38378.0,38056.0,38093.0,34.00208517 +2023-12-29 22:00:00,38104.0,38387.0,37656.0,38246.0,54.21707383 +2023-12-30 00:00:00,38246.0,38335.0,38201.0,38250.0,11.51887542 +2023-12-30 02:00:00,38250.0,38261.0,37951.0,38085.0,17.69367177 +2023-12-30 04:00:00,38087.0,38450.0,38085.0,38193.0,17.67028915 +2023-12-30 06:00:00,38218.0,38274.0,38080.0,38095.0,15.25889939 +2023-12-30 08:00:00,38105.0,38135.0,37701.0,37850.0,63.51307731 +2023-12-30 10:00:00,37841.0,38173.0,37841.0,38109.0,33.71547479 +2023-12-30 12:00:00,38109.0,38225.0,38048.0,38158.0,48.32463607 +2023-12-30 14:00:00,38156.0,38535.0,38156.0,38490.0,34.04666797 +2023-12-30 16:00:00,38498.0,38699.0,38352.0,38565.0,59.31724068 +2023-12-30 18:00:00,38566.0,38586.0,38416.0,38454.0,30.23121595 +2023-12-30 20:00:00,38469.0,38481.0,38307.0,38404.0,18.0963365 +2023-12-30 22:00:00,38405.0,38433.0,38235.0,38289.0,25.1892697 +2023-12-31 00:00:00,38289.0,38547.0,38288.0,38328.0,9.57847914 +2023-12-31 02:00:00,38307.0,38367.0,38169.0,38294.0,5.41789071 +2023-12-31 04:00:00,38331.0,38442.0,38323.0,38331.0,5.59805347 +2023-12-31 06:00:00,38320.0,38760.0,38301.0,38630.0,19.0593467 +2023-12-31 08:00:00,38640.0,38990.0,38530.0,38845.0,71.70006417 +2023-12-31 10:00:00,38850.0,38900.0,38638.0,38639.0,35.34436862 +2023-12-31 12:00:00,38657.0,38793.0,38485.0,38591.0,26.78237524 +2023-12-31 14:00:00,38591.0,38800.0,38465.0,38550.0,42.22412048 +2023-12-31 16:00:00,38550.0,38767.0,38520.0,38689.0,26.68210016 +2023-12-31 18:00:00,38704.0,38767.0,38625.0,38648.0,24.27727911 +2023-12-31 20:00:00,38650.0,38714.0,38543.0,38543.0,21.29696825 +2023-12-31 22:00:00,38548.0,38800.0,38140.0,38445.0,78.36050378 +2024-01-01 00:00:00,38434.0,38890.0,38426.0,38723.0,37.27727434 +2024-01-01 02:00:00,38723.0,38723.0,38428.0,38493.0,7.95336086 +2024-01-01 04:00:00,38499.0,38846.0,38393.0,38397.0,6.66334972 +2024-01-01 06:00:00,38410.0,38626.0,38375.0,38591.0,11.22705051 +2024-01-01 08:00:00,38604.0,38776.0,38590.0,38735.0,16.45640655 +2024-01-01 10:00:00,38735.0,38813.0,38695.0,38759.0,21.77067941 +2024-01-01 12:00:00,38760.0,38867.0,38728.0,38808.0,27.5083432 +2024-01-01 14:00:00,38808.0,38984.0,38700.0,38975.0,27.21115378 +2024-01-01 16:00:00,38963.0,39000.0,38767.0,38977.0,32.93362898 +2024-01-01 18:00:00,38974.0,39651.0,38935.0,39521.0,103.16797831 +2024-01-01 20:00:00,39523.0,39776.0,39413.0,39544.0,101.06016965 +2024-01-01 22:00:00,39544.0,40084.0,39329.0,40071.0,86.29081994 +2024-01-02 00:00:00,40061.0,41045.0,40039.0,40662.0,137.43676788 +2024-01-02 02:00:00,40674.0,41250.0,40662.0,41184.0,68.7845008 +2024-01-02 04:00:00,41196.0,41237.0,40851.0,40961.0,46.61921546 +2024-01-02 06:00:00,40949.0,41360.0,40852.0,41287.0,118.22213418 +2024-01-02 08:00:00,41291.0,41620.0,41112.0,41507.0,190.16931293 +2024-01-02 10:00:00,41506.0,41594.0,41195.0,41380.0,157.55014656 +2024-01-02 12:00:00,41399.0,41745.0,41288.0,41726.0,113.84256106 +2024-01-02 14:00:00,41714.0,41903.0,40918.0,41346.0,225.27287126 +2024-01-02 16:00:00,41342.0,41477.0,41000.0,41090.0,95.2514022 +2024-01-02 18:00:00,41093.0,41374.0,41001.0,41264.0,73.65945872 +2024-01-02 20:00:00,41269.0,41424.0,40950.0,41424.0,80.31415475 +2024-01-02 22:00:00,41423.0,41527.0,41078.0,41191.0,62.031177 +2024-01-03 00:00:00,41206.0,41662.0,41206.0,41662.0,22.23667807 +2024-01-03 02:00:00,41662.0,41700.0,41273.0,41336.0,24.95721451 +2024-01-03 04:00:00,41345.0,41388.0,41211.0,41290.0,9.50636623 +2024-01-03 06:00:00,41297.0,41474.0,41100.0,41135.0,53.77251602 +2024-01-03 08:00:00,41125.0,41666.0,41125.0,41500.0,56.77261102 +2024-01-03 10:00:00,41516.0,41558.0,39650.0,40078.0,181.20817975 +2024-01-03 12:00:00,40049.0,41750.0,37500.0,39296.0,542.18794221 +2024-01-03 14:00:00,39433.0,40500.0,38700.0,40362.0,213.34835438 +2024-01-03 16:00:00,40352.0,40999.0,39600.0,40225.0,106.53643789 +2024-01-03 18:00:00,40157.0,40449.0,39500.0,39749.0,57.1235192 +2024-01-03 20:00:00,39749.0,39999.0,39557.0,39733.0,15.51185042 +2024-01-03 22:00:00,39733.0,39997.0,39200.0,39511.0,59.99783221 +2024-01-04 00:00:00,39565.0,39700.0,39250.0,39252.0,13.48083815 +2024-01-04 02:00:00,39267.0,39818.0,39253.0,39555.0,14.9004402 +2024-01-04 04:00:00,39620.0,39998.0,39417.0,39839.0,10.12009472 +2024-01-04 06:00:00,39839.0,39950.0,39300.0,39300.0,26.34611435 +2024-01-04 08:00:00,39301.0,39844.0,39216.0,39333.0,73.91817027 +2024-01-04 10:00:00,39332.0,40000.0,39019.0,39549.0,74.26939648 +2024-01-04 12:00:00,39553.0,39872.0,39480.0,39778.0,73.24422528 +2024-01-04 14:00:00,39774.0,40500.0,39633.0,40282.0,125.04844312 +2024-01-04 16:00:00,40281.0,40498.0,40015.0,40291.0,79.76064063 +2024-01-04 18:00:00,40307.0,40725.0,40157.0,40253.0,92.2929466 +2024-01-04 20:00:00,40259.0,40899.0,40207.0,40749.0,101.80267676 +2024-01-04 22:00:00,40755.0,40964.0,40418.0,40461.0,67.29616844 +2024-01-05 00:00:00,40477.0,40653.0,39490.0,39763.0,49.02741054 +2024-01-05 02:00:00,39818.0,40353.0,39724.0,39928.0,12.14235893 +2024-01-05 04:00:00,39917.0,40134.0,39773.0,39997.0,16.46811253 +2024-01-05 06:00:00,39995.0,40410.0,39954.0,40268.0,33.56604471 +2024-01-05 08:00:00,40268.0,40800.0,40250.0,40644.0,49.72819438 +2024-01-05 10:00:00,40644.0,40800.0,40041.0,40523.0,52.50242141 +2024-01-05 12:00:00,40511.0,40605.0,40161.0,40404.0,57.90601411 +2024-01-05 14:00:00,40394.0,40454.0,39600.0,39718.0,111.39070892 +2024-01-05 16:00:00,39691.0,40187.0,39575.0,40059.0,75.83921211 +2024-01-05 18:00:00,40041.0,40310.0,39885.0,39995.0,40.56561555 +2024-01-05 20:00:00,40003.0,40650.0,39960.0,40261.0,49.42510774 +2024-01-05 22:00:00,40269.0,40613.0,40107.0,40455.0,37.90088708 +2024-01-06 00:00:00,40455.0,40500.0,40228.0,40271.0,15.30130319 +2024-01-06 02:00:00,40271.0,40357.0,40131.0,40292.0,10.60986385 +2024-01-06 04:00:00,40292.0,40319.0,39969.0,40057.0,9.28354464 +2024-01-06 06:00:00,40058.0,40062.0,39781.0,40043.0,36.64431765 +2024-01-06 08:00:00,40043.0,40226.0,40018.0,40053.0,32.84690688 +2024-01-06 10:00:00,40053.0,40227.0,40005.0,40096.0,23.95878032 +2024-01-06 12:00:00,40097.0,40267.0,40000.0,40166.0,25.24249946 +2024-01-06 14:00:00,40166.0,40473.0,40157.0,40273.0,28.63068679 +2024-01-06 16:00:00,40273.0,40477.0,40246.0,40356.0,26.43601417 +2024-01-06 18:00:00,40357.0,40490.0,40258.0,40322.0,26.51134352 +2024-01-06 20:00:00,40329.0,40430.0,40100.0,40267.0,28.86687324 +2024-01-06 22:00:00,40231.0,40650.0,40185.0,40397.0,25.96532915 +2024-01-07 00:00:00,40397.0,40573.0,40271.0,40279.0,18.57174599 +2024-01-07 02:00:00,40273.0,40470.0,40192.0,40264.0,9.26540661 +2024-01-07 04:00:00,40259.0,40384.0,40165.0,40206.0,10.56279714 +2024-01-07 06:00:00,40226.0,40481.0,40201.0,40396.0,14.52168206 +2024-01-07 08:00:00,40400.0,40500.0,40312.0,40357.0,26.30121572 +2024-01-07 10:00:00,40357.0,40700.0,40350.0,40506.0,44.6360706 +2024-01-07 12:00:00,40506.0,40889.0,40500.0,40774.0,60.34247126 +2024-01-07 14:00:00,40793.0,41000.0,40500.0,40501.0,52.96596407 +2024-01-07 16:00:00,40501.0,40811.0,40360.0,40509.0,44.87567542 +2024-01-07 18:00:00,40508.0,40750.0,40459.0,40750.0,34.51466873 +2024-01-07 20:00:00,40750.0,40927.0,40575.0,40878.0,52.47928344 +2024-01-07 22:00:00,40872.0,40907.0,39934.0,40254.0,115.72213787 +2024-01-08 00:00:00,40250.0,40301.0,39939.0,40015.0,23.85426655 +2024-01-08 02:00:00,40034.0,40108.0,39615.0,39891.0,32.60026051 +2024-01-08 04:00:00,39889.0,40599.0,39812.0,40599.0,32.75078902 +2024-01-08 06:00:00,40473.0,40725.0,40147.0,40336.0,49.20021713 +2024-01-08 08:00:00,40352.0,40800.0,40000.0,40087.0,50.46486001 +2024-01-08 10:00:00,40128.0,41000.0,40070.0,40857.0,87.79520091 +2024-01-08 12:00:00,40845.0,41307.0,40589.0,41053.0,197.7568873 +2024-01-08 14:00:00,41059.0,41395.0,40813.0,41034.0,107.40591936 +2024-01-08 16:00:00,41064.0,41682.0,40877.0,41682.0,124.43168889 +2024-01-08 18:00:00,41682.0,42927.0,41000.0,42874.0,536.57805959 +2024-01-08 20:00:00,42875.0,43126.0,42200.0,43010.0,257.62682822 +2024-01-08 22:00:00,43007.0,43050.0,42300.0,42906.0,86.19755451 +2024-01-09 00:00:00,42906.0,43049.0,42223.0,42479.0,52.18808759 +2024-01-09 02:00:00,42480.0,42864.0,42434.0,42840.0,18.71841554 +2024-01-09 04:00:00,42825.0,42844.0,42568.0,42674.0,28.57237198 +2024-01-09 06:00:00,42677.0,42850.0,42633.0,42778.0,53.95831832 +2024-01-09 08:00:00,42779.0,42880.0,42487.0,42528.0,88.37915463 +2024-01-09 10:00:00,42530.0,42730.0,42488.0,42705.0,103.93611658 +2024-01-09 12:00:00,42714.0,43300.0,41900.0,42874.0,174.84818354 +2024-01-09 14:00:00,42845.0,43250.0,42500.0,42990.0,131.69876689 +2024-01-09 16:00:00,42990.0,43250.0,42717.0,42816.0,108.67330935 +2024-01-09 18:00:00,42802.0,43083.0,42621.0,42972.0,93.38391446 +2024-01-09 20:00:00,42972.0,43845.0,40985.0,41577.0,551.12815094 +2024-01-09 22:00:00,41592.0,42400.0,41441.0,42223.0,185.0416974 +2024-01-10 00:00:00,42231.0,42342.0,41800.0,42069.0,34.74268553 +2024-01-10 02:00:00,42069.0,42860.0,42027.0,42245.0,16.02980429 +2024-01-10 04:00:00,42259.0,42750.0,42033.0,42144.0,29.82674481 +2024-01-10 06:00:00,42113.0,42915.0,41888.0,41945.0,69.55916826 +2024-01-10 08:00:00,41943.0,42020.0,41443.0,41753.0,135.7701603 +2024-01-10 10:00:00,41766.0,42672.0,41250.0,41638.0,118.62224539 +2024-01-10 12:00:00,41623.0,41756.0,40525.0,41325.0,224.80894222 +2024-01-10 14:00:00,41325.0,41675.0,41000.0,41569.0,133.41021818 +2024-01-10 16:00:00,41575.0,42600.0,41279.0,42413.0,175.40552956 +2024-01-10 18:00:00,42431.0,42750.0,42111.0,42486.0,194.29558726 +2024-01-10 20:00:00,42463.0,42900.0,40944.0,42001.0,531.39037173 +2024-01-10 22:00:00,41951.0,43569.0,41794.0,42593.0,466.19095271 +2024-01-11 00:00:00,42596.0,42660.0,42223.0,42427.0,62.54119875 +2024-01-11 02:00:00,42440.0,42540.0,42184.0,42425.0,15.1698999 +2024-01-11 04:00:00,42411.0,42421.0,41900.0,42043.0,60.26923094 +2024-01-11 06:00:00,42043.0,42950.0,41623.0,42104.0,149.4394321 +2024-01-11 08:00:00,42095.0,42399.0,42019.0,42226.0,126.18097302 +2024-01-11 10:00:00,42217.0,43000.0,42214.0,42904.0,151.51597379 +2024-01-11 12:00:00,42914.0,43320.0,42808.0,43314.0,183.93025601 +2024-01-11 14:00:00,43309.0,44750.0,42249.0,42752.0,680.4594881 +2024-01-11 16:00:00,42750.0,43002.0,41679.0,42472.0,293.17454031 +2024-01-11 18:00:00,42478.0,42610.0,42229.0,42567.0,106.54968121 +2024-01-11 20:00:00,42567.0,43450.0,42075.0,42107.0,135.76978621 +2024-01-11 22:00:00,42104.0,42399.0,42050.0,42239.0,39.50642095 +2024-01-12 00:00:00,42245.0,42401.0,41851.0,42038.0,27.52310156 +2024-01-12 02:00:00,42038.0,42148.0,41851.0,41982.0,16.05299218 +2024-01-12 04:00:00,41963.0,42136.0,41820.0,42118.0,18.64731198 +2024-01-12 06:00:00,42120.0,42273.0,41769.0,41982.0,55.01914844 +2024-01-12 08:00:00,41979.0,42011.0,41520.0,41888.0,122.1014588 +2024-01-12 10:00:00,41891.0,42246.0,41839.0,41982.0,75.80516581 +2024-01-12 12:00:00,41982.0,42125.0,41629.0,41812.0,82.23871869 +2024-01-12 14:00:00,41819.0,41886.0,40245.0,40536.0,354.3195966 +2024-01-12 16:00:00,40541.0,40721.0,39361.0,39995.0,479.24626127 +2024-01-12 18:00:00,39995.0,40999.0,39451.0,39677.0,241.70993222 +2024-01-12 20:00:00,39674.0,40253.0,39500.0,39690.0,139.91652642 +2024-01-12 22:00:00,39692.0,39693.0,37700.0,39165.0,391.10609079 +2024-01-13 00:00:00,39145.0,39369.0,38915.0,39051.0,43.46139513 +2024-01-13 02:00:00,39047.0,39223.0,38833.0,38988.0,20.63723576 +2024-01-13 04:00:00,38987.0,39491.0,38932.0,39439.0,26.55322417 +2024-01-13 06:00:00,39460.0,39800.0,39375.0,39497.0,51.98920202 +2024-01-13 08:00:00,39497.0,39787.0,39251.0,39297.0,67.61327072 +2024-01-13 10:00:00,39290.0,39293.0,38900.0,38997.0,99.65871179 +2024-01-13 12:00:00,38993.0,39173.0,38900.0,39107.0,61.41615554 +2024-01-13 14:00:00,39124.0,39639.0,39044.0,39530.0,56.38324256 +2024-01-13 16:00:00,39527.0,39534.0,39162.0,39274.0,44.10302489 +2024-01-13 18:00:00,39264.0,39380.0,39131.0,39201.0,28.8099205 +2024-01-13 20:00:00,39201.0,39363.0,39102.0,39347.0,40.97840241 +2024-01-13 22:00:00,39348.0,39413.0,39106.0,39194.0,68.83653522 +2024-01-14 00:00:00,39201.0,39232.0,39025.0,39106.0,17.9027897 +2024-01-14 02:00:00,39105.0,39146.0,38971.0,39019.0,10.13042076 +2024-01-14 04:00:00,39010.0,39122.0,38920.0,39074.0,9.82895958 +2024-01-14 06:00:00,39081.0,39400.0,39072.0,39299.0,33.2764497 +2024-01-14 08:00:00,39321.0,39398.0,39166.0,39378.0,26.63407541 +2024-01-14 10:00:00,39370.0,39384.0,39107.0,39152.0,31.95613505 +2024-01-14 12:00:00,39166.0,39250.0,39062.0,39229.0,29.62075587 +2024-01-14 14:00:00,39226.0,39326.0,39123.0,39230.0,31.44286476 +2024-01-14 16:00:00,39232.0,39300.0,39167.0,39267.0,35.78735932 +2024-01-14 18:00:00,39270.0,39291.0,38968.0,38987.0,40.78678733 +2024-01-14 20:00:00,38981.0,39084.0,38350.0,38883.0,144.37229758 +2024-01-14 22:00:00,38869.0,38957.0,38110.0,38124.0,105.44677757 +2024-01-15 00:00:00,38124.0,38714.0,38074.0,38593.0,48.90632178 +2024-01-15 02:00:00,38607.0,38912.0,38524.0,38848.0,9.72704406 +2024-01-15 04:00:00,38840.0,39069.0,38798.0,39007.0,15.14994553 +2024-01-15 06:00:00,39003.0,39050.0,38830.0,39009.0,40.75646012 +2024-01-15 08:00:00,39012.0,39076.0,38901.0,39072.0,48.05169073 +2024-01-15 10:00:00,39072.0,39078.0,38905.0,39035.0,39.78626113 +2024-01-15 12:00:00,39062.0,39270.0,38862.0,39202.0,54.28683027 +2024-01-15 14:00:00,39201.0,39218.0,38513.0,38624.0,96.55496852 +2024-01-15 16:00:00,38617.0,39074.0,38586.0,39016.0,38.22819353 +2024-01-15 18:00:00,39005.0,39780.0,38999.0,39265.0,116.3748755 +2024-01-15 20:00:00,39264.0,39391.0,39017.0,39017.0,31.58053053 +2024-01-15 22:00:00,39028.0,39118.0,38700.0,38850.0,34.71845961 +2024-01-16 00:00:00,38847.0,39149.0,38813.0,38977.0,9.58653074 +2024-01-16 02:00:00,38977.0,39303.0,38961.0,39303.0,9.42039482 +2024-01-16 04:00:00,39285.0,39495.0,39161.0,39187.0,22.36154917 +2024-01-16 06:00:00,39180.0,39188.0,39025.0,39170.0,32.87767771 +2024-01-16 08:00:00,39181.0,39594.0,39136.0,39428.0,68.23108933 +2024-01-16 10:00:00,39417.0,39474.0,39246.0,39393.0,33.86121421 +2024-01-16 12:00:00,39390.0,39663.0,39288.0,39375.0,54.81825438 +2024-01-16 14:00:00,39364.0,39790.0,38700.0,39726.0,180.664837 +2024-01-16 16:00:00,39725.0,40434.0,39522.0,39636.0,93.8605169 +2024-01-16 18:00:00,39636.0,39735.0,39398.0,39706.0,40.46421997 +2024-01-16 20:00:00,39707.0,40084.0,39641.0,39948.0,72.70394445 +2024-01-16 22:00:00,39959.0,40012.0,39644.0,39665.0,27.1330139 +2024-01-17 00:00:00,39662.0,39733.0,39515.0,39524.0,10.73565736 +2024-01-17 02:00:00,39510.0,39598.0,39450.0,39450.0,12.26003174 +2024-01-17 04:00:00,39450.0,39499.0,39364.0,39377.0,9.41668808 +2024-01-17 06:00:00,39377.0,39488.0,39197.0,39236.0,32.66937679 +2024-01-17 08:00:00,39232.0,39445.0,39130.0,39252.0,30.17741326 +2024-01-17 10:00:00,39246.0,39436.0,39169.0,39228.0,30.80549415 +2024-01-17 12:00:00,39229.0,39337.0,39012.0,39230.0,46.70615036 +2024-01-17 14:00:00,39207.0,39524.0,39016.0,39143.0,85.63516332 +2024-01-17 16:00:00,39168.0,39194.0,38844.0,38971.0,90.30087185 +2024-01-17 18:00:00,38976.0,39295.0,38894.0,39165.0,54.30555779 +2024-01-17 20:00:00,39157.0,39381.0,38800.0,39170.0,65.71351562 +2024-01-17 22:00:00,39170.0,39271.0,38965.0,39269.0,31.18292053 +2024-01-18 00:00:00,39260.0,39264.0,38983.0,39050.0,7.10152731 +2024-01-18 02:00:00,39054.0,39163.0,39026.0,39051.0,5.07850972 +2024-01-18 04:00:00,39049.0,39230.0,39046.0,39227.0,7.67061389 +2024-01-18 06:00:00,39229.0,39355.0,39185.0,39347.0,36.58162432 +2024-01-18 08:00:00,39354.0,39379.0,39170.0,39227.0,38.3951719 +2024-01-18 10:00:00,39213.0,39242.0,38879.0,39054.0,49.24900317 +2024-01-18 12:00:00,39048.0,39261.0,38882.0,39154.0,32.44355168 +2024-01-18 14:00:00,39154.0,39380.0,39062.0,39245.0,37.28182438 +2024-01-18 16:00:00,39245.0,39245.0,38146.0,38510.0,174.8611767 +2024-01-18 18:00:00,38503.0,38594.0,37536.0,37744.0,270.26820801 +2024-01-18 20:00:00,37748.0,38015.0,37397.0,37806.0,220.97808986 +2024-01-18 22:00:00,37800.0,38050.0,37765.0,37996.0,52.10292255 +2024-01-19 00:00:00,38006.0,38033.0,37800.0,37921.0,23.54700989 +2024-01-19 02:00:00,37922.0,37933.0,37431.0,37698.0,19.58000836 +2024-01-19 04:00:00,37702.0,37887.0,37686.0,37864.0,14.30423227 +2024-01-19 06:00:00,37876.0,38213.0,37853.0,37923.0,60.7131791 +2024-01-19 08:00:00,37920.0,38100.0,37793.0,38041.0,42.77997558 +2024-01-19 10:00:00,38032.0,38142.0,37991.0,38082.0,62.21359121 +2024-01-19 12:00:00,38077.0,38092.0,37900.0,38026.0,48.58962851 +2024-01-19 14:00:00,38025.0,38074.0,37420.0,37567.0,129.83142269 +2024-01-19 16:00:00,37570.0,37858.0,37000.0,37858.0,233.69407643 +2024-01-19 18:00:00,37847.0,38561.0,37640.0,38378.0,132.32968478 +2024-01-19 20:00:00,38385.0,38728.0,38109.0,38210.0,114.99337065 +2024-01-19 22:00:00,38197.0,38296.0,38116.0,38228.0,28.50416826 +2024-01-20 00:00:00,38218.0,38270.0,38022.0,38217.0,24.78438427 +2024-01-20 02:00:00,38228.0,38228.0,38100.0,38203.0,6.7967076 +2024-01-20 04:00:00,38202.0,38227.0,38151.0,38195.0,8.23996274 +2024-01-20 06:00:00,38205.0,38332.0,38193.0,38237.0,19.38217385 +2024-01-20 08:00:00,38243.0,38251.0,38043.0,38100.0,26.89064474 +2024-01-20 10:00:00,38098.0,38192.0,38067.0,38161.0,17.90617333 +2024-01-20 12:00:00,38163.0,38256.0,38115.0,38222.0,23.11783985 +2024-01-20 14:00:00,38217.0,38259.0,38085.0,38161.0,17.90965745 +2024-01-20 16:00:00,38162.0,38233.0,38120.0,38187.0,20.78485912 +2024-01-20 18:00:00,38170.0,38248.0,38116.0,38208.0,24.37890291 +2024-01-20 20:00:00,38220.0,38425.0,38200.0,38310.0,27.83214945 +2024-01-20 22:00:00,38309.0,38371.0,38180.0,38252.0,9.80929704 +2024-01-21 00:00:00,38257.0,38293.0,38191.0,38226.0,4.86914953 +2024-01-21 02:00:00,38225.0,38282.0,38219.0,38224.0,10.27571683 +2024-01-21 04:00:00,38224.0,38250.0,38186.0,38189.0,2.34121717 +2024-01-21 06:00:00,38189.0,38213.0,38120.0,38201.0,9.43755332 +2024-01-21 08:00:00,38200.0,38299.0,38200.0,38295.0,16.80933589 +2024-01-21 10:00:00,38295.0,38373.0,38257.0,38292.0,16.66634416 +2024-01-21 12:00:00,38285.0,38424.0,38260.0,38418.0,21.38918044 +2024-01-21 14:00:00,38423.0,38467.0,38192.0,38242.0,35.53075569 +2024-01-21 16:00:00,38239.0,38281.0,38127.0,38266.0,15.46439768 +2024-01-21 18:00:00,38266.0,38309.0,38212.0,38296.0,10.72779023 +2024-01-21 20:00:00,38289.0,38350.0,38203.0,38332.0,17.94534511 +2024-01-21 22:00:00,38337.0,38341.0,38081.0,38146.0,17.7925421 +2024-01-22 00:00:00,38140.0,38224.0,37845.0,37918.0,20.30024036 +2024-01-22 02:00:00,37901.0,37951.0,37640.0,37757.0,18.37363012 +2024-01-22 04:00:00,37748.0,37770.0,37303.0,37721.0,41.1367312 +2024-01-22 06:00:00,37733.0,37873.0,37576.0,37633.0,46.62942204 +2024-01-22 08:00:00,37633.0,37650.0,37290.0,37373.0,87.93381464 +2024-01-22 10:00:00,37378.0,37600.0,37052.0,37477.0,97.27397029 +2024-01-22 12:00:00,37469.0,37852.0,37345.0,37580.0,98.04586323 +2024-01-22 14:00:00,37578.0,37627.0,37041.0,37434.0,134.54484391 +2024-01-22 16:00:00,37434.0,37542.0,37064.0,37331.0,68.48891022 +2024-01-22 18:00:00,37331.0,37413.0,36225.0,36593.0,269.3691882 +2024-01-22 20:00:00,36596.0,37100.0,36537.0,36551.0,146.60442691 +2024-01-22 22:00:00,36582.0,36783.0,36241.0,36308.0,84.57403551 +2024-01-23 00:00:00,36308.0,36646.0,36266.0,36559.0,25.35474088 +2024-01-23 02:00:00,36556.0,36833.0,36548.0,36706.0,16.587074 +2024-01-23 04:00:00,36708.0,36850.0,36708.0,36716.0,20.66094853 +2024-01-23 06:00:00,36721.0,36777.0,36341.0,36425.0,47.90501361 +2024-01-23 08:00:00,36434.0,36500.0,35678.0,35750.0,255.98580335 +2024-01-23 10:00:00,35744.0,35933.0,35524.0,35689.0,190.41959092 +2024-01-23 12:00:00,35681.0,35942.0,35619.0,35713.0,125.41301754 +2024-01-23 14:00:00,35700.0,37500.0,35433.0,36206.0,182.75914254 +2024-01-23 16:00:00,36205.0,36600.0,35924.0,36386.0,128.24455842 +2024-01-23 18:00:00,36387.0,36608.0,35979.0,36109.0,80.37548093 +2024-01-23 20:00:00,36117.0,36306.0,35991.0,36150.0,58.14709482 +2024-01-23 22:00:00,36150.0,36754.0,36105.0,36754.0,67.8469797 +2024-01-24 00:00:00,36740.0,37077.0,36638.0,36638.0,35.34024396 +2024-01-24 02:00:00,36645.0,36760.0,36434.0,36465.0,8.7174071 +2024-01-24 04:00:00,36491.0,36689.0,36446.0,36648.0,20.48041423 +2024-01-24 06:00:00,36653.0,36980.0,36517.0,36798.0,93.16370334 +2024-01-24 08:00:00,36798.0,37100.0,36631.0,36733.0,91.38947194 +2024-01-24 10:00:00,36735.0,37400.0,36696.0,36952.0,124.03414604 +2024-01-24 12:00:00,36946.0,37500.0,36570.0,36627.0,99.15159089 +2024-01-24 14:00:00,36627.0,37000.0,36430.0,36780.0,69.65808609 +2024-01-24 16:00:00,36780.0,36904.0,36662.0,36841.0,42.32401001 +2024-01-24 18:00:00,36839.0,36871.0,36400.0,36581.0,41.24348757 +2024-01-24 20:00:00,36582.0,36765.0,36309.0,36567.0,44.52037896 +2024-01-24 22:00:00,36569.0,36909.0,36534.0,36840.0,36.33800886 +2024-01-25 00:00:00,36841.0,36938.0,36714.0,36762.0,6.79580302 +2024-01-25 02:00:00,36761.0,36848.0,36704.0,36785.0,5.58478951 +2024-01-25 04:00:00,36777.0,36808.0,36577.0,36666.0,10.46271915 +2024-01-25 06:00:00,36666.0,36871.0,36665.0,36871.0,20.99875196 +2024-01-25 08:00:00,36864.0,36929.0,36766.0,36774.0,40.97016722 +2024-01-25 10:00:00,36774.0,37005.0,36701.0,36887.0,44.78681976 +2024-01-25 12:00:00,36893.0,36986.0,36523.0,36719.0,33.28626093 +2024-01-25 14:00:00,36720.0,36920.0,36623.0,36781.0,37.3872391 +2024-01-25 16:00:00,36769.0,36807.0,36500.0,36742.0,58.91243357 +2024-01-25 18:00:00,36751.0,36943.0,36652.0,36898.0,44.95931277 +2024-01-25 20:00:00,36900.0,36910.0,36593.0,36836.0,26.45182518 +2024-01-25 22:00:00,36835.0,36890.0,36800.0,36850.0,13.51709662 +2024-01-26 00:00:00,36847.0,36866.0,36740.0,36814.0,10.43862952 +2024-01-26 02:00:00,36814.0,37090.0,36814.0,36921.0,15.04485067 +2024-01-26 04:00:00,36919.0,37088.0,36919.0,37004.0,21.06177306 +2024-01-26 06:00:00,37003.0,37082.0,36896.0,36961.0,30.18027784 +2024-01-26 08:00:00,36961.0,37284.0,36946.0,36986.0,49.2642428 +2024-01-26 10:00:00,36973.0,38050.0,36973.0,38005.0,152.09286064 +2024-01-26 12:00:00,38010.0,38249.0,37654.0,37757.0,139.44050592 +2024-01-26 14:00:00,37764.0,38966.0,37500.0,38154.0,169.41960042 +2024-01-26 16:00:00,38143.0,39000.0,38135.0,38620.0,198.16168319 +2024-01-26 18:00:00,38608.0,38880.0,38560.0,38764.0,100.08450464 +2024-01-26 20:00:00,38761.0,38942.0,38567.0,38704.0,70.15308528 +2024-01-26 22:00:00,38702.0,38725.0,38530.0,38547.0,24.51695203 +2024-01-27 00:00:00,38551.0,38660.0,38473.0,38569.0,16.4323852 +2024-01-27 02:00:00,38569.0,38631.0,38520.0,38564.0,6.5489845 +2024-01-27 04:00:00,38568.0,38635.0,38503.0,38527.0,4.44828114 +2024-01-27 06:00:00,38522.0,38572.0,38371.0,38462.0,21.39808595 +2024-01-27 08:00:00,38462.0,38490.0,38159.0,38421.0,39.92335125 +2024-01-27 10:00:00,38425.0,38550.0,38406.0,38521.0,22.83042669 +2024-01-27 12:00:00,38531.0,38599.0,38479.0,38523.0,25.09341368 +2024-01-27 14:00:00,38522.0,38676.0,38507.0,38591.0,15.44902483 +2024-01-27 16:00:00,38592.0,38667.0,38551.0,38553.0,14.40250477 +2024-01-27 18:00:00,38557.0,38722.0,38530.0,38663.0,18.15071211 +2024-01-27 20:00:00,38674.0,38944.0,38673.0,38910.0,23.3978848 +2024-01-27 22:00:00,38912.0,38937.0,38821.0,38858.0,28.00038515 +2024-01-28 00:00:00,38863.0,38924.0,38665.0,38801.0,37.81062377 +2024-01-28 02:00:00,38805.0,38925.0,38801.0,38925.0,6.65256423 +2024-01-28 04:00:00,38925.0,39432.0,38919.0,39197.0,41.95777418 +2024-01-28 06:00:00,39197.0,39207.0,38953.0,39077.0,35.41944471 +2024-01-28 08:00:00,39077.0,39435.0,39016.0,39287.0,65.71004857 +2024-01-28 10:00:00,39287.0,39446.0,39105.0,39191.0,45.34477799 +2024-01-28 12:00:00,39195.0,39212.0,38991.0,39102.0,34.82875619 +2024-01-28 14:00:00,39107.0,39236.0,38878.0,38954.0,28.54606459 +2024-01-28 16:00:00,38953.0,39040.0,38798.0,38844.0,28.55309068 +2024-01-28 18:00:00,38839.0,38844.0,38440.0,38481.0,60.63529863 +2024-01-28 20:00:00,38470.0,38714.0,38388.0,38672.0,45.31528091 +2024-01-28 22:00:00,38666.0,38784.0,38383.0,38748.0,15.41192247 +2024-01-29 00:00:00,38758.0,38991.0,38615.0,38870.0,3.37033822 +2024-01-29 02:00:00,38871.0,39173.0,38850.0,39038.0,7.134838 +2024-01-29 04:00:00,39021.0,39032.0,38838.0,38843.0,10.49801933 +2024-01-29 06:00:00,38844.0,38932.0,38710.0,38772.0,24.55784435 +2024-01-29 08:00:00,38784.0,39103.0,38701.0,39063.0,42.87658983 +2024-01-29 10:00:00,39074.0,39181.0,38999.0,39017.0,30.72904809 +2024-01-29 12:00:00,39040.0,39140.0,38747.0,38817.0,25.50534551 +2024-01-29 14:00:00,38821.0,39498.0,38700.0,39493.0,61.15114607 +2024-01-29 16:00:00,39482.0,40110.0,39331.0,39724.0,204.24943982 +2024-01-29 18:00:00,39725.0,39913.0,39632.0,39758.0,75.33256109 +2024-01-29 20:00:00,39767.0,39954.0,39693.0,39884.0,47.63795899 +2024-01-29 22:00:00,39875.0,39976.0,39771.0,39976.0,20.84514211 +2024-01-30 00:00:00,39977.0,40180.0,39810.0,40088.0,29.15019076 +2024-01-30 02:00:00,40102.0,40399.0,40094.0,40157.0,13.24832872 +2024-01-30 04:00:00,40162.0,40228.0,40068.0,40096.0,35.77602082 +2024-01-30 06:00:00,40106.0,40226.0,40000.0,40106.0,41.67046242 +2024-01-30 08:00:00,40093.0,40203.0,40000.0,40056.0,41.14628784 +2024-01-30 10:00:00,40063.0,40348.0,40012.0,40204.0,53.40906895 +2024-01-30 12:00:00,40204.0,40500.0,39802.0,39947.0,128.63310285 +2024-01-30 14:00:00,39957.0,40257.0,39773.0,40050.0,64.87896729 +2024-01-30 16:00:00,40055.0,40229.0,39914.0,40050.0,37.51609445 +2024-01-30 18:00:00,40056.0,40196.0,39985.0,40192.0,41.41342369 +2024-01-30 20:00:00,40194.0,40379.0,40114.0,40157.0,49.05876556 +2024-01-30 22:00:00,40169.0,40203.0,39378.0,39622.0,69.02660287 +2024-01-31 00:00:00,39617.0,39777.0,39433.0,39504.0,15.99230009 +2024-01-31 02:00:00,39509.0,39770.0,39436.0,39713.0,12.38325233 +2024-01-31 04:00:00,39721.0,39805.0,39653.0,39733.0,16.96371485 +2024-01-31 06:00:00,39730.0,39839.0,39664.0,39819.0,30.22171073 +2024-01-31 08:00:00,39813.0,39836.0,39360.0,39360.0,40.70730747 +2024-01-31 10:00:00,39394.0,39493.0,39077.0,39348.0,72.60070165 +2024-01-31 12:00:00,39325.0,39530.0,39197.0,39402.0,42.14267956 +2024-01-31 14:00:00,39415.0,40103.0,39181.0,39961.0,72.31373639 +2024-01-31 16:00:00,39954.0,40323.0,39902.0,40295.0,72.70193802 +2024-01-31 18:00:00,40298.0,40333.0,39687.0,39943.0,116.54705859 +2024-01-31 20:00:00,39948.0,39962.0,39140.0,39278.0,108.06376796 +2024-01-31 22:00:00,39282.0,39500.0,39189.0,39424.0,27.341608 +2024-02-01 00:00:00,39417.0,39507.0,38780.0,38836.0,26.23099245 +2024-02-01 02:00:00,38851.0,39004.0,38821.0,38869.0,14.03189043 +2024-02-01 04:00:00,38850.0,39064.0,38780.0,39044.0,30.05573137 +2024-02-01 06:00:00,39045.0,39305.0,38999.0,39109.0,44.88637408 +2024-02-01 08:00:00,39104.0,39179.0,39019.0,39036.0,30.81569963 +2024-02-01 10:00:00,39033.0,39220.0,38878.0,38932.0,36.45440864 +2024-02-01 12:00:00,38929.0,39084.0,38800.0,39065.0,48.46004791 +2024-02-01 14:00:00,39056.0,39675.0,39024.0,39280.0,87.64103504 +2024-02-01 16:00:00,39281.0,39761.0,39063.0,39462.0,50.89098117 +2024-02-01 18:00:00,39463.0,39823.0,39378.0,39763.0,33.20351846 +2024-02-01 20:00:00,39759.0,39799.0,39472.0,39628.0,44.73729894 +2024-02-01 22:00:00,39634.0,39643.0,39426.0,39617.0,12.99127639 +2024-02-02 00:00:00,39631.0,39910.0,39578.0,39660.0,16.74763507 +2024-02-02 02:00:00,39661.0,39716.0,39558.0,39560.0,2.87008196 +2024-02-02 04:00:00,39563.0,39670.0,39494.0,39639.0,7.48349729 +2024-02-02 06:00:00,39636.0,39777.0,39611.0,39630.0,24.35488301 +2024-02-02 08:00:00,39624.0,39800.0,39462.0,39474.0,35.97932797 +2024-02-02 10:00:00,39474.0,39707.0,39433.0,39660.0,20.8724569 +2024-02-02 12:00:00,39660.0,39750.0,39332.0,39492.0,38.24647826 +2024-02-02 14:00:00,39508.0,40000.0,39436.0,39996.0,51.38960308 +2024-02-02 16:00:00,39992.0,40229.0,39750.0,39784.0,111.27254219 +2024-02-02 18:00:00,39785.0,39894.0,39623.0,39876.0,26.42155132 +2024-02-02 20:00:00,39900.0,39904.0,39710.0,39801.0,12.55266155 +2024-02-02 22:00:00,39805.0,40019.0,39797.0,39974.0,14.69719251 +2024-02-03 00:00:00,39982.0,40141.0,39941.0,39982.0,8.4175627 +2024-02-03 02:00:00,39987.0,40001.0,39933.0,39964.0,1.38584185 +2024-02-03 04:00:00,39965.0,40001.0,39901.0,39953.0,3.48686167 +2024-02-03 06:00:00,39960.0,39960.0,39869.0,39876.0,10.66812003 +2024-02-03 08:00:00,39871.0,39975.0,39842.0,39932.0,24.04646248 +2024-02-03 10:00:00,39931.0,39970.0,39829.0,39856.0,23.74168113 +2024-02-03 12:00:00,39855.0,39951.0,39841.0,39937.0,15.08142046 +2024-02-03 14:00:00,39933.0,40044.0,39800.0,39967.0,21.49580021 +2024-02-03 16:00:00,39979.0,40090.0,39915.0,40046.0,16.9488119 +2024-02-03 18:00:00,40051.0,40066.0,39857.0,39928.0,20.07003046 +2024-02-03 20:00:00,39930.0,39959.0,39877.0,39921.0,6.82368764 +2024-02-03 22:00:00,39910.0,39977.0,39818.0,39867.0,9.90456554 +2024-02-04 00:00:00,39867.0,39904.0,39780.0,39902.0,4.86474242 +2024-02-04 02:00:00,39901.0,39920.0,39871.0,39889.0,1.26206912 +2024-02-04 04:00:00,39881.0,39963.0,39760.0,39762.0,7.46465238 +2024-02-04 06:00:00,39769.0,39822.0,39610.0,39731.0,15.17644161 +2024-02-04 08:00:00,39731.0,39948.0,39642.0,39833.0,23.34580815 +2024-02-04 10:00:00,39838.0,39957.0,39780.0,39912.0,15.17133225 +2024-02-04 12:00:00,39911.0,39944.0,39815.0,39835.0,14.68250849 +2024-02-04 14:00:00,39835.0,39871.0,39700.0,39784.0,15.99006014 +2024-02-04 16:00:00,39783.0,39811.0,39712.0,39759.0,7.09052239 +2024-02-04 18:00:00,39758.0,39801.0,39500.0,39540.0,27.5483299 +2024-02-04 20:00:00,39534.0,39900.0,39500.0,39658.0,23.04661621 +2024-02-04 22:00:00,39671.0,39763.0,39230.0,39520.0,17.11871596 +2024-02-05 00:00:00,39522.0,39559.0,39230.0,39468.0,5.83311129 +2024-02-05 02:00:00,39464.0,39613.0,39339.0,39610.0,15.13450262 +2024-02-05 04:00:00,39626.0,39728.0,39553.0,39664.0,5.41999943 +2024-02-05 06:00:00,39670.0,40036.0,39650.0,39935.0,25.44960953 +2024-02-05 08:00:00,39936.0,40047.0,39866.0,39974.0,26.29144184 +2024-02-05 10:00:00,39988.0,40195.0,39984.0,40112.0,55.23902875 +2024-02-05 12:00:00,40113.0,40483.0,40050.0,40391.0,73.66167421 +2024-02-05 14:00:00,40386.0,40433.0,39400.0,39725.0,88.46779542 +2024-02-05 16:00:00,39723.0,39875.0,39573.0,39765.0,38.90483395 +2024-02-05 18:00:00,39764.0,39900.0,39629.0,39808.0,34.08060046 +2024-02-05 20:00:00,39810.0,39840.0,39420.0,39467.0,36.48155685 +2024-02-05 22:00:00,39466.0,39776.0,39425.0,39762.0,16.48401764 +2024-02-06 00:00:00,39763.0,39791.0,39616.0,39703.0,4.47821098 +2024-02-06 02:00:00,39708.0,39950.0,39677.0,39875.0,5.57043721 +2024-02-06 04:00:00,39874.0,39935.0,39761.0,39782.0,8.13921763 +2024-02-06 06:00:00,39774.0,39900.0,39671.0,39869.0,8.38788909 +2024-02-06 08:00:00,39879.0,40102.0,39864.0,40056.0,36.28887707 +2024-02-06 10:00:00,40058.0,40134.0,39761.0,39855.0,36.62902797 +2024-02-06 12:00:00,39851.0,40029.0,39724.0,39913.0,31.98836383 +2024-02-06 14:00:00,39913.0,40201.0,39865.0,40196.0,53.51389141 +2024-02-06 16:00:00,40196.0,40289.0,40000.0,40094.0,80.18484304 +2024-02-06 18:00:00,40093.0,40228.0,39966.0,40228.0,26.33939904 +2024-02-06 20:00:00,40224.0,40270.0,40003.0,40120.0,38.69643783 +2024-02-06 22:00:00,40122.0,40163.0,39963.0,40010.0,21.57362656 +2024-02-07 00:00:00,40017.0,40101.0,39967.0,39980.0,14.09421081 +2024-02-07 02:00:00,39974.0,40017.0,39740.0,39742.0,10.23001577 +2024-02-07 04:00:00,39751.0,39978.0,39751.0,39957.0,12.12677514 +2024-02-07 06:00:00,39964.0,39964.0,39814.0,39832.0,24.44485602 +2024-02-07 08:00:00,39832.0,40131.0,39813.0,40085.0,26.77612849 +2024-02-07 10:00:00,40084.0,40089.0,39790.0,39881.0,34.48228535 +2024-02-07 12:00:00,39885.0,40100.0,39831.0,40085.0,21.26332321 +2024-02-07 14:00:00,40086.0,40212.0,39861.0,40025.0,44.10722871 +2024-02-07 16:00:00,40029.0,40500.0,39957.0,40342.0,117.81724515 +2024-02-07 18:00:00,40353.0,40497.0,40227.0,40448.0,64.65135583 +2024-02-07 20:00:00,40457.0,41150.0,40457.0,40969.0,232.0970609 +2024-02-07 22:00:00,40968.0,41098.0,40889.0,41089.0,48.48484257 +2024-02-08 00:00:00,41086.0,41399.0,41078.0,41376.0,44.41511314 +2024-02-08 02:00:00,41383.0,41459.0,41255.0,41257.0,15.95548154 +2024-02-08 04:00:00,41274.0,41314.0,41177.0,41250.0,27.14576238 +2024-02-08 06:00:00,41245.0,41269.0,41150.0,41247.0,41.63789814 +2024-02-08 08:00:00,41250.0,41600.0,41249.0,41427.0,110.97076952 +2024-02-08 10:00:00,41428.0,41696.0,41417.0,41529.0,62.92805734 +2024-02-08 12:00:00,41530.0,41857.0,41500.0,41836.0,65.1680634 +2024-02-08 14:00:00,41854.0,42200.0,41680.0,42133.0,184.26046379 +2024-02-08 16:00:00,42149.0,42200.0,41079.0,41748.0,168.47202634 +2024-02-08 18:00:00,41760.0,42100.0,41689.0,41974.0,73.36657358 +2024-02-08 20:00:00,41980.0,42249.0,41915.0,42015.0,95.07417346 +2024-02-08 22:00:00,42023.0,42093.0,41259.0,41990.0,36.25295658 +2024-02-09 00:00:00,41990.0,42180.0,41948.0,42180.0,9.21933144 +2024-02-09 02:00:00,42180.0,42947.0,42144.0,42704.0,85.54705339 +2024-02-09 04:00:00,42719.0,42944.0,42511.0,42928.0,33.70477453 +2024-02-09 06:00:00,42930.0,43065.0,42796.0,42827.0,114.42299869 +2024-02-09 08:00:00,42825.0,43404.0,42820.0,43225.0,193.35679355 +2024-02-09 10:00:00,43228.0,43933.0,43228.0,43818.0,149.71637326 +2024-02-09 12:00:00,43818.0,44250.0,43761.0,43965.0,259.7498192 +2024-02-09 14:00:00,43962.0,44182.0,42600.0,43681.0,443.73095188 +2024-02-09 16:00:00,43682.0,44138.0,43662.0,44119.0,139.45012075 +2024-02-09 18:00:00,44119.0,44500.0,43752.0,43998.0,218.92583157 +2024-02-09 20:00:00,43999.0,44177.0,43716.0,43934.0,100.5807209 +2024-02-09 22:00:00,43934.0,43987.0,43250.0,43382.0,105.79133532 +2024-02-10 00:00:00,43383.0,43759.0,43197.0,43516.0,42.73039947 +2024-02-10 02:00:00,43516.0,43788.0,43514.0,43641.0,17.46261325 +2024-02-10 04:00:00,43646.0,43758.0,43611.0,43691.0,11.04569154 +2024-02-10 06:00:00,43692.0,43799.0,43615.0,43628.0,29.67282628 +2024-02-10 08:00:00,43627.0,43750.0,43222.0,43323.0,60.4696897 +2024-02-10 10:00:00,43323.0,43674.0,42850.0,43313.0,132.67012239 +2024-02-10 12:00:00,43465.0,43776.0,43000.0,43669.0,52.29668676 +2024-02-10 14:00:00,43688.0,43724.0,43510.0,43700.0,26.79235798 +2024-02-10 16:00:00,43705.0,43729.0,43487.0,43569.0,27.52993392 +2024-02-10 18:00:00,43569.0,43999.0,43568.0,43869.0,47.27525525 +2024-02-10 20:00:00,43879.0,44464.0,43820.0,44303.0,129.54835958 +2024-02-10 22:00:00,44277.0,44277.0,43918.0,44057.0,46.51788327 +2024-02-11 00:00:00,44057.0,44084.0,43910.0,43927.0,8.4013087 +2024-02-11 02:00:00,43920.0,44544.0,43900.0,44535.0,49.00883152 +2024-02-11 04:00:00,44535.0,44555.0,44174.0,44239.0,22.117319 +2024-02-11 06:00:00,44240.0,44555.0,44131.0,44401.0,36.64476617 +2024-02-11 08:00:00,44422.0,44505.0,44091.0,44413.0,57.24591644 +2024-02-11 10:00:00,44413.0,44610.0,44125.0,44591.0,65.42914382 +2024-02-11 12:00:00,44591.0,44697.0,44307.0,44333.0,60.0948062 +2024-02-11 14:00:00,44333.0,44523.0,44208.0,44447.0,38.27059001 +2024-02-11 16:00:00,44438.0,44648.0,44263.0,44561.0,42.13668459 +2024-02-11 18:00:00,44566.0,44639.0,44200.0,44518.0,34.49992088 +2024-02-11 20:00:00,44524.0,44615.0,44254.0,44413.0,67.43187171 +2024-02-11 22:00:00,44413.0,44593.0,44351.0,44561.0,22.54761328 +2024-02-12 00:00:00,44590.0,44992.0,44543.0,44754.0,66.79466199 +2024-02-12 02:00:00,44762.0,44795.0,44396.0,44535.0,21.74398303 +2024-02-12 04:00:00,44536.0,44574.0,44426.0,44476.0,10.25051446 +2024-02-12 06:00:00,44472.0,44742.0,44169.0,44591.0,76.98430969 +2024-02-12 08:00:00,44610.0,44866.0,44400.0,44452.0,65.77794043 +2024-02-12 10:00:00,44459.0,44589.0,44255.0,44459.0,71.39203886 +2024-02-12 12:00:00,44459.0,44600.0,44436.0,44546.0,41.75698599 +2024-02-12 14:00:00,44545.0,46421.0,44530.0,46355.0,362.87600246 +2024-02-12 16:00:00,46350.0,46598.0,45478.0,46167.0,314.61240382 +2024-02-12 18:00:00,46186.0,46303.0,45519.0,45846.0,169.5097826 +2024-02-12 20:00:00,45841.0,46500.0,45841.0,46163.0,154.51839472 +2024-02-12 22:00:00,46162.0,46388.0,46161.0,46245.0,64.17641764 +2024-02-13 00:00:00,46263.0,46625.0,46245.0,46479.0,33.11832797 +2024-02-13 02:00:00,46466.0,46468.0,46063.0,46129.0,23.8071799 +2024-02-13 04:00:00,46130.0,46408.0,46000.0,46392.0,31.54171553 +2024-02-13 06:00:00,46397.0,46447.0,46291.0,46369.0,52.31457995 +2024-02-13 08:00:00,46364.0,46745.0,46329.0,46700.0,116.67306097 +2024-02-13 10:00:00,46701.0,46701.0,46065.0,46369.0,105.17453391 +2024-02-13 12:00:00,46374.0,46600.0,45854.0,46238.0,101.93971465 +2024-02-13 14:00:00,46223.0,46342.0,44859.0,45429.0,364.43862216 +2024-02-13 16:00:00,45424.0,45642.0,44800.0,45578.0,202.22218862 +2024-02-13 18:00:00,45577.0,46064.0,45559.0,45849.0,111.61557586 +2024-02-13 20:00:00,45868.0,46500.0,45850.0,46271.0,101.62212105 +2024-02-13 22:00:00,46272.0,46485.0,46081.0,46418.0,37.17098885 +2024-02-14 00:00:00,46428.0,46428.0,46094.0,46155.0,7.25513124 +2024-02-14 02:00:00,46158.0,46327.0,46104.0,46230.0,5.3522457 +2024-02-14 04:00:00,46245.0,46341.0,46000.0,46258.0,14.16968524 +2024-02-14 06:00:00,46267.0,46600.0,46231.0,46571.0,61.45713818 +2024-02-14 08:00:00,46577.0,48312.0,46506.0,48173.0,313.53200638 +2024-02-14 10:00:00,48165.0,48291.0,47583.0,48127.0,253.38997608 +2024-02-14 12:00:00,48144.0,48383.0,47987.0,48350.0,145.71674825 +2024-02-14 14:00:00,48327.0,48551.0,47865.0,48136.0,157.78046375 +2024-02-14 16:00:00,48125.0,48249.0,47752.0,48143.0,122.47788476 +2024-02-14 18:00:00,48140.0,48201.0,47716.0,48178.0,110.70871458 +2024-02-14 20:00:00,48177.0,48364.0,48014.0,48273.0,83.11317241 +2024-02-14 22:00:00,48276.0,48383.0,48136.0,48302.0,56.23969058 +2024-02-15 00:00:00,48305.0,48924.0,48227.0,48391.0,53.95450846 +2024-02-15 02:00:00,48395.0,48872.0,48376.0,48845.0,25.40058964 +2024-02-15 04:00:00,48834.0,48876.0,48325.0,48455.0,60.74595925 +2024-02-15 06:00:00,48445.0,48608.0,48176.0,48325.0,96.43145963 +2024-02-15 08:00:00,48296.0,48747.0,48181.0,48678.0,84.39319822 +2024-02-15 10:00:00,48690.0,48990.0,48611.0,48806.0,89.09020566 +2024-02-15 12:00:00,48790.0,48947.0,48456.0,48554.0,90.94441546 +2024-02-15 14:00:00,48531.0,49035.0,48014.0,48299.0,233.08945154 +2024-02-15 16:00:00,48291.0,48719.0,48129.0,48229.0,107.62662126 +2024-02-15 18:00:00,48228.0,48397.0,48086.0,48341.0,105.85373182 +2024-02-15 20:00:00,48337.0,48372.0,47637.0,47650.0,148.07515649 +2024-02-15 22:00:00,47637.0,48270.0,47627.0,48184.0,67.16335128 +2024-02-16 00:00:00,48180.0,48469.0,48158.0,48273.0,12.94812476 +2024-02-16 02:00:00,48260.0,48634.0,48180.0,48601.0,14.16978839 +2024-02-16 04:00:00,48600.0,48651.0,48328.0,48364.0,38.07888947 +2024-02-16 06:00:00,48364.0,48460.0,48047.0,48080.0,50.67640637 +2024-02-16 08:00:00,48078.0,48329.0,47918.0,48160.0,63.95035726 +2024-02-16 10:00:00,48157.0,48664.0,48116.0,48493.0,63.15505243 +2024-02-16 12:00:00,48482.0,48848.0,48378.0,48826.0,74.4089458 +2024-02-16 14:00:00,48825.0,48918.0,47919.0,48186.0,164.0794161 +2024-02-16 16:00:00,48183.0,48532.0,48137.0,48287.0,49.07743498 +2024-02-16 18:00:00,48309.0,48309.0,47968.0,48034.0,48.93728057 +2024-02-16 20:00:00,48040.0,48341.0,47987.0,48287.0,31.47537033 +2024-02-16 22:00:00,48288.0,48509.0,48213.0,48418.0,32.50337874 +2024-02-17 00:00:00,48419.0,48461.0,48189.0,48278.0,14.13465281 +2024-02-17 02:00:00,48275.0,48313.0,48205.0,48270.0,6.41470889 +2024-02-17 04:00:00,48264.0,48340.0,48132.0,48223.0,4.81482113 +2024-02-17 06:00:00,48232.0,48275.0,48187.0,48210.0,19.11743826 +2024-02-17 08:00:00,48211.0,48211.0,47980.0,48014.0,34.81227217 +2024-02-17 10:00:00,48001.0,48090.0,47823.0,47997.0,54.21063552 +2024-02-17 12:00:00,47992.0,48029.0,47376.0,47464.0,147.75538858 +2024-02-17 14:00:00,47464.0,47689.0,46901.0,47291.0,236.57739426 +2024-02-17 16:00:00,47290.0,47557.0,47056.0,47523.0,89.01694557 +2024-02-17 18:00:00,47535.0,47787.0,47457.0,47750.0,46.01682598 +2024-02-17 20:00:00,47748.0,48313.0,47667.0,48114.0,59.45341459 +2024-02-17 22:00:00,48123.0,48169.0,47901.0,47961.0,32.38735285 +2024-02-18 00:00:00,47963.0,48108.0,47814.0,47854.0,17.42051531 +2024-02-18 02:00:00,47854.0,47872.0,47528.0,47807.0,9.35217843 +2024-02-18 04:00:00,47807.0,47994.0,47807.0,47963.0,5.7735074 +2024-02-18 06:00:00,47965.0,48046.0,47733.0,47972.0,20.47818236 +2024-02-18 08:00:00,47977.0,48289.0,47950.0,48280.0,62.1263921 +2024-02-18 10:00:00,48274.0,48356.0,48038.0,48134.0,37.37033882 +2024-02-18 12:00:00,48138.0,48181.0,47845.0,47927.0,50.11960243 +2024-02-18 14:00:00,47926.0,48217.0,47924.0,48071.0,28.84409282 +2024-02-18 16:00:00,48047.0,48294.0,47981.0,48155.0,35.62075528 +2024-02-18 18:00:00,48146.0,48176.0,47975.0,48081.0,40.21874687 +2024-02-18 20:00:00,48065.0,48200.0,47908.0,48143.0,39.39495728 +2024-02-18 22:00:00,48130.0,48611.0,48123.0,48350.0,80.39399328 +2024-02-19 00:00:00,48372.0,48600.0,48170.0,48334.0,14.37713698 +2024-02-19 02:00:00,48329.0,48446.0,48241.0,48321.0,4.92378971 +2024-02-19 04:00:00,48328.0,48453.0,48217.0,48336.0,11.02399179 +2024-02-19 06:00:00,48346.0,48900.0,48343.0,48629.0,97.72241475 +2024-02-19 08:00:00,48630.0,48649.0,48365.0,48581.0,65.16466759 +2024-02-19 10:00:00,48580.0,48700.0,48458.0,48619.0,52.28481319 +2024-02-19 12:00:00,48619.0,48719.0,48402.0,48442.0,54.40473844 +2024-02-19 14:00:00,48431.0,48654.0,48336.0,48427.0,59.89365194 +2024-02-19 16:00:00,48423.0,48514.0,48002.0,48408.0,70.23757747 +2024-02-19 18:00:00,48415.0,48436.0,48064.0,48103.0,47.14434934 +2024-02-19 20:00:00,48097.0,48227.0,47983.0,48172.0,43.96156409 +2024-02-19 22:00:00,48168.0,48374.0,48001.0,48062.0,28.34657136 +2024-02-20 00:00:00,48064.0,48128.0,47699.0,48002.0,26.20496918 +2024-02-20 02:00:00,47993.0,48109.0,47918.0,47927.0,5.17360069 +2024-02-20 04:00:00,47921.0,48306.0,47859.0,48258.0,11.57401339 +2024-02-20 06:00:00,48259.0,48341.0,47200.0,48150.0,71.70883791 +2024-02-20 08:00:00,48151.0,48174.0,47800.0,47975.0,51.417638 +2024-02-20 10:00:00,47977.0,48536.0,47976.0,48438.0,63.06305587 +2024-02-20 12:00:00,48437.0,48990.0,48260.0,48824.0,106.95404391 +2024-02-20 14:00:00,48826.0,48853.0,47500.0,47815.0,171.67062556 +2024-02-20 16:00:00,47818.0,47927.0,46960.0,47521.0,173.84614681 +2024-02-20 18:00:00,47516.0,48267.0,47435.0,48266.0,96.04747178 +2024-02-20 20:00:00,48256.0,48333.0,48051.0,48167.0,69.04326423 +2024-02-20 22:00:00,48174.0,48582.0,48148.0,48336.0,42.38225074 +2024-02-21 00:00:00,48344.0,48442.0,48136.0,48181.0,11.54569129 +2024-02-21 02:00:00,48198.0,48229.0,48069.0,48076.0,5.05210928 +2024-02-21 04:00:00,48085.0,48187.0,47912.0,47936.0,14.83071173 +2024-02-21 06:00:00,47931.0,48010.0,47648.0,47734.0,48.48040882 +2024-02-21 08:00:00,47728.0,47933.0,47280.0,47350.0,80.55590487 +2024-02-21 10:00:00,47348.0,47637.0,47082.0,47218.0,91.28649586 +2024-02-21 12:00:00,47217.0,47895.0,46956.0,47376.0,88.10436179 +2024-02-21 14:00:00,47382.0,47496.0,47000.0,47371.0,86.9334301 +2024-02-21 16:00:00,47368.0,47581.0,47127.0,47163.0,59.29742649 +2024-02-21 18:00:00,47162.0,47309.0,46900.0,47245.0,75.64170296 +2024-02-21 20:00:00,47249.0,47544.0,47065.0,47538.0,52.73593793 +2024-02-21 22:00:00,47542.0,48046.0,47384.0,47962.0,44.89053798 +2024-02-22 00:00:00,47949.0,47965.0,47262.0,47359.0,15.93880521 +2024-02-22 02:00:00,47328.0,47732.0,47328.0,47669.0,6.18319113 +2024-02-22 04:00:00,47667.0,47706.0,47446.0,47561.0,11.97546229 +2024-02-22 06:00:00,47562.0,47873.0,47559.0,47790.0,42.02106775 +2024-02-22 08:00:00,47788.0,47984.0,47520.0,47895.0,57.06653177 +2024-02-22 10:00:00,47898.0,47898.0,47503.0,47567.0,43.16246141 +2024-02-22 12:00:00,47564.0,47684.0,47043.0,47282.0,69.02007587 +2024-02-22 14:00:00,47302.0,47777.0,47215.0,47720.0,51.56036511 +2024-02-22 16:00:00,47720.0,47833.0,47527.0,47785.0,44.81028188 +2024-02-22 18:00:00,47774.0,47779.0,47557.0,47592.0,31.87826141 +2024-02-22 20:00:00,47592.0,48102.0,47552.0,47740.0,65.67894004 +2024-02-22 22:00:00,47750.0,47788.0,47308.0,47382.0,25.38945449 +2024-02-23 00:00:00,47382.0,47599.0,47363.0,47410.0,8.48125819 +2024-02-23 02:00:00,47390.0,47493.0,47115.0,47212.0,17.40105647 +2024-02-23 04:00:00,47212.0,47397.0,47138.0,47354.0,25.35573681 +2024-02-23 06:00:00,47353.0,47432.0,47008.0,47042.0,47.49122946 +2024-02-23 08:00:00,47043.0,47250.0,47007.0,47178.0,55.50982524 +2024-02-23 10:00:00,47175.0,47359.0,47130.0,47323.0,34.48069553 +2024-02-23 12:00:00,47333.0,47333.0,47012.0,47151.0,37.45807119 +2024-02-23 14:00:00,47154.0,47387.0,46908.0,47048.0,83.36015946 +2024-02-23 16:00:00,47051.0,47250.0,46809.0,47238.0,73.34733067 +2024-02-23 18:00:00,47248.0,47290.0,47108.0,47200.0,23.19121721 +2024-02-23 20:00:00,47208.0,47268.0,47094.0,47100.0,21.06307109 +2024-02-23 22:00:00,47099.0,47131.0,46662.0,46869.0,52.933981 +2024-02-24 00:00:00,46858.0,46997.0,46756.0,46770.0,53.13372804 +2024-02-24 02:00:00,46763.0,46964.0,46760.0,46963.0,31.9870185 +2024-02-24 04:00:00,46966.0,47152.0,46962.0,47131.0,6.13415091 +2024-02-24 06:00:00,47141.0,47205.0,47032.0,47181.0,20.71806995 +2024-02-24 08:00:00,47181.0,47235.0,47076.0,47212.0,22.223998 +2024-02-24 10:00:00,47212.0,47279.0,47160.0,47210.0,21.90501202 +2024-02-24 12:00:00,47210.0,47251.0,47139.0,47223.0,17.93176723 +2024-02-24 14:00:00,47221.0,47239.0,47159.0,47186.0,11.81020452 +2024-02-24 16:00:00,47194.0,47738.0,47188.0,47573.0,49.90029673 +2024-02-24 18:00:00,47585.0,47723.0,47467.0,47607.0,23.8799571 +2024-02-24 20:00:00,47608.0,47694.0,47499.0,47620.0,24.70933736 +2024-02-24 22:00:00,47620.0,47719.0,47570.0,47621.0,16.20659186 +2024-02-25 00:00:00,47606.0,47734.0,47502.0,47728.0,4.57367012 +2024-02-25 02:00:00,47731.0,47866.0,47500.0,47645.0,12.87233083 +2024-02-25 04:00:00,47652.0,47742.0,47586.0,47681.0,5.69059088 +2024-02-25 06:00:00,47685.0,47810.0,47647.0,47746.0,17.92868389 +2024-02-25 08:00:00,47747.0,47816.0,47599.0,47701.0,20.82211938 +2024-02-25 10:00:00,47692.0,47744.0,47612.0,47696.0,16.81019667 +2024-02-25 12:00:00,47696.0,47748.0,47631.0,47678.0,14.21310186 +2024-02-25 14:00:00,47684.0,47815.0,47511.0,47586.0,26.16966007 +2024-02-25 16:00:00,47583.0,47690.0,47395.0,47640.0,31.23660555 +2024-02-25 18:00:00,47659.0,47763.0,47572.0,47710.0,27.11898546 +2024-02-25 20:00:00,47710.0,47979.0,47705.0,47828.0,69.45209128 +2024-02-25 22:00:00,47826.0,47953.0,47739.0,47814.0,24.13835257 +2024-02-26 00:00:00,47815.0,47860.0,47589.0,47590.0,9.11623927 +2024-02-26 02:00:00,47594.0,47663.0,47527.0,47660.0,2.76284748 +2024-02-26 04:00:00,47663.0,47682.0,47538.0,47646.0,8.51839505 +2024-02-26 06:00:00,47646.0,47677.0,47351.0,47354.0,46.57370643 +2024-02-26 08:00:00,47352.0,47459.0,47000.0,47020.0,62.05513949 +2024-02-26 10:00:00,47017.0,47282.0,47014.0,47097.0,43.83114899 +2024-02-26 12:00:00,47097.0,47408.0,46952.0,47186.0,61.70043045 +2024-02-26 14:00:00,47181.0,48678.0,47169.0,48663.0,211.48668938 +2024-02-26 16:00:00,48651.0,49370.0,48570.0,49225.0,298.76164366 +2024-02-26 18:00:00,49228.0,50192.0,49098.0,50128.0,332.48853018 +2024-02-26 20:00:00,50129.0,50500.0,49495.0,50218.0,301.55174172 +2024-02-26 22:00:00,50217.0,50350.0,49987.0,50030.0,71.32719418 +2024-02-27 00:00:00,50030.0,51197.0,50025.0,51197.0,71.68368374 +2024-02-27 02:00:00,51197.0,52000.0,51055.0,51174.0,118.45572191 +2024-02-27 04:00:00,51178.0,51800.0,51150.0,51638.0,113.03484239 +2024-02-27 06:00:00,51638.0,52000.0,51254.0,51604.0,208.50792294 +2024-02-27 08:00:00,51611.0,52286.0,51579.0,52168.0,198.51947126 +2024-02-27 10:00:00,52167.0,52400.0,51852.0,52067.0,180.34757677 +2024-02-27 12:00:00,52075.0,52866.0,52001.0,52658.0,198.94493066 +2024-02-27 14:00:00,52659.0,52869.0,52114.0,52296.0,215.74571045 +2024-02-27 16:00:00,52296.0,52650.0,51762.0,52258.0,173.88973562 +2024-02-27 18:00:00,52260.0,53056.0,52170.0,52795.0,126.79784645 +2024-02-27 20:00:00,52794.0,52827.0,52141.0,52255.0,123.46214965 +2024-02-27 22:00:00,52255.0,52649.0,52186.0,52580.0,41.46446213 +2024-02-28 00:00:00,52593.0,52653.0,52364.0,52364.0,11.10313513 +2024-02-28 02:00:00,52373.0,52586.0,52301.0,52541.0,7.80183049 +2024-02-28 04:00:00,52542.0,52861.0,52514.0,52723.0,10.16434396 +2024-02-28 06:00:00,52727.0,53999.0,52640.0,53839.0,193.59016834 +2024-02-28 08:00:00,53839.0,55042.0,53771.0,54909.0,380.61678974 +2024-02-28 10:00:00,54897.0,54981.0,53634.0,54444.0,239.10718823 +2024-02-28 12:00:00,54444.0,56251.0,54394.0,55858.0,319.8288455 +2024-02-28 14:00:00,55841.0,56694.0,55228.0,56282.0,367.23516563 +2024-02-28 16:00:00,56288.0,59000.0,49069.0,56595.0,1180.26299716 +2024-02-28 18:00:00,56608.0,56746.0,53389.0,56219.0,590.31851572 +2024-02-28 20:00:00,56218.0,56357.0,55001.0,55779.0,287.23383296 +2024-02-28 22:00:00,55762.0,57800.0,55715.0,57552.0,179.3858613 +2024-02-29 00:00:00,57550.0,57550.0,56177.0,56497.0,127.97745063 +2024-02-29 02:00:00,56520.0,56871.0,56260.0,56694.0,76.39122889 +2024-02-29 04:00:00,56685.0,57765.0,56492.0,57650.0,80.19651952 +2024-02-29 06:00:00,57650.0,58748.0,57200.0,57762.0,278.28682085 +2024-02-29 08:00:00,57768.0,58242.0,57328.0,57735.0,153.31592891 +2024-02-29 10:00:00,57728.0,58378.0,57179.0,58047.0,148.46371437 +2024-02-29 12:00:00,58028.0,58196.0,57325.0,58067.0,115.96518048 +2024-02-29 14:00:00,58083.0,58574.0,57663.0,57947.0,183.54424962 +2024-02-29 16:00:00,57931.0,58094.0,55555.0,56375.0,377.76694789 +2024-02-29 18:00:00,56360.0,57000.0,55756.0,56977.0,262.70301003 +2024-02-29 20:00:00,56974.0,57620.0,56061.0,56770.0,191.67762358 +2024-02-29 22:00:00,56781.0,56935.0,56134.0,56545.0,70.63184836 +2024-03-01 00:00:00,56545.0,57104.0,56445.0,56515.0,32.14903935 +2024-03-01 02:00:00,56513.0,56558.0,56144.0,56457.0,19.68514445 +2024-03-01 04:00:00,56438.0,56853.0,56397.0,56648.0,29.67601775 +2024-03-01 06:00:00,56635.0,57051.0,56513.0,56735.0,76.85255948 +2024-03-01 08:00:00,56752.0,57554.0,56651.0,57464.0,112.22123826 +2024-03-01 10:00:00,57436.0,57594.0,57111.0,57158.0,84.98961591 +2024-03-01 12:00:00,57159.0,57973.0,57154.0,57757.0,109.9702502 +2024-03-01 14:00:00,57757.0,57779.0,56392.0,56506.0,148.33844816 +2024-03-01 16:00:00,56506.0,57300.0,56465.0,57129.0,101.404243 +2024-03-01 18:00:00,57132.0,57648.0,57056.0,57388.0,80.14609614 +2024-03-01 20:00:00,57414.0,58200.0,57395.0,57629.0,182.84107809 +2024-03-01 22:00:00,57629.0,57854.0,57466.0,57517.0,68.12414627 +2024-03-02 00:00:00,57503.0,57553.0,57135.0,57217.0,23.28735762 +2024-03-02 02:00:00,57207.0,57580.0,57140.0,57467.0,30.40623056 +2024-03-02 04:00:00,57458.0,57460.0,56963.0,57195.0,27.55298222 +2024-03-02 06:00:00,57204.0,57451.0,57001.0,57224.0,52.28718051 +2024-03-02 08:00:00,57214.0,57315.0,56885.0,57043.0,68.1990754 +2024-03-02 10:00:00,57055.0,57232.0,57009.0,57042.0,71.4011921 +2024-03-02 12:00:00,57042.0,57332.0,57021.0,57021.0,48.95837812 +2024-03-02 14:00:00,57021.0,57196.0,56800.0,57007.0,54.55325943 +2024-03-02 16:00:00,57004.0,57166.0,56900.0,57002.0,41.17940975 +2024-03-02 18:00:00,57002.0,57313.0,56982.0,57312.0,42.03074797 +2024-03-02 20:00:00,57314.0,57389.0,56981.0,57087.0,53.46905923 +2024-03-02 22:00:00,57087.0,57277.0,56902.0,57178.0,38.12364431 +2024-03-03 00:00:00,57138.0,57185.0,56943.0,57022.0,14.17845356 +2024-03-03 04:00:00,57053.0,57203.0,57053.0,57077.0,13.69011159 +2024-03-03 06:00:00,57060.0,57221.0,56602.0,56859.0,76.60727468 +2024-03-03 08:00:00,56858.0,57150.0,56665.0,56962.0,65.93235513 +2024-03-03 10:00:00,56966.0,57044.0,56851.0,57018.0,45.24632944 +2024-03-03 12:00:00,57016.0,57793.0,57009.0,57556.0,106.70057975 +2024-03-03 14:00:00,57556.0,57593.0,57285.0,57354.0,52.36246195 +2024-03-03 16:00:00,57339.0,58030.0,57288.0,57920.0,102.87365611 +2024-03-03 20:00:00,57918.0,57919.0,57821.0,57890.0,16.87454634 +2024-03-03 22:00:00,57917.0,58400.0,57814.0,58199.0,79.41346253 +2024-03-04 00:00:00,58203.0,59153.0,57400.0,58553.0,109.61355139 +2024-03-04 02:00:00,58555.0,58891.0,58195.0,58529.0,34.14185728 +2024-03-04 04:00:00,58527.0,58866.0,58312.0,58455.0,67.54703399 +2024-03-04 06:00:00,58449.0,59365.0,58435.0,59119.0,149.89319463 +2024-03-04 08:00:00,59116.0,60529.0,59041.0,60248.0,395.98510805 +2024-03-04 10:00:00,60258.0,60259.0,59723.0,60162.0,156.62915545 +2024-03-04 12:00:00,60184.0,60530.0,59854.0,60042.0,130.73124567 +2024-03-04 14:00:00,60043.0,61285.0,59580.0,61174.0,296.50633413 +2024-03-04 16:00:00,61174.0,62109.0,60801.0,61507.0,326.63678234 +2024-03-04 18:00:00,61525.0,62100.0,60090.0,62040.0,268.27480196 +2024-03-04 20:00:00,62042.0,62435.0,61474.0,62085.0,243.2865199 +2024-03-04 22:00:00,62095.0,63000.0,61950.0,62858.0,259.33044744 +2024-03-05 00:00:00,62870.0,63211.0,62332.0,63076.0,180.19022089 +2024-03-05 02:00:00,63061.0,63103.0,62201.0,62735.0,51.2985841 +2024-03-05 04:00:00,62736.0,62971.0,59800.0,61574.0,219.43691859 +2024-03-05 06:00:00,61588.0,62224.0,60915.0,60951.0,203.59128265 +2024-03-05 08:00:00,60945.0,61712.0,60344.0,61196.0,159.69387106 +2024-03-05 10:00:00,61185.0,61858.0,61185.0,61470.0,100.20934063 +2024-03-05 12:00:00,61459.0,62715.0,61391.0,62523.0,174.66568943 +2024-03-05 14:00:00,62521.0,63534.0,61101.0,61403.0,414.96751875 +2024-03-05 16:00:00,61409.0,63000.0,49220.0,60414.0,1421.36608378 +2024-03-05 18:00:00,60414.0,61690.0,52500.0,56145.0,867.21580064 +2024-03-05 20:00:00,55965.0,60100.0,54000.0,58792.0,657.39871975 +2024-03-05 22:00:00,58828.0,59645.0,57659.0,58895.0,130.91370802 +2024-03-06 00:00:00,58848.0,59297.0,58250.0,58287.0,37.76200807 +2024-03-06 02:00:00,58285.0,58598.0,57923.0,58409.0,44.26665628 +2024-03-06 04:00:00,58430.0,61410.0,58403.0,61409.0,130.74725316 +2024-03-06 06:00:00,61342.0,61648.0,60489.0,61566.0,154.69171943 +2024-03-06 08:00:00,61579.0,62500.0,60809.0,60831.0,183.94863266 +2024-03-06 10:00:00,60839.0,61927.0,60838.0,61909.0,95.75613127 +2024-03-06 12:00:00,61914.0,62150.0,59557.0,60966.0,187.15792102 +2024-03-06 14:00:00,60944.0,61764.0,60001.0,60917.0,144.72118799 +2024-03-06 16:00:00,60934.0,61799.0,60800.0,61799.0,127.65871438 +2024-03-06 18:00:00,61790.0,61896.0,61154.0,61289.0,109.13301004 +2024-03-06 20:00:00,61289.0,61867.0,60850.0,60935.0,119.59852305 +2024-03-06 22:00:00,60942.0,61006.0,60292.0,60637.0,67.3866193 +2024-03-07 00:00:00,60637.0,60909.0,60200.0,60879.0,24.34643062 +2024-03-07 02:00:00,60901.0,60977.0,60413.0,60423.0,10.76955403 +2024-03-07 04:00:00,60440.0,60706.0,60212.0,60333.0,33.71917426 +2024-03-07 06:00:00,60331.0,60969.0,60208.0,60907.0,87.62058563 +2024-03-07 08:00:00,60896.0,61512.0,60866.0,61211.0,80.87703589 +2024-03-07 10:00:00,61212.0,61721.0,61046.0,61400.0,68.00151812 +2024-03-07 12:00:00,61400.0,61612.0,61115.0,61523.0,106.30289379 +2024-03-07 14:00:00,61531.0,62324.0,61077.0,61622.0,186.62841995 +2024-03-07 16:00:00,61603.0,62100.0,61384.0,61829.0,102.45686266 +2024-03-07 18:00:00,61833.0,62046.0,61441.0,61687.0,78.43913872 +2024-03-07 20:00:00,61688.0,62047.0,61307.0,61413.0,103.46724003 +2024-03-07 22:00:00,61436.0,61645.0,61002.0,61050.0,61.49836743 +2024-03-08 00:00:00,61049.0,61467.0,61000.0,61193.0,42.91566992 +2024-03-08 02:00:00,61180.0,61467.0,61109.0,61368.0,18.73401808 +2024-03-08 04:00:00,61357.0,61457.0,61061.0,61191.0,19.99887619 +2024-03-08 06:00:00,61187.0,61899.0,61134.0,61558.0,55.56976565 +2024-03-08 08:00:00,61565.0,61753.0,61428.0,61468.0,58.43258879 +2024-03-08 10:00:00,61469.0,61985.0,61440.0,61985.0,80.5446041 +2024-03-08 12:00:00,61975.0,62010.0,61616.0,61902.0,137.78277253 +2024-03-08 14:00:00,61920.0,63953.0,61300.0,61724.0,512.56606204 +2024-03-08 16:00:00,61787.0,62947.0,60384.0,62550.0,295.05214479 +2024-03-08 18:00:00,62510.0,62963.0,62285.0,62930.0,127.52043139 +2024-03-08 20:00:00,62930.0,63389.0,62108.0,62448.0,216.76778512 +2024-03-08 22:00:00,62443.0,62624.0,62274.0,62353.0,67.72174329 +2024-03-09 00:00:00,62358.0,62474.0,62128.0,62157.0,34.5753686 +2024-03-09 02:00:00,62154.0,62546.0,62108.0,62504.0,12.07323238 +2024-03-09 04:00:00,62495.0,62582.0,62382.0,62492.0,15.20493126 +2024-03-09 06:00:00,62480.0,62767.0,62410.0,62514.0,61.14293463 +2024-03-09 08:00:00,62512.0,62695.0,62408.0,62572.0,73.69101562 +2024-03-09 10:00:00,62566.0,62613.0,62273.0,62503.0,64.25600388 +2024-03-09 12:00:00,62512.0,62687.0,62417.0,62512.0,63.26189004 +2024-03-09 14:00:00,62512.0,62563.0,62342.0,62503.0,72.27867214 +2024-03-09 16:00:00,62503.0,62547.0,62295.0,62387.0,59.45448245 +2024-03-09 18:00:00,62385.0,62544.0,62351.0,62409.0,44.85877207 +2024-03-09 20:00:00,62409.0,62599.0,62397.0,62558.0,33.88713112 +2024-03-09 22:00:00,62558.0,62597.0,62414.0,62483.0,40.77490751 +2024-03-10 00:00:00,62473.0,63250.0,62401.0,62966.0,34.78663906 +2024-03-10 02:00:00,62985.0,63250.0,62792.0,63184.0,38.41943004 +2024-03-10 04:00:00,63178.0,63578.0,63086.0,63348.0,60.83562959 +2024-03-10 06:00:00,63348.0,63483.0,63111.0,63411.0,55.8845518 +2024-03-10 08:00:00,63436.0,63857.0,63274.0,63796.0,107.49897139 +2024-03-10 10:00:00,63820.0,63888.0,63490.0,63620.0,97.38697004 +2024-03-10 12:00:00,63621.0,63895.0,63166.0,63411.0,74.37306395 +2024-03-10 14:00:00,63407.0,63536.0,62800.0,63306.0,93.68955818 +2024-03-10 16:00:00,63299.0,63829.0,63279.0,63546.0,61.06194075 +2024-03-10 18:00:00,63533.0,63591.0,63251.0,63517.0,53.06308614 +2024-03-10 20:00:00,63518.0,63577.0,63202.0,63202.0,48.0273497 +2024-03-10 22:00:00,63216.0,63226.0,62343.0,63064.0,93.0604624 +2024-03-11 00:00:00,63071.0,63077.0,61528.0,62526.0,78.67925708 +2024-03-11 02:00:00,62537.0,62796.0,62473.0,62779.0,13.02160889 +2024-03-11 04:00:00,62777.0,62995.0,62691.0,62769.0,25.166237 +2024-03-11 06:00:00,62768.0,65058.0,62700.0,64702.0,390.69461559 +2024-03-11 08:00:00,64701.0,65600.0,64701.0,65540.0,243.83368329 +2024-03-11 10:00:00,65551.0,65871.0,64951.0,65250.0,182.46169881 +2024-03-11 12:00:00,65258.0,66142.0,65118.0,65424.0,215.79311994 +2024-03-11 14:00:00,65443.0,66500.0,65432.0,65832.0,208.03194438 +2024-03-11 16:00:00,65822.0,66372.0,65673.0,66245.0,149.60566059 +2024-03-11 18:00:00,66244.0,66500.0,65563.0,65741.0,194.28880777 +2024-03-11 20:00:00,65742.0,66288.0,65604.0,66217.0,92.31318478 +2024-03-11 22:00:00,66211.0,66401.0,65777.0,65794.0,93.0949206 +2024-03-12 00:00:00,65793.0,66225.0,65656.0,66166.0,44.68707977 +2024-03-12 02:00:00,66139.0,66187.0,65201.0,65339.0,60.32907837 +2024-03-12 04:00:00,65334.0,65767.0,64994.0,65737.0,82.81480849 +2024-03-12 06:00:00,65723.0,66100.0,65202.0,65927.0,103.25617519 +2024-03-12 08:00:00,65924.0,66000.0,65279.0,65800.0,143.69021125 +2024-03-12 10:00:00,65798.0,66200.0,65528.0,65937.0,81.11983493 +2024-03-12 12:00:00,65938.0,66318.0,65525.0,66304.0,114.17225245 +2024-03-12 14:00:00,66312.0,66935.0,64978.0,65734.0,212.69916263 +2024-03-12 16:00:00,65735.0,65833.0,62900.0,65248.0,690.95678855 +2024-03-12 18:00:00,65248.0,65667.0,64671.0,65379.0,211.37153204 +2024-03-12 20:00:00,65381.0,65387.0,64600.0,64810.0,110.82300406 +2024-03-12 22:00:00,64805.0,65470.0,64674.0,65410.0,61.90239658 +2024-03-13 00:00:00,65399.0,65975.0,65228.0,65913.0,25.9778641 +2024-03-13 02:00:00,65903.0,66070.0,65767.0,65913.0,25.56582019 +2024-03-13 04:00:00,65931.0,66079.0,65799.0,66009.0,33.96529001 +2024-03-13 06:00:00,66010.0,66944.0,65953.0,66694.0,148.86704787 +2024-03-13 08:00:00,66698.0,67451.0,66663.0,67162.0,218.14498998 +2024-03-13 10:00:00,67162.0,67249.0,66803.0,66840.0,90.40221379 +2024-03-13 12:00:00,66849.0,66933.0,65501.0,66078.0,112.37756197 +2024-03-13 14:00:00,66085.0,66904.0,65939.0,66495.0,107.77654126 +2024-03-13 16:00:00,66493.0,66930.0,66237.0,66574.0,87.83954535 +2024-03-13 18:00:00,66582.0,67150.0,66501.0,67130.0,73.67348013 +2024-03-13 20:00:00,67124.0,67164.0,66690.0,66960.0,91.62454188 +2024-03-13 22:00:00,66967.0,66975.0,66564.0,66783.0,34.53345268 +2024-03-14 00:00:00,66780.0,66875.0,66279.0,66645.0,22.65630078 +2024-03-14 02:00:00,66640.0,67003.0,66564.0,66987.0,12.5699217 +2024-03-14 04:00:00,66987.0,67326.0,66490.0,66908.0,40.83740557 +2024-03-14 06:00:00,66909.0,67450.0,66846.0,66969.0,102.38779567 +2024-03-14 08:00:00,66968.0,67218.0,66873.0,67039.0,55.93939273 +2024-03-14 10:00:00,67037.0,67062.0,66416.0,66682.0,127.8490715 +2024-03-14 12:00:00,66678.0,66827.0,65449.0,65908.0,160.35129312 +2024-03-14 14:00:00,65923.0,66617.0,64842.0,65128.0,228.46701145 +2024-03-14 16:00:00,65116.0,65664.0,64100.0,65314.0,258.49561088 +2024-03-14 18:00:00,65314.0,65314.0,63000.0,63699.0,464.65473747 +2024-03-14 20:00:00,63698.0,65470.0,63590.0,65367.0,223.73674166 +2024-03-14 22:00:00,65366.0,65962.0,65362.0,65663.0,86.83844325 +2024-03-15 00:00:00,65667.0,66575.0,65560.0,65843.0,43.73038473 +2024-03-15 02:00:00,65830.0,65948.0,61321.0,62749.0,187.33360645 +2024-03-15 04:00:00,62779.0,63444.0,61623.0,61958.0,592.09948713 +2024-03-15 06:00:00,61958.0,63280.0,61935.0,62913.0,251.02421169 +2024-03-15 08:00:00,62915.0,63058.0,60003.0,62179.0,628.69438134 +2024-03-15 10:00:00,62172.0,62449.0,61221.0,62156.0,232.16433667 +2024-03-15 12:00:00,62153.0,63108.0,61943.0,62955.0,191.00077027 +2024-03-15 14:00:00,62954.0,63202.0,62400.0,62682.0,120.06343781 +2024-03-15 16:00:00,62670.0,62879.0,62086.0,62682.0,94.36899156 +2024-03-15 18:00:00,62699.0,64934.0,62699.0,63431.0,270.23387128 +2024-03-15 20:00:00,63413.0,63428.0,62000.0,62757.0,125.53879741 +2024-03-15 22:00:00,62800.0,64100.0,62714.0,63859.0,69.99003785 +2024-03-16 00:00:00,63894.0,64373.0,63438.0,63574.0,44.85239415 +2024-03-16 02:00:00,63661.0,63778.0,63335.0,63584.0,19.92262535 +2024-03-16 04:00:00,63535.0,63654.0,63024.0,63376.0,36.97983394 +2024-03-16 06:00:00,63377.0,63896.0,63351.0,63862.0,80.06481004 +2024-03-16 08:00:00,63876.0,63876.0,63388.0,63509.0,87.35678772 +2024-03-16 10:00:00,63507.0,63546.0,62254.0,62825.0,115.56917284 +2024-03-16 12:00:00,62806.0,62948.0,62254.0,62312.0,62.2024594 +2024-03-16 14:00:00,62312.0,63022.0,62136.0,62912.0,73.0252944 +2024-03-16 16:00:00,62901.0,62921.0,61730.0,61829.0,118.6639591 +2024-03-16 18:00:00,61855.0,62200.0,60100.0,61439.0,319.11244331 +2024-03-16 20:00:00,61439.0,62000.0,60576.0,60748.0,193.35444266 +2024-03-16 22:00:00,60757.0,61228.0,59335.0,59842.0,298.76409404 +2024-03-17 00:00:00,59836.0,60783.0,59700.0,60671.0,94.77999288 +2024-03-17 02:00:00,60665.0,61129.0,60542.0,61052.0,28.01803713 +2024-03-17 04:00:00,61048.0,61087.0,60566.0,60784.0,27.95705433 +2024-03-17 06:00:00,60792.0,60911.0,59050.0,60080.0,311.5208394 +2024-03-17 08:00:00,60075.0,61409.0,59759.0,60979.0,259.16481132 +2024-03-17 10:00:00,60992.0,62069.0,60934.0,61549.0,173.50601556 +2024-03-17 12:00:00,61552.0,62199.0,60990.0,61655.0,82.96378785 +2024-03-17 14:00:00,61648.0,62856.0,61462.0,62550.0,125.96310052 +2024-03-17 16:00:00,62550.0,63450.0,62383.0,63064.0,148.35108034 +2024-03-17 18:00:00,63040.0,63700.0,62525.0,63199.0,122.72918011 +2024-03-17 20:00:00,63208.0,63286.0,62450.0,62587.0,78.43911617 +2024-03-17 22:00:00,62605.0,63359.0,62605.0,62913.0,54.28180571 +2024-03-18 00:00:00,62901.0,62925.0,61381.0,62146.0,67.51058196 +2024-03-18 02:00:00,62106.0,62577.0,61894.0,62398.0,19.96922464 +2024-03-18 04:00:00,62341.0,63320.0,62150.0,63127.0,18.19846076 +2024-03-18 06:00:00,63124.0,63152.0,62501.0,62633.0,50.13803764 +2024-03-18 08:00:00,62644.0,62644.0,61724.0,62202.0,118.4653785 +2024-03-18 10:00:00,62184.0,62769.0,62072.0,62562.0,55.9009098 +2024-03-18 12:00:00,62566.0,62958.0,61647.0,62001.0,86.05217011 +2024-03-18 14:00:00,62004.0,62239.0,61136.0,61983.0,149.75277135 +2024-03-18 16:00:00,61978.0,62575.0,61184.0,61992.0,104.69130798 +2024-03-18 18:00:00,61996.0,62067.0,61504.0,61568.0,43.24637848 +2024-03-18 20:00:00,61575.0,62385.0,61575.0,62130.0,66.90983887 +2024-03-18 22:00:00,62100.0,62498.0,61828.0,62151.0,39.58481433 +2024-03-19 00:00:00,62134.0,62600.0,60575.0,60634.0,55.57310437 +2024-03-19 02:00:00,60629.0,61081.0,59725.0,60603.0,81.48633762 +2024-03-19 04:00:00,60605.0,60727.0,59843.0,60188.0,35.90560735 +2024-03-19 06:00:00,59952.0,60222.0,58355.0,59533.0,401.21016494 +2024-03-19 08:00:00,59536.0,59538.0,57903.0,59146.0,377.88988414 +2024-03-19 10:00:00,59145.0,59145.0,57000.0,57979.0,336.71715133 +2024-03-19 12:00:00,57978.0,58843.0,57916.0,58573.0,207.55026392 +2024-03-19 14:00:00,58561.0,59045.0,57404.0,58962.0,229.9165329 +2024-03-19 16:00:00,58960.0,60618.0,58843.0,59746.0,337.65575837 +2024-03-19 18:00:00,59745.0,60172.0,59113.0,59277.0,115.32198913 +2024-03-19 20:00:00,59284.0,59375.0,58433.0,58822.0,125.86607411 +2024-03-19 22:00:00,58808.0,58879.0,56564.0,56928.0,208.87232352 +2024-03-20 00:00:00,56919.0,58256.0,56818.0,57304.0,65.26390282 +2024-03-20 02:00:00,57353.0,58327.0,56687.0,56871.0,34.33606376 +2024-03-20 04:00:00,56877.0,57283.0,55885.0,56597.0,219.63321518 +2024-03-20 06:00:00,56566.0,58245.0,56543.0,58045.0,242.47989816 +2024-03-20 08:00:00,58044.0,58500.0,57809.0,58396.0,135.15175575 +2024-03-20 10:00:00,58397.0,59525.0,58000.0,58593.0,147.59855884 +2024-03-20 12:00:00,58594.0,59397.0,58218.0,58698.0,123.63852438 +2024-03-20 14:00:00,58688.0,59404.0,58475.0,58631.0,121.62204159 +2024-03-20 16:00:00,58628.0,59595.0,57141.0,59013.0,250.43466923 +2024-03-20 18:00:00,58988.0,60537.0,58849.0,60304.0,301.01941914 +2024-03-20 20:00:00,60313.0,62499.0,58250.0,62111.0,484.10015065 +2024-03-20 22:00:00,62115.0,62474.0,61708.0,62092.0,126.26107297 +2024-03-21 00:00:00,62092.0,62500.0,61740.0,62049.0,32.47326037 +2024-03-21 02:00:00,62072.0,62166.0,60723.0,60993.0,55.82131275 +2024-03-21 04:00:00,61003.0,61494.0,60472.0,61415.0,66.34978011 +2024-03-21 06:00:00,61415.0,61695.0,61292.0,61413.0,111.60054389 +2024-03-21 08:00:00,61417.0,62157.0,61177.0,61320.0,98.9870822 +2024-03-21 10:00:00,61329.0,61682.0,61151.0,61520.0,42.40271918 +2024-03-21 12:00:00,61545.0,62200.0,61266.0,61320.0,77.56673184 +2024-03-21 14:00:00,61372.0,62000.0,60750.0,61299.0,88.44664254 +2024-03-21 16:00:00,61299.0,61738.0,60513.0,60550.0,70.70439392 +2024-03-21 18:00:00,60553.0,60691.0,59690.0,60101.0,171.48865965 +2024-03-21 20:00:00,60088.0,60732.0,59456.0,60475.0,113.65803274 +2024-03-21 22:00:00,60467.0,60667.0,60128.0,60328.0,29.77094281 +2024-03-22 00:00:00,60326.0,60759.0,60150.0,60174.0,13.43670425 +2024-03-22 02:00:00,60175.0,61072.0,60067.0,60893.0,16.57775278 +2024-03-22 04:00:00,60894.0,61350.0,60723.0,61350.0,39.46636816 +2024-03-22 06:00:00,61350.0,61577.0,61117.0,61172.0,53.71393238 +2024-03-22 08:00:00,61175.0,61394.0,60454.0,60605.0,62.2587043 +2024-03-22 10:00:00,60617.0,60731.0,59271.0,59420.0,136.53217877 +2024-03-22 12:00:00,59420.0,59791.0,58037.0,58240.0,157.17803443 +2024-03-22 14:00:00,58230.0,59588.0,57840.0,59152.0,251.5598457 +2024-03-22 16:00:00,59164.0,59164.0,58187.0,58935.0,83.84299663 +2024-03-22 18:00:00,58936.0,59464.0,58807.0,59238.0,50.59055757 +2024-03-22 20:00:00,59235.0,59314.0,57745.0,58364.0,93.20380802 +2024-03-22 22:00:00,58383.0,59164.0,58002.0,59158.0,59.20397979 +2024-03-23 00:00:00,59149.0,59610.0,58912.0,59411.0,12.79336022 +2024-03-23 02:00:00,59426.0,59653.0,58403.0,58919.0,14.29819638 +2024-03-23 04:00:00,58894.0,59429.0,58876.0,59390.0,10.30556983 +2024-03-23 06:00:00,59390.0,60124.0,59306.0,59874.0,44.0204366 +2024-03-23 08:00:00,59875.0,60123.0,59500.0,59750.0,48.32224336 +2024-03-23 10:00:00,59757.0,60132.0,59509.0,59899.0,41.5848601 +2024-03-23 12:00:00,59906.0,60158.0,59609.0,59881.0,61.67941533 +2024-03-23 14:00:00,59881.0,60597.0,59700.0,60349.0,89.17846004 +2024-03-23 16:00:00,60349.0,61175.0,60177.0,60825.0,98.02056178 +2024-03-23 18:00:00,60801.0,60816.0,60000.0,60076.0,54.22626502 +2024-03-23 20:00:00,60074.0,60368.0,59868.0,60158.0,33.62961353 +2024-03-23 22:00:00,60141.0,60251.0,59150.0,59251.0,49.35593708 +2024-03-24 00:00:00,59243.0,59916.0,59213.0,59734.0,24.98160242 +2024-03-24 02:00:00,59696.0,59753.0,59209.0,59278.0,12.63548094 +2024-03-24 04:00:00,59259.0,59692.0,59090.0,59587.0,43.34611706 +2024-03-24 06:00:00,59578.0,59873.0,59359.0,59866.0,34.52304262 +2024-03-24 08:00:00,59866.0,60500.0,59768.0,60165.0,50.58645867 +2024-03-24 10:00:00,60161.0,60601.0,60014.0,60535.0,85.80440924 +2024-03-24 12:00:00,60536.0,60950.0,60384.0,60513.0,68.50223546 +2024-03-24 14:00:00,60510.0,61016.0,60472.0,60800.0,89.80921874 +2024-03-24 16:00:00,60791.0,60945.0,59834.0,60504.0,90.96954222 +2024-03-24 18:00:00,60494.0,61129.0,60494.0,60927.0,76.68480714 +2024-03-24 20:00:00,60940.0,61661.0,60825.0,61551.0,121.53662286 +2024-03-24 22:00:00,61577.0,62560.0,61535.0,62171.0,118.73523629 +2024-03-25 00:00:00,62179.0,62269.0,61404.0,61516.0,46.38199922 +2024-03-25 02:00:00,61523.0,62308.0,61356.0,62287.0,41.22020599 +2024-03-25 04:00:00,62284.0,62647.0,62017.0,62270.0,67.32579028 +2024-03-25 06:00:00,62287.0,62323.0,61703.0,61812.0,83.43303475 +2024-03-25 08:00:00,61812.0,62199.0,61757.0,62051.0,48.28772958 +2024-03-25 10:00:00,62060.0,62302.0,61725.0,61755.0,41.56054157 +2024-03-25 12:00:00,61742.0,62800.0,61710.0,62800.0,68.2021475 +2024-03-25 14:00:00,62799.0,64581.0,62468.0,64381.0,421.40651277 +2024-03-25 16:00:00,64391.0,65337.0,64008.0,65001.0,251.61262622 +2024-03-25 18:00:00,65002.0,65499.0,64844.0,65482.0,176.41273692 +2024-03-25 20:00:00,65480.0,65600.0,63975.0,64354.0,292.52259669 +2024-03-25 22:00:00,64342.0,65139.0,64250.0,64398.0,76.40805764 +2024-03-26 00:00:00,64380.0,64762.0,64234.0,64731.0,16.43534792 +2024-03-26 02:00:00,64710.0,65071.0,64540.0,64940.0,21.07771009 +2024-03-26 04:00:00,64940.0,65188.0,64771.0,64786.0,59.56278013 +2024-03-26 06:00:00,64783.0,65985.0,64736.0,65015.0,120.67439235 +2024-03-26 08:00:00,65023.0,65715.0,64837.0,65581.0,89.70566517 +2024-03-26 10:00:00,65595.0,65641.0,65055.0,65135.0,48.29019231 +2024-03-26 12:00:00,65135.0,65529.0,64526.0,64791.0,100.09148472 +2024-03-26 14:00:00,64808.0,65065.0,63801.0,64842.0,224.33282187 +2024-03-26 16:00:00,64843.0,65061.0,64078.0,64608.0,105.81259296 +2024-03-26 18:00:00,64634.0,64967.0,64060.0,64070.0,92.69596643 +2024-03-26 20:00:00,64092.0,64766.0,64009.0,64600.0,46.64702979 +2024-03-26 22:00:00,64601.0,64879.0,64281.0,64590.0,26.45388865 +2024-03-27 00:00:00,64580.0,65253.0,64452.0,64936.0,21.16854669 +2024-03-27 02:00:00,64926.0,65215.0,64795.0,64985.0,12.95831456 +2024-03-27 04:00:00,64998.0,65100.0,64660.0,65065.0,26.39883986 +2024-03-27 06:00:00,65048.0,65158.0,64279.0,64352.0,58.41417708 +2024-03-27 08:00:00,64360.0,64726.0,64046.0,64702.0,65.89307653 +2024-03-27 10:00:00,64690.0,64934.0,64566.0,64881.0,39.18907496 +2024-03-27 12:00:00,64884.0,66298.0,64351.0,64607.0,249.66363036 +2024-03-27 14:00:00,64602.0,64896.0,63362.0,63638.0,277.02801635 +2024-03-27 16:00:00,63636.0,64207.0,63232.0,63513.0,92.21636969 +2024-03-27 18:00:00,63488.0,63722.0,63215.0,63411.0,62.02452912 +2024-03-27 20:00:00,63401.0,63976.0,63390.0,63709.0,49.82976449 +2024-03-27 22:00:00,63721.0,64383.0,63690.0,64244.0,28.03476069 +2024-03-28 00:00:00,64215.0,64700.0,64056.0,64172.0,14.16857828 +2024-03-28 02:00:00,64175.0,64298.0,63681.0,64025.0,11.41283819 +2024-03-28 04:00:00,64025.0,64607.0,64024.0,64418.0,14.01962496 +2024-03-28 06:00:00,64422.0,65218.0,64353.0,65192.0,74.05919498 +2024-03-28 08:00:00,65201.0,65760.0,65155.0,65446.0,86.57541373 +2024-03-28 10:00:00,65454.0,65700.0,65157.0,65458.0,80.07455299 +2024-03-28 12:00:00,65494.0,65937.0,65100.0,65526.0,86.03553426 +2024-03-28 14:00:00,65502.0,66209.0,65346.0,65967.0,173.57434483 +2024-03-28 16:00:00,65969.0,66024.0,65219.0,65549.0,79.99017256 +2024-03-28 18:00:00,65552.0,65744.0,65232.0,65631.0,50.1485383 +2024-03-28 20:00:00,65613.0,65805.0,65443.0,65601.0,57.14866993 +2024-03-28 22:00:00,65589.0,65838.0,65397.0,65568.0,28.97116803 +2024-03-29 00:00:00,65569.0,65748.0,65421.0,65661.0,11.70382416 +2024-03-29 02:00:00,65651.0,65689.0,65222.0,65359.0,7.00744374 +2024-03-29 04:00:00,65362.0,65443.0,65125.0,65125.0,17.97155206 +2024-03-29 06:00:00,65125.0,65425.0,64730.0,64795.0,77.50366759 +2024-03-29 08:00:00,64792.0,65075.0,64573.0,64714.0,58.07584788 +2024-03-29 10:00:00,64702.0,65220.0,64521.0,65080.0,64.87182875 +2024-03-29 12:00:00,65104.0,65449.0,64804.0,65231.0,40.39544977 +2024-03-29 14:00:00,65240.0,65315.0,64000.0,64135.0,94.16230205 +2024-03-29 16:00:00,64150.0,64543.0,64084.0,64403.0,70.95697867 +2024-03-29 18:00:00,64403.0,64627.0,64322.0,64626.0,25.8608354 +2024-03-29 20:00:00,64622.0,64689.0,64250.0,64371.0,28.06883568 +2024-03-29 22:00:00,64368.0,64818.0,64368.0,64766.0,17.52245907 +2024-03-30 00:00:00,64777.0,65024.0,64658.0,64856.0,17.67632755 +2024-03-30 02:00:00,64851.0,64897.0,64645.0,64672.0,4.36230668 +2024-03-30 04:00:00,64670.0,65148.0,64654.0,64851.0,11.5198425 +2024-03-30 06:00:00,64859.0,64956.0,64702.0,64702.0,29.90509741 +2024-03-30 08:00:00,64700.0,65031.0,64681.0,64904.0,32.32170491 +2024-03-30 10:00:00,64904.0,65059.0,64846.0,65054.0,25.93132294 +2024-03-30 12:00:00,65054.0,65132.0,64963.0,65039.0,33.73953326 +2024-03-30 14:00:00,65046.0,65062.0,64840.0,64900.0,18.87740114 +2024-03-30 16:00:00,64895.0,65157.0,64809.0,64941.0,24.31645541 +2024-03-30 18:00:00,64933.0,64936.0,64619.0,64822.0,20.21761911 +2024-03-30 20:00:00,64817.0,64854.0,64611.0,64703.0,19.3244166 +2024-03-30 22:00:00,64700.0,64794.0,64534.0,64599.0,20.06522694 +2024-03-31 00:00:00,64579.0,65025.0,64557.0,64994.0,9.21627377 +2024-03-31 02:00:00,64979.0,65060.0,64720.0,64850.0,5.12331386 +2024-03-31 04:00:00,64860.0,65342.0,64821.0,65239.0,12.22190612 +2024-03-31 06:00:00,65250.0,65279.0,65078.0,65183.0,24.19187905 +2024-03-31 08:00:00,65183.0,65333.0,65031.0,65109.0,27.47857841 +2024-03-31 10:00:00,65109.0,65462.0,65064.0,65250.0,41.4022112 +2024-03-31 12:00:00,65256.0,65609.0,65255.0,65472.0,70.01251872 +2024-03-31 14:00:00,65471.0,65552.0,65200.0,65286.0,28.95203274 +2024-03-31 16:00:00,65280.0,65550.0,65223.0,65392.0,20.68347755 +2024-03-31 18:00:00,65392.0,66018.0,65318.0,65821.0,98.48611679 +2024-03-31 20:00:00,65873.0,65914.0,65472.0,65672.0,33.60242038 +2024-03-31 22:00:00,65680.0,66145.0,65648.0,66064.0,39.07366257 +2024-04-01 00:00:00,66057.0,66057.0,65649.0,65677.0,16.27721108 +2024-04-01 02:00:00,65659.0,65743.0,65379.0,65447.0,11.26643977 +2024-04-01 04:00:00,65418.0,65503.0,64060.0,64271.0,73.83102784 +2024-04-01 06:00:00,64249.0,64860.0,64000.0,64636.0,132.78600883 +2024-04-01 08:00:00,64636.0,64642.0,64195.0,64428.0,66.41956997 +2024-04-01 10:00:00,64426.0,64797.0,64336.0,64471.0,30.17812938 +2024-04-01 12:00:00,64462.0,65067.0,64426.0,64912.0,38.54450462 +2024-04-01 14:00:00,64917.0,65068.0,63521.0,63630.0,160.30940089 +2024-04-01 16:00:00,63630.0,64085.0,63478.0,64042.0,139.68883334 +2024-04-01 18:00:00,64047.0,65080.0,63775.0,64951.0,107.82711172 +2024-04-01 20:00:00,64943.0,65154.0,64623.0,64847.0,46.98024583 +2024-04-01 22:00:00,64848.0,65119.0,64848.0,64924.0,11.64167074 +2024-04-02 00:00:00,64939.0,64955.0,64395.0,64708.0,15.06759581 +2024-04-02 02:00:00,64696.0,64707.0,61866.0,62304.0,189.27308747 +2024-04-02 04:00:00,62292.0,62757.0,61697.0,62431.0,135.52162941 +2024-04-02 06:00:00,62431.0,63327.0,61963.0,61976.0,156.58965949 +2024-04-02 08:00:00,61976.0,62268.0,61261.0,61582.0,182.29312744 +2024-04-02 10:00:00,61579.0,61768.0,60558.0,61048.0,199.57066159 +2024-04-02 12:00:00,61043.0,61304.0,60019.0,60618.0,191.96289106 +2024-04-02 14:00:00,60626.0,61608.0,60175.0,60371.0,242.692786 +2024-04-02 16:00:00,60367.0,61178.0,60070.0,61066.0,103.79768245 +2024-04-02 18:00:00,61051.0,61663.0,60814.0,61441.0,129.48840159 +2024-04-02 20:00:00,61436.0,61572.0,60675.0,61105.0,92.94049613 +2024-04-02 22:00:00,61113.0,61330.0,60831.0,60890.0,27.19539784 +2024-04-03 00:00:00,60903.0,61314.0,60041.0,61216.0,63.64076697 +2024-04-03 02:00:00,61244.0,61619.0,61095.0,61574.0,21.29505775 +2024-04-03 04:00:00,61585.0,61802.0,61328.0,61476.0,57.95544739 +2024-04-03 06:00:00,61476.0,62000.0,61448.0,61597.0,70.43689522 +2024-04-03 08:00:00,61605.0,62000.0,61445.0,61878.0,69.01131024 +2024-04-03 10:00:00,61877.0,61910.0,60934.0,61395.0,96.65549912 +2024-04-03 12:00:00,61381.0,61525.0,60925.0,61090.0,63.32205257 +2024-04-03 14:00:00,61089.0,61985.0,60783.0,60889.0,110.95302805 +2024-04-03 16:00:00,60889.0,61544.0,60853.0,60988.0,55.58093129 +2024-04-03 18:00:00,60971.0,61130.0,60512.0,60811.0,65.6439955 +2024-04-03 20:00:00,60813.0,60938.0,60507.0,60929.0,67.58105684 +2024-04-03 22:00:00,60928.0,61243.0,60843.0,60945.0,42.13145323 +2024-04-04 00:00:00,60923.0,61284.0,60802.0,61079.0,9.98372594 +2024-04-04 02:00:00,61093.0,61093.0,60500.0,60588.0,17.01452796 +2024-04-04 04:00:00,60587.0,60661.0,60081.0,60567.0,62.87822744 +2024-04-04 06:00:00,60567.0,61132.0,60514.0,60913.0,59.62160119 +2024-04-04 08:00:00,60918.0,61231.0,60863.0,61070.0,38.96492591 +2024-04-04 10:00:00,61079.0,61250.0,60920.0,61176.0,39.00763516 +2024-04-04 12:00:00,61173.0,62153.0,61152.0,61940.0,145.63955639 +2024-04-04 14:00:00,61945.0,62577.0,61776.0,62335.0,109.36045107 +2024-04-04 16:00:00,62353.0,63548.0,62218.0,63508.0,126.04837888 +2024-04-04 18:00:00,63497.0,64000.0,63099.0,63279.0,166.50230216 +2024-04-04 20:00:00,63300.0,63378.0,62184.0,62611.0,149.92399975 +2024-04-04 22:00:00,62636.0,63323.0,62446.0,63295.0,34.73430268 +2024-04-05 00:00:00,63298.0,63463.0,62703.0,63036.0,23.00651729 +2024-04-05 02:00:00,63034.0,63034.0,62383.0,62777.0,33.42286868 +2024-04-05 04:00:00,62770.0,62912.0,61401.0,61870.0,94.99607375 +2024-04-05 06:00:00,61871.0,62161.0,61710.0,61797.0,71.44994154 +2024-04-05 08:00:00,61802.0,62491.0,61291.0,61686.0,99.42688365 +2024-04-05 10:00:00,61673.0,62082.0,61315.0,61389.0,59.22093386 +2024-04-05 12:00:00,61400.0,62643.0,61071.0,62568.0,173.86212266 +2024-04-05 14:00:00,62551.0,63442.0,62373.0,63027.0,98.91334378 +2024-04-05 16:00:00,62983.0,63144.0,62207.0,62276.0,62.27413025 +2024-04-05 18:00:00,62301.0,62871.0,62160.0,62267.0,51.5894465 +2024-04-05 20:00:00,62271.0,62663.0,62209.0,62343.0,39.17754835 +2024-04-05 22:00:00,62348.0,62769.0,62348.0,62635.0,16.68001191 +2024-04-06 00:00:00,62638.0,62861.0,62478.0,62522.0,12.09400641 +2024-04-06 02:00:00,62539.0,62677.0,62295.0,62605.0,20.11220435 +2024-04-06 04:00:00,62607.0,63019.0,62458.0,62856.0,28.32008026 +2024-04-06 06:00:00,62846.0,63008.0,62709.0,62844.0,24.58998842 +2024-04-06 08:00:00,62842.0,62952.0,62641.0,62680.0,32.20966231 +2024-04-06 10:00:00,62674.0,62769.0,62507.0,62555.0,20.54488868 +2024-04-06 12:00:00,62556.0,62684.0,62441.0,62584.0,26.952361 +2024-04-06 14:00:00,62583.0,63111.0,62571.0,62942.0,43.68488553 +2024-04-06 16:00:00,62936.0,63276.0,62785.0,63112.0,35.20125321 +2024-04-06 18:00:00,63118.0,63243.0,63002.0,63077.0,25.10151311 +2024-04-06 20:00:00,63087.0,63252.0,63007.0,63126.0,25.23956725 +2024-04-06 22:00:00,63116.0,64326.0,63105.0,63590.0,87.09411061 +2024-04-07 00:00:00,63599.0,64290.0,63554.0,64205.0,20.88269627 +2024-04-07 02:00:00,64199.0,64402.0,63907.0,64053.0,28.59821683 +2024-04-07 04:00:00,64064.0,64145.0,63744.0,64053.0,33.05357799 +2024-04-07 06:00:00,64064.0,64176.0,63817.0,64062.0,46.6378499 +2024-04-07 08:00:00,64057.0,64500.0,63952.0,64020.0,66.47621356 +2024-04-07 10:00:00,64021.0,64203.0,63931.0,64088.0,29.62334495 +2024-04-07 12:00:00,64085.0,64213.0,63933.0,64023.0,28.54744235 +2024-04-07 14:00:00,64034.0,64480.0,63895.0,64170.0,48.01978435 +2024-04-07 16:00:00,64195.0,64845.0,64110.0,64355.0,106.60301815 +2024-04-07 18:00:00,64359.0,64385.0,63502.0,63680.0,91.13593145 +2024-04-07 20:00:00,63664.0,64017.0,63605.0,63660.0,31.70507749 +2024-04-07 22:00:00,63697.0,64125.0,63558.0,64033.0,20.58546963 +2024-04-08 00:00:00,64024.0,64468.0,63790.0,64083.0,11.29538119 +2024-04-08 02:00:00,64073.0,64132.0,63765.0,64122.0,21.81619633 +2024-04-08 04:00:00,64125.0,64449.0,63965.0,64347.0,28.92538593 +2024-04-08 06:00:00,64351.0,65376.0,64311.0,65240.0,130.21522721 +2024-04-08 08:00:00,65251.0,66984.0,65197.0,66589.0,438.7090283 +2024-04-08 10:00:00,66589.0,67000.0,66200.0,66796.0,234.44430505 +2024-04-08 12:00:00,66799.0,67150.0,65919.0,66225.0,240.71362561 +2024-04-08 14:00:00,66219.0,66297.0,65385.0,66079.0,218.70987746 +2024-04-08 16:00:00,66056.0,66600.0,65623.0,66007.0,147.97137215 +2024-04-08 18:00:00,66003.0,66383.0,65738.0,66027.0,81.85499342 +2024-04-08 20:00:00,66079.0,66318.0,65774.0,65969.0,84.65592346 +2024-04-08 22:00:00,65969.0,66264.0,65882.0,65910.0,29.44262204 +2024-04-09 00:00:00,65898.0,66040.0,65215.0,65592.0,43.38018445 +2024-04-09 02:00:00,65599.0,65956.0,65496.0,65640.0,20.09738576 +2024-04-09 04:00:00,65638.0,65704.0,65315.0,65446.0,45.46247989 +2024-04-09 06:00:00,65448.0,65673.0,64647.0,64880.0,97.6566068 +2024-04-09 08:00:00,64886.0,65280.0,64148.0,64823.0,180.86462817 +2024-04-09 10:00:00,64823.0,65293.0,64664.0,65221.0,66.1962712 +2024-04-09 12:00:00,65221.0,65328.0,64301.0,64308.0,93.46143055 +2024-04-09 14:00:00,64308.0,64793.0,63163.0,63830.0,290.62367865 +2024-04-09 16:00:00,63841.0,63896.0,62871.0,63447.0,164.15995996 +2024-04-09 18:00:00,63418.0,63744.0,63300.0,63617.0,69.83899494 +2024-04-09 20:00:00,63580.0,63816.0,63523.0,63769.0,63.31279114 +2024-04-09 22:00:00,63767.0,63979.0,63450.0,63706.0,41.20699443 +2024-04-10 00:00:00,63665.0,63843.0,63217.0,63753.0,15.45790948 +2024-04-10 02:00:00,63840.0,64110.0,63132.0,63753.0,20.75876471 +2024-04-10 04:00:00,63736.0,63999.0,63626.0,63841.0,40.70690228 +2024-04-10 06:00:00,63862.0,64093.0,63835.0,63921.0,46.046865 +2024-04-10 08:00:00,63913.0,63931.0,63419.0,63692.0,46.3349593 +2024-04-10 10:00:00,63693.0,63725.0,63223.0,63607.0,63.25970513 +2024-04-10 12:00:00,63603.0,63754.0,62610.0,63438.0,216.62591822 +2024-04-10 14:00:00,63457.0,64189.0,63242.0,63991.0,131.85889186 +2024-04-10 16:00:00,63981.0,65096.0,63916.0,64534.0,120.88145995 +2024-04-10 18:00:00,64554.0,65228.0,64315.0,65228.0,82.8192382 +2024-04-10 20:00:00,65231.0,65268.0,64740.0,65147.0,85.51360965 +2024-04-10 22:00:00,65145.0,66176.0,65135.0,65720.0,122.41315243 +2024-04-11 00:00:00,65725.0,65825.0,65386.0,65628.0,23.36432487 +2024-04-11 02:00:00,65633.0,66100.0,65591.0,65916.0,31.14967553 +2024-04-11 04:00:00,65923.0,65932.0,65471.0,65669.0,42.47310589 +2024-04-11 06:00:00,65675.0,66358.0,65663.0,65820.0,106.50208401 +2024-04-11 08:00:00,65820.0,66308.0,65700.0,65743.0,98.42417283 +2024-04-11 10:00:00,65745.0,65939.0,65053.0,65161.0,100.49214939 +2024-04-11 12:00:00,65159.0,66174.0,64875.0,65444.0,155.60032481 +2024-04-11 14:00:00,65446.0,65523.0,64880.0,65260.0,86.52210814 +2024-04-11 16:00:00,65268.0,65672.0,64880.0,65414.0,81.26408816 +2024-04-11 18:00:00,65412.0,65714.0,65159.0,65650.0,36.47412014 +2024-04-11 20:00:00,65658.0,65937.0,65288.0,65358.0,56.20196101 +2024-04-11 22:00:00,65374.0,65496.0,65087.0,65264.0,14.55398577 +2024-04-12 00:00:00,65258.0,65586.0,65258.0,65529.0,16.43490581 +2024-04-12 02:00:00,65515.0,66223.0,65474.0,66218.0,37.04471645 +2024-04-12 04:00:00,66197.0,66500.0,66053.0,66200.0,114.78966482 +2024-04-12 06:00:00,66198.0,66374.0,65500.0,66195.0,102.35875143 +2024-04-12 08:00:00,66183.0,66380.0,66082.0,66222.0,57.07560586 +2024-04-12 10:00:00,66222.0,66548.0,66169.0,66489.0,57.72168196 +2024-04-12 12:00:00,66489.0,66569.0,65400.0,65626.0,140.62416317 +2024-04-12 14:00:00,65613.0,65835.0,65087.0,65146.0,142.43516173 +2024-04-12 16:00:00,65128.0,65358.0,63375.0,64052.0,303.23800334 +2024-04-12 18:00:00,64029.0,65139.0,61598.0,63652.0,488.96297133 +2024-04-12 20:00:00,63708.0,64241.0,62891.0,63368.0,213.04011076 +2024-04-12 22:00:00,63367.0,63989.0,63137.0,63789.0,36.8744358 +2024-04-13 00:00:00,63756.0,63761.0,62500.0,62661.0,35.93506332 +2024-04-13 02:00:00,62657.0,63882.0,62642.0,63662.0,36.81677937 +2024-04-13 04:00:00,63637.0,64815.0,63499.0,63881.0,48.38547783 +2024-04-13 06:00:00,63900.0,64464.0,63782.0,64245.0,40.421225 +2024-04-13 08:00:00,64244.0,64245.0,63437.0,63701.0,57.34814526 +2024-04-13 10:00:00,63713.0,64041.0,63510.0,63627.0,43.95853743 +2024-04-13 12:00:00,63613.0,63996.0,63395.0,63789.0,38.84847664 +2024-04-13 14:00:00,63781.0,64150.0,63592.0,63944.0,32.48030288 +2024-04-13 16:00:00,63943.0,64007.0,62700.0,62864.0,131.37925602 +2024-04-13 18:00:00,62878.0,63445.0,60500.0,61230.0,223.51109601 +2024-04-13 20:00:00,61230.0,61515.0,57500.0,59945.0,768.65224608 +2024-04-13 22:00:00,59951.0,63045.0,59266.0,61192.0,298.88733396 +2024-04-14 00:00:00,61163.0,61546.0,60113.0,61006.0,63.40169535 +2024-04-14 02:00:00,60975.0,61144.0,59024.0,60399.0,70.84690284 +2024-04-14 04:00:00,60367.0,62750.0,60322.0,62202.0,85.89199643 +2024-04-14 06:00:00,62201.0,63390.0,61750.0,61881.0,146.91225519 +2024-04-14 08:00:00,61877.0,62185.0,60863.0,61098.0,201.30630138 +2024-04-14 10:00:00,61098.0,61783.0,61077.0,61309.0,111.84354424 +2024-04-14 12:00:00,61298.0,61998.0,61200.0,61549.0,59.29091346 +2024-04-14 14:00:00,61541.0,61585.0,60640.0,61304.0,85.83752909 +2024-04-14 16:00:00,61331.0,61875.0,59701.0,61027.0,135.61977499 +2024-04-14 18:00:00,61005.0,61766.0,60955.0,61144.0,65.30339136 +2024-04-14 20:00:00,61144.0,61152.0,59950.0,60307.0,117.09032378 +2024-04-14 22:00:00,60300.0,62119.0,60239.0,61926.0,79.43076406 +2024-04-15 00:00:00,61884.0,62080.0,61336.0,61519.0,27.16799282 +2024-04-15 02:00:00,61508.0,61595.0,61200.0,61412.0,9.89914118 +2024-04-15 04:00:00,61429.0,61750.0,61023.0,61713.0,35.60183832 +2024-04-15 06:00:00,61713.0,62729.0,61537.0,62313.0,152.74854082 +2024-04-15 08:00:00,62310.0,62878.0,62140.0,62676.0,104.23353901 +2024-04-15 10:00:00,62691.0,62800.0,61861.0,61916.0,77.43504706 +2024-04-15 12:00:00,61921.0,62557.0,61861.0,62104.0,89.11488646 +2024-04-15 14:00:00,62115.0,62234.0,60137.0,60819.0,164.42398954 +2024-04-15 16:00:00,60827.0,61084.0,59678.0,60199.0,167.32217213 +2024-04-15 18:00:00,60184.0,60319.0,58625.0,59720.0,297.51175802 +2024-04-15 20:00:00,59780.0,60076.0,59121.0,59659.0,109.56657885 +2024-04-15 22:00:00,59699.0,59904.0,59167.0,59799.0,35.984474 +2024-04-16 00:00:00,59814.0,60297.0,59358.0,59584.0,42.11696799 +2024-04-16 02:00:00,59571.0,60055.0,59242.0,59417.0,23.34768962 +2024-04-16 04:00:00,59432.0,59505.0,58264.0,59196.0,115.21273407 +2024-04-16 06:00:00,59207.0,60251.0,59151.0,59928.0,112.36037655 +2024-04-16 08:00:00,59929.0,60048.0,59450.0,59540.0,105.93064145 +2024-04-16 10:00:00,59542.0,59616.0,58001.0,59303.0,187.46711928 +2024-04-16 12:00:00,59314.0,59615.0,58460.0,58993.0,111.20814397 +2024-04-16 14:00:00,59045.0,59343.0,58046.0,58127.0,150.45335238 +2024-04-16 16:00:00,58125.0,59647.0,58019.0,58867.0,163.54819195 +2024-04-16 18:00:00,58868.0,59426.0,58845.0,59141.0,91.47895861 +2024-04-16 20:00:00,59091.0,60681.0,58954.0,60368.0,119.46893503 +2024-04-16 22:00:00,60355.0,60402.0,59976.0,60118.0,45.60126801 +2024-04-17 00:00:00,60107.0,60553.0,59921.0,60287.0,25.90154189 +2024-04-17 02:00:00,60259.0,60536.0,59964.0,60138.0,31.32490536 +2024-04-17 04:00:00,60127.0,60836.0,59955.0,60344.0,99.00134301 +2024-04-17 06:00:00,60343.0,60383.0,59604.0,59604.0,64.86814828 +2024-04-17 08:00:00,59600.0,59904.0,59405.0,59566.0,66.50612755 +2024-04-17 10:00:00,59573.0,59584.0,58910.0,58941.0,87.39105429 +2024-04-17 12:00:00,58947.0,59261.0,58439.0,58941.0,140.45692766 +2024-04-17 14:00:00,58961.0,58961.0,56229.0,56680.0,440.0944197 +2024-04-17 16:00:00,56720.0,57617.0,56083.0,57495.0,297.03105654 +2024-04-17 18:00:00,57524.0,58147.0,56961.0,57211.0,191.46965204 +2024-04-17 20:00:00,57236.0,57829.0,56996.0,57477.0,94.31339498 +2024-04-17 22:00:00,57507.0,57908.0,57345.0,57475.0,25.31885564 +2024-04-18 00:00:00,57466.0,57804.0,57171.0,57804.0,19.96903245 +2024-04-18 02:00:00,57779.0,58305.0,57610.0,58058.0,29.9409851 +2024-04-18 04:00:00,58063.0,58158.0,57131.0,57207.0,62.83109845 +2024-04-18 06:00:00,57199.0,57434.0,56854.0,57291.0,96.03866357 +2024-04-18 08:00:00,57294.0,57817.0,57003.0,57811.0,63.12340456 +2024-04-18 10:00:00,57805.0,59169.0,57671.0,58666.0,145.95535626 +2024-04-18 12:00:00,58665.0,59036.0,57748.0,59016.0,124.58040827 +2024-04-18 14:00:00,59013.0,60242.0,58827.0,59634.0,279.77573456 +2024-04-18 16:00:00,59661.0,60034.0,58887.0,59014.0,141.56383202 +2024-04-18 18:00:00,59029.0,59851.0,58561.0,59851.0,123.44439475 +2024-04-18 20:00:00,59732.0,60094.0,59508.0,59761.0,101.72099798 +2024-04-18 22:00:00,59718.0,59908.0,59408.0,59712.0,32.38926641 +2024-04-19 00:00:00,59731.0,59731.0,57192.0,57550.0,104.2575243 +2024-04-19 02:00:00,57571.0,58495.0,56226.0,58154.0,163.78958059 +2024-04-19 04:00:00,58154.0,59099.0,58118.0,58420.0,126.50653722 +2024-04-19 06:00:00,58423.0,61225.0,58178.0,60608.0,278.32297624 +2024-04-19 08:00:00,60592.0,61138.0,60271.0,60847.0,161.73953878 +2024-04-19 10:00:00,60845.0,61494.0,60542.0,61015.0,146.10034662 +2024-04-19 12:00:00,61007.0,61500.0,60433.0,60916.0,142.96347658 +2024-04-19 14:00:00,60937.0,60984.0,59840.0,60543.0,129.07421992 +2024-04-19 16:00:00,60550.0,60915.0,59734.0,60758.0,106.44958514 +2024-04-19 18:00:00,60752.0,60791.0,60235.0,60435.0,60.48596558 +2024-04-19 20:00:00,60443.0,60583.0,59825.0,60522.0,69.17437522 +2024-04-19 22:00:00,60521.0,60636.0,59160.0,59993.0,101.95209275 +2024-04-20 00:00:00,60025.0,60433.0,59308.0,59877.0,51.470905 +2024-04-20 02:00:00,59856.0,60265.0,59760.0,60176.0,20.91592317 +2024-04-20 04:00:00,60159.0,60480.0,60039.0,60411.0,38.96469236 +2024-04-20 06:00:00,60414.0,60508.0,60197.0,60235.0,40.2938157 +2024-04-20 08:00:00,60223.0,60262.0,59500.0,59825.0,101.49891319 +2024-04-20 10:00:00,59818.0,60089.0,59598.0,59906.0,42.36127378 +2024-04-20 12:00:00,59916.0,60203.0,59762.0,60066.0,43.53329047 +2024-04-20 14:00:00,60070.0,61070.0,59950.0,60938.0,65.29148983 +2024-04-20 16:00:00,60934.0,61578.0,60587.0,61378.0,145.12353494 +2024-04-20 18:00:00,61370.0,61532.0,60957.0,61036.0,68.43631483 +2024-04-20 20:00:00,61035.0,61175.0,60802.0,60894.0,29.27382467 +2024-04-20 22:00:00,60923.0,61115.0,60727.0,61074.0,23.50380607 +2024-04-21 00:00:00,61068.0,61200.0,60772.0,61070.0,10.47856413 +2024-04-21 02:00:00,61060.0,61714.0,61058.0,61241.0,31.24671083 +2024-04-21 04:00:00,61225.0,61322.0,60944.0,61131.0,38.6935894 +2024-04-21 06:00:00,61138.0,61311.0,61046.0,61282.0,37.04440589 +2024-04-21 08:00:00,61290.0,61360.0,60977.0,61078.0,42.63963162 +2024-04-21 10:00:00,61093.0,61602.0,60977.0,61398.0,46.17736342 +2024-04-21 12:00:00,61404.0,61528.0,60980.0,61053.0,35.3636935 +2024-04-21 14:00:00,61071.0,61248.0,60950.0,61186.0,35.0558137 +2024-04-21 16:00:00,61177.0,61223.0,60392.0,60922.0,83.65546671 +2024-04-21 18:00:00,60929.0,60960.0,60646.0,60663.0,30.28547035 +2024-04-21 20:00:00,60669.0,61231.0,60502.0,60742.0,46.1227798 +2024-04-21 22:00:00,60744.0,61132.0,60638.0,60981.0,21.36800756 +2024-04-22 00:00:00,60980.0,61606.0,60640.0,60711.0,25.53296043 +2024-04-22 02:00:00,60687.0,62000.0,60524.0,61656.0,38.08005525 +2024-04-22 04:00:00,61670.0,62341.0,61477.0,62310.0,89.26216614 +2024-04-22 06:00:00,62318.0,62442.0,61981.0,61984.0,71.83737179 +2024-04-22 08:00:00,61987.0,62218.0,61846.0,61980.0,44.92884127 +2024-04-22 10:00:00,61982.0,62150.0,61840.0,62017.0,33.55239775 +2024-04-22 12:00:00,62023.0,62361.0,61787.0,62279.0,58.128269 +2024-04-22 14:00:00,62284.0,62563.0,61800.0,62065.0,88.02886753 +2024-04-22 16:00:00,62085.0,62780.0,62003.0,62507.0,77.24972905 +2024-04-22 18:00:00,62508.0,62669.0,62141.0,62575.0,48.52352331 +2024-04-22 20:00:00,62536.0,62750.0,62335.0,62518.0,36.5335766 +2024-04-22 22:00:00,62538.0,63147.0,62521.0,62779.0,56.72772689 +2024-04-23 00:00:00,62775.0,63096.0,62678.0,62772.0,31.24055737 +2024-04-23 02:00:00,62759.0,62849.0,62430.0,62459.0,15.40452152 +2024-04-23 04:00:00,62430.0,62626.0,62205.0,62531.0,29.30521252 +2024-04-23 06:00:00,62534.0,62715.0,61850.0,61934.0,91.12682537 +2024-04-23 08:00:00,61944.0,62235.0,61815.0,62059.0,46.76407436 +2024-04-23 10:00:00,62061.0,62286.0,61810.0,61942.0,45.79185522 +2024-04-23 12:00:00,61951.0,62393.0,61733.0,62199.0,71.15789904 +2024-04-23 14:00:00,62216.0,62754.0,62059.0,62132.0,95.62819499 +2024-04-23 16:00:00,62146.0,62520.0,62087.0,62392.0,37.84283382 +2024-04-23 18:00:00,62392.0,62474.0,62066.0,62142.0,40.76761899 +2024-04-23 20:00:00,62143.0,62147.0,61678.0,62006.0,56.78868703 +2024-04-23 22:00:00,62011.0,62107.0,61794.0,62065.0,21.63668354 +2024-04-24 00:00:00,62048.0,62471.0,62044.0,62331.0,20.51493314 +2024-04-24 02:00:00,62337.0,62359.0,62054.0,62207.0,15.41739522 +2024-04-24 04:00:00,62220.0,62662.0,62203.0,62364.0,38.11951369 +2024-04-24 06:00:00,62356.0,62590.0,62218.0,62347.0,55.529951 +2024-04-24 08:00:00,62337.0,62477.0,62013.0,62109.0,35.12213816 +2024-04-24 10:00:00,62115.0,62366.0,61962.0,62297.0,37.13250552 +2024-04-24 12:00:00,62293.0,62460.0,61567.0,61802.0,76.1613936 +2024-04-24 14:00:00,61801.0,61907.0,60386.0,60469.0,210.88589026 +2024-04-24 16:00:00,60463.0,60954.0,60232.0,60705.0,86.51220611 +2024-04-24 18:00:00,60719.0,60732.0,59643.0,59777.0,165.26187198 +2024-04-24 20:00:00,59775.0,60261.0,59455.0,60216.0,101.15350387 +2024-04-24 22:00:00,60201.0,60227.0,59699.0,60124.0,27.85803628 +2024-04-25 00:00:00,60102.0,60528.0,59873.0,59892.0,21.38781018 +2024-04-25 02:00:00,59861.0,60238.0,59700.0,60085.0,14.37520048 +2024-04-25 04:00:00,60081.0,60174.0,59826.0,60006.0,52.63936145 +2024-04-25 06:00:00,60006.0,60114.0,59572.0,59744.0,55.78363104 +2024-04-25 08:00:00,59737.0,59876.0,59420.0,59667.0,52.18448427 +2024-04-25 10:00:00,59671.0,59779.0,59068.0,59591.0,83.21649054 +2024-04-25 12:00:00,59592.0,59994.0,58787.0,59271.0,136.04289723 +2024-04-25 14:00:00,59294.0,59907.0,59041.0,59829.0,88.59810597 +2024-04-25 16:00:00,59839.0,60476.0,59705.0,60325.0,79.85304754 +2024-04-25 18:00:00,60329.0,60589.0,60138.0,60345.0,49.13949063 +2024-04-25 20:00:00,60354.0,60887.0,60119.0,60357.0,60.9667355 +2024-04-25 22:00:00,60345.0,60380.0,60095.0,60159.0,18.72310616 +2024-04-26 00:00:00,60179.0,60286.0,59600.0,60065.0,37.97315855 +2024-04-26 02:00:00,60069.0,60309.0,59966.0,60060.0,15.43853722 +2024-04-26 04:00:00,60063.0,60240.0,59750.0,60235.0,26.74556811 +2024-04-26 06:00:00,60238.0,60260.0,59900.0,59939.0,38.00616256 +2024-04-26 08:00:00,59941.0,60202.0,59845.0,60051.0,46.7957663 +2024-04-26 10:00:00,60083.0,60156.0,59720.0,59973.0,40.37460398 +2024-04-26 12:00:00,59961.0,60342.0,59485.0,60265.0,87.42533695 +2024-04-26 14:00:00,60276.0,60595.0,59318.0,59457.0,86.08159208 +2024-04-26 16:00:00,59453.0,59980.0,59276.0,59865.0,38.83570242 +2024-04-26 18:00:00,59877.0,59976.0,59580.0,59580.0,18.7603367 +2024-04-26 20:00:00,59600.0,59957.0,59600.0,59937.0,28.91902654 +2024-04-26 22:00:00,59932.0,59933.0,59607.0,59662.0,11.10693164 +2024-04-27 00:00:00,59663.0,59810.0,58350.0,58603.0,83.61758377 +2024-04-27 02:00:00,58615.0,59304.0,58527.0,59084.0,39.7012277 +2024-04-27 04:00:00,59050.0,59157.0,58814.0,58957.0,41.65168946 +2024-04-27 06:00:00,58956.0,59098.0,58832.0,58933.0,36.36370709 +2024-04-27 08:00:00,58938.0,59028.0,58855.0,58959.0,25.57918679 +2024-04-27 10:00:00,58962.0,58980.0,58676.0,58821.0,53.54281126 +2024-04-27 12:00:00,58825.0,59230.0,58768.0,59199.0,39.20507662 +2024-04-27 14:00:00,59195.0,59359.0,58844.0,58934.0,28.66094539 +2024-04-27 16:00:00,58936.0,59558.0,58736.0,59348.0,71.31776923 +2024-04-27 18:00:00,59333.0,59521.0,58795.0,59267.0,48.6117205 +2024-04-27 20:00:00,59277.0,59383.0,59078.0,59220.0,18.57836591 +2024-04-27 22:00:00,59221.0,59461.0,59179.0,59385.0,20.37052819 +2024-04-28 00:00:00,59387.0,59663.0,59387.0,59523.0,12.51791395 +2024-04-28 02:00:00,59522.0,60158.0,59450.0,59857.0,26.23607537 +2024-04-28 04:00:00,59863.0,59887.0,59647.0,59805.0,19.6996127 +2024-04-28 06:00:00,59797.0,59920.0,59650.0,59778.0,20.24455691 +2024-04-28 08:00:00,59778.0,59842.0,59526.0,59599.0,33.89912576 +2024-04-28 10:00:00,59597.0,59633.0,59208.0,59341.0,27.27559109 +2024-04-28 12:00:00,59341.0,59694.0,59296.0,59611.0,26.19031027 +2024-04-28 14:00:00,59611.0,59623.0,59317.0,59405.0,22.69146381 +2024-04-28 16:00:00,59404.0,59675.0,59353.0,59632.0,18.67240912 +2024-04-28 18:00:00,59632.0,59830.0,59568.0,59598.0,23.2495209 +2024-04-28 20:00:00,59589.0,59616.0,59443.0,59529.0,22.44957333 +2024-04-28 22:00:00,59525.0,59563.0,58671.0,58970.0,46.54285212 +2024-04-29 00:00:00,58957.0,59152.0,58855.0,59023.0,11.4484548 +2024-04-29 02:00:00,59054.0,59066.0,58096.0,58146.0,40.65717668 +2024-04-29 04:00:00,58146.0,58407.0,57870.0,58250.0,81.46491442 +2024-04-29 06:00:00,58252.0,58276.0,57806.0,58240.0,98.3479659 +2024-04-29 08:00:00,58236.0,58494.0,58051.0,58380.0,73.36797731 +2024-04-29 10:00:00,58394.0,58524.0,58030.0,58097.0,70.37401728 +2024-04-29 12:00:00,58094.0,58563.0,57769.0,57952.0,84.26147592 +2024-04-29 14:00:00,57957.0,58869.0,57809.0,58831.0,70.4549388 +2024-04-29 16:00:00,58825.0,58930.0,58499.0,58791.0,41.84733754 +2024-04-29 18:00:00,58789.0,58818.0,58330.0,58718.0,42.23039866 +2024-04-29 20:00:00,58722.0,58891.0,58567.0,58820.0,30.67851674 +2024-04-29 22:00:00,58810.0,59889.0,58777.0,59560.0,57.8643063 +2024-04-30 00:00:00,59560.0,60351.0,59341.0,59343.0,53.23875838 +2024-04-30 02:00:00,59354.0,59613.0,58833.0,59421.0,40.36054027 +2024-04-30 04:00:00,59449.0,59492.0,58895.0,59168.0,25.87968661 +2024-04-30 06:00:00,59168.0,59309.0,58969.0,58979.0,39.39860619 +2024-04-30 08:00:00,58980.0,59083.0,57387.0,57500.0,173.13241081 +2024-04-30 10:00:00,57490.0,57606.0,56915.0,57070.0,202.47617888 +2024-04-30 12:00:00,57068.0,57282.0,56641.0,56763.0,160.32414969 +2024-04-30 14:00:00,56727.0,57461.0,56471.0,56808.0,184.55570434 +2024-04-30 16:00:00,56806.0,56940.0,56165.0,56427.0,147.13443724 +2024-04-30 18:00:00,56420.0,56586.0,55320.0,55384.0,166.76061841 +2024-04-30 20:00:00,55389.0,56523.0,55370.0,56323.0,124.47187584 +2024-04-30 22:00:00,56317.0,57182.0,56298.0,56858.0,63.47327816 +2024-05-01 00:00:00,56845.0,56983.0,56069.0,56360.0,44.52953441 +2024-05-01 02:00:00,56363.0,56539.0,55845.0,56464.0,28.60394442 +2024-05-01 04:00:00,56469.0,56575.0,56157.0,56265.0,42.95102457 +2024-05-01 06:00:00,56280.0,56323.0,53425.0,53799.0,457.16764805 +2024-05-01 08:00:00,53797.0,53946.0,52850.0,53434.0,366.34747419 +2024-05-01 10:00:00,53459.0,54208.0,53214.0,54198.0,203.43853565 +2024-05-01 12:00:00,54191.0,54528.0,53545.0,53571.0,140.96083982 +2024-05-01 14:00:00,53597.0,53853.0,53013.0,53175.0,169.54315608 +2024-05-01 16:00:00,53183.0,53945.0,52974.0,53785.0,122.40959255 +2024-05-01 18:00:00,53754.0,55532.0,53159.0,53260.0,466.2620042 +2024-05-01 20:00:00,53254.0,54255.0,53000.0,54008.0,156.76391074 +2024-05-01 22:00:00,54012.0,54591.0,53908.0,54414.0,54.56836389 +2024-05-02 00:00:00,54383.0,54624.0,53150.0,53248.0,63.46095998 +2024-05-02 02:00:00,53269.0,53794.0,53269.0,53554.0,22.56732941 +2024-05-02 04:00:00,53561.0,53739.0,53333.0,53592.0,72.21183649 +2024-05-02 06:00:00,53594.0,54045.0,53530.0,53804.0,73.58915864 +2024-05-02 08:00:00,53804.0,54209.0,53730.0,54017.0,84.33807965 +2024-05-02 10:00:00,54007.0,54858.0,53814.0,54749.0,133.92017646 +2024-05-02 12:00:00,54739.0,55278.0,54518.0,54705.0,163.03880767 +2024-05-02 14:00:00,54721.0,55587.0,54614.0,55415.0,135.3150744 +2024-05-02 16:00:00,55416.0,55475.0,55030.0,55280.0,72.05759374 +2024-05-02 18:00:00,55281.0,55603.0,55079.0,55384.0,62.81690721 +2024-05-02 20:00:00,55361.0,55610.0,54721.0,55154.0,71.24740614 +2024-05-02 22:00:00,55136.0,55423.0,55066.0,55066.0,30.17553382 +2024-05-03 00:00:00,55062.0,55459.0,54857.0,55272.0,27.65142495 +2024-05-03 02:00:00,55300.0,55944.0,55234.0,55671.0,39.67159814 +2024-05-03 04:00:00,55682.0,55777.0,55431.0,55490.0,43.05776095 +2024-05-03 06:00:00,55502.0,55546.0,55057.0,55144.0,91.85524748 +2024-05-03 08:00:00,55158.0,55502.0,55077.0,55412.0,48.66261378 +2024-05-03 10:00:00,55421.0,55430.0,54826.0,55218.0,65.88799555 +2024-05-03 12:00:00,55234.0,57412.0,54929.0,57311.0,282.93664594 +2024-05-03 14:00:00,57314.0,57730.0,56965.0,57329.0,203.47176126 +2024-05-03 16:00:00,57357.0,57790.0,57218.0,57476.0,88.30179777 +2024-05-03 18:00:00,57473.0,57750.0,57263.0,57721.0,44.96929695 +2024-05-03 20:00:00,57700.0,58865.0,57644.0,58392.0,182.84159387 +2024-05-03 22:00:00,58473.0,58911.0,58298.0,58503.0,64.59071824 +2024-05-04 00:00:00,58496.0,59117.0,58395.0,58447.0,37.91406331 +2024-05-04 02:00:00,58427.0,58491.0,58141.0,58319.0,21.18918455 +2024-05-04 04:00:00,58327.0,59052.0,58299.0,58967.0,43.83487843 +2024-05-04 06:00:00,58975.0,58978.0,58500.0,58579.0,47.84600247 +2024-05-04 08:00:00,58566.0,58872.0,58515.0,58761.0,41.78384982 +2024-05-04 10:00:00,58759.0,60000.0,58663.0,59410.0,134.69452838 +2024-05-04 12:00:00,59412.0,59689.0,58981.0,59248.0,72.1470118 +2024-05-04 14:00:00,59233.0,59455.0,58960.0,59110.0,47.85082925 +2024-05-04 16:00:00,59111.0,59241.0,58843.0,58975.0,59.78704217 +2024-05-04 18:00:00,58962.0,59521.0,58902.0,59415.0,44.79831019 +2024-05-04 20:00:00,59421.0,59686.0,59085.0,59408.0,35.89320373 +2024-05-04 22:00:00,59419.0,59437.0,59101.0,59386.0,18.62821807 +2024-05-05 00:00:00,59396.0,59655.0,58440.0,58874.0,32.48818639 +2024-05-05 02:00:00,58855.0,58972.0,58578.0,58770.0,11.35284707 +2024-05-05 04:00:00,58788.0,59017.0,58669.0,58758.0,18.80477988 +2024-05-05 06:00:00,58765.0,59480.0,58713.0,59269.0,26.25522937 +2024-05-05 08:00:00,59259.0,59416.0,59061.0,59190.0,27.20171026 +2024-05-05 10:00:00,59209.0,59442.0,59091.0,59356.0,25.94455257 +2024-05-05 12:00:00,59376.0,59727.0,59136.0,59578.0,49.30178209 +2024-05-05 14:00:00,59573.0,60000.0,59240.0,59834.0,57.96004235 +2024-05-05 16:00:00,59881.0,59964.0,59615.0,59672.0,45.89684221 +2024-05-05 18:00:00,59677.0,59712.0,59275.0,59331.0,51.52659356 +2024-05-05 20:00:00,59345.0,59345.0,59063.0,59340.0,32.46413522 +2024-05-05 22:00:00,59304.0,59676.0,59183.0,59502.0,20.84675393 +2024-05-06 00:00:00,59508.0,59881.0,59508.0,59567.0,15.24401505 +2024-05-06 02:00:00,59554.0,59642.0,59192.0,59342.0,16.19288537 +2024-05-06 04:00:00,59323.0,59797.0,59259.0,59653.0,21.75609881 +2024-05-06 06:00:00,59657.0,60000.0,59603.0,59977.0,62.10024818 +2024-05-06 08:00:00,59983.0,60827.0,59885.0,60507.0,119.27069699 +2024-05-06 10:00:00,60516.0,60610.0,59270.0,59601.0,109.1326779 +2024-05-06 12:00:00,59611.0,59693.0,58690.0,59229.0,148.89107365 +2024-05-06 14:00:00,59225.0,59576.0,58357.0,59039.0,115.01463245 +2024-05-06 16:00:00,59031.0,59144.0,58425.0,58628.0,80.07108677 +2024-05-06 18:00:00,58623.0,58977.0,58220.0,58698.0,88.24751997 +2024-05-06 20:00:00,58699.0,59073.0,58543.0,59014.0,46.0037223 +2024-05-06 22:00:00,58998.0,59023.0,58644.0,58662.0,27.579255 +2024-05-07 00:00:00,58665.0,59400.0,58456.0,59327.0,26.25707961 +2024-05-07 02:00:00,59344.0,59355.0,58377.0,58730.0,23.71315187 +2024-05-07 04:00:00,58731.0,59187.0,58600.0,59043.0,23.54120911 +2024-05-07 06:00:00,59083.0,59317.0,58930.0,59162.0,35.48971933 +2024-05-07 08:00:00,59161.0,59850.0,59104.0,59603.0,61.16178629 +2024-05-07 10:00:00,59595.0,59640.0,58860.0,58973.0,47.67586831 +2024-05-07 12:00:00,58961.0,59204.0,58549.0,58645.0,72.58096273 +2024-05-07 14:00:00,58655.0,59690.0,58524.0,59202.0,89.18183459 +2024-05-07 16:00:00,59212.0,59336.0,58863.0,58940.0,25.92500849 +2024-05-07 18:00:00,58930.0,58937.0,58432.0,58635.0,74.19348843 +2024-05-07 20:00:00,58634.0,58771.0,58425.0,58655.0,40.79187825 +2024-05-07 22:00:00,58632.0,58707.0,57936.0,57980.0,41.12611371 +2024-05-08 00:00:00,57959.0,58349.0,57791.0,58220.0,23.10097354 +2024-05-08 02:00:00,58225.0,58620.0,58225.0,58556.0,13.67939652 +2024-05-08 04:00:00,58548.0,58666.0,58058.0,58297.0,30.19073057 +2024-05-08 06:00:00,58298.0,58363.0,57792.0,57922.0,53.70443966 +2024-05-08 08:00:00,57918.0,58084.0,57719.0,57907.0,49.89987697 +2024-05-08 10:00:00,57900.0,58115.0,57778.0,57875.0,42.23898251 +2024-05-08 12:00:00,57890.0,58106.0,57436.0,58050.0,71.5463574 +2024-05-08 14:00:00,58055.0,58456.0,57594.0,57898.0,69.97887809 +2024-05-08 16:00:00,57879.0,58352.0,57652.0,58262.0,32.89765068 +2024-05-08 18:00:00,58269.0,58406.0,57645.0,57843.0,40.01730948 +2024-05-08 20:00:00,57847.0,57908.0,57111.0,57204.0,79.19605382 +2024-05-08 22:00:00,57199.0,57284.0,56642.0,56959.0,74.39013133 +2024-05-09 00:00:00,56942.0,57262.0,56907.0,57257.0,9.39067703 +2024-05-09 02:00:00,57253.0,57490.0,57132.0,57371.0,10.17666592 +2024-05-09 04:00:00,57388.0,57440.0,57142.0,57299.0,21.28576077 +2024-05-09 06:00:00,57301.0,57501.0,56926.0,57040.0,42.44705187 +2024-05-09 08:00:00,57033.0,57261.0,56764.0,57092.0,64.34847488 +2024-05-09 10:00:00,57086.0,57119.0,56456.0,56903.0,64.39773199 +2024-05-09 12:00:00,56912.0,57328.0,56570.0,56824.0,51.34936135 +2024-05-09 14:00:00,56834.0,57805.0,56733.0,57701.0,72.47643268 +2024-05-09 16:00:00,57707.0,58179.0,57314.0,57472.0,89.75512464 +2024-05-09 18:00:00,57470.0,58025.0,57423.0,57948.0,35.36755777 +2024-05-09 20:00:00,57925.0,58283.0,57838.0,58037.0,65.25066255 +2024-05-09 22:00:00,58024.0,58841.0,57982.0,58513.0,55.90949647 +2024-05-10 00:00:00,58515.0,58534.0,58144.0,58366.0,24.53456375 +2024-05-10 02:00:00,58344.0,58499.0,58275.0,58398.0,11.03942418 +2024-05-10 04:00:00,58392.0,58472.0,58145.0,58238.0,31.98832969 +2024-05-10 06:00:00,58239.0,58791.0,58208.0,58504.0,68.99588598 +2024-05-10 08:00:00,58504.0,58600.0,58276.0,58564.0,27.0009894 +2024-05-10 10:00:00,58561.0,58757.0,58269.0,58730.0,23.90971763 +2024-05-10 12:00:00,58735.0,58891.0,58300.0,58410.0,44.75484616 +2024-05-10 14:00:00,58410.0,58514.0,56372.0,56596.0,222.28531749 +2024-05-10 16:00:00,56582.0,56920.0,55911.0,56096.0,122.75011913 +2024-05-10 18:00:00,56091.0,56560.0,55964.0,56401.0,75.60834138 +2024-05-10 20:00:00,56409.0,56638.0,56186.0,56432.0,53.5364284 +2024-05-10 22:00:00,56441.0,56737.0,56367.0,56525.0,24.92665821 +2024-05-11 00:00:00,56564.0,56791.0,56385.0,56588.0,20.86866246 +2024-05-11 02:00:00,56583.0,56663.0,56421.0,56436.0,10.10821159 +2024-05-11 04:00:00,56436.0,56648.0,56420.0,56625.0,10.80689365 +2024-05-11 06:00:00,56625.0,56806.0,56581.0,56749.0,29.2857812 +2024-05-11 08:00:00,56760.0,56787.0,56402.0,56630.0,18.45800626 +2024-05-11 10:00:00,56617.0,56630.0,56209.0,56413.0,16.10692495 +2024-05-11 12:00:00,56412.0,56704.0,56372.0,56700.0,18.0667575 +2024-05-11 14:00:00,56700.0,57219.0,56523.0,56877.0,55.65078505 +2024-05-11 16:00:00,56916.0,57121.0,56715.0,56813.0,19.94691861 +2024-05-11 18:00:00,56831.0,57000.0,56745.0,56866.0,15.91921909 +2024-05-11 20:00:00,56857.0,56877.0,56464.0,56622.0,15.86879839 +2024-05-11 22:00:00,56617.0,56690.0,56464.0,56516.0,4.25523713 +2024-05-12 00:00:00,56513.0,56779.0,56506.0,56568.0,2.42085923 +2024-05-12 02:00:00,56563.0,56672.0,56545.0,56625.0,2.86203082 +2024-05-12 04:00:00,56617.0,56804.0,56608.0,56734.0,5.44351998 +2024-05-12 06:00:00,56721.0,56757.0,56320.0,56527.0,20.80013565 +2024-05-12 08:00:00,56508.0,56789.0,56500.0,56670.0,15.31582095 +2024-05-12 10:00:00,56670.0,57009.0,56621.0,56799.0,15.56845062 +2024-05-12 12:00:00,56794.0,56875.0,56731.0,56839.0,12.42267813 +2024-05-12 14:00:00,56850.0,57174.0,56771.0,57030.0,22.76326064 +2024-05-12 16:00:00,57037.0,57448.0,56821.0,57249.0,37.80028025 +2024-05-12 18:00:00,57235.0,57260.0,56849.0,57023.0,15.17626118 +2024-05-12 20:00:00,57025.0,57041.0,56600.0,56870.0,14.16100464 +2024-05-12 22:00:00,56865.0,57155.0,56833.0,57091.0,11.10522855 +2024-05-13 00:00:00,57105.0,57392.0,56854.0,57033.0,10.37483056 +2024-05-13 02:00:00,57014.0,57080.0,56430.0,56794.0,23.89078266 +2024-05-13 04:00:00,56796.0,56798.0,56454.0,56501.0,26.60517741 +2024-05-13 06:00:00,56490.0,57957.0,56436.0,57868.0,51.82622174 +2024-05-13 08:00:00,57861.0,58690.0,57860.0,58492.0,129.59987624 +2024-05-13 10:00:00,58517.0,58517.0,57848.0,58139.0,66.47266792 +2024-05-13 12:00:00,58144.0,58347.0,57796.0,58089.0,64.91203493 +2024-05-13 14:00:00,58100.0,58545.0,58036.0,58353.0,40.19242079 +2024-05-13 16:00:00,58361.0,58750.0,58000.0,58156.0,60.9357647 +2024-05-13 18:00:00,58154.0,58556.0,57944.0,58545.0,50.48855873 +2024-05-13 20:00:00,58529.0,58545.0,58199.0,58263.0,29.9213267 +2024-05-13 22:00:00,58255.0,58316.0,58097.0,58296.0,7.86677899 +2024-05-14 00:00:00,58291.0,58470.0,57980.0,58064.0,11.90291304 +2024-05-14 02:00:00,58041.0,58086.0,57768.0,57851.0,24.59490818 +2024-05-14 04:00:00,57836.0,58141.0,57758.0,58098.0,22.53968529 +2024-05-14 06:00:00,58099.0,58099.0,56899.0,57461.0,75.97597132 +2024-05-14 08:00:00,57472.0,57472.0,57198.0,57240.0,31.36155705 +2024-05-14 10:00:00,57237.0,57292.0,56970.0,57227.0,41.01042358 +2024-05-14 12:00:00,57219.0,57486.0,56688.0,56990.0,81.30388897 +2024-05-14 14:00:00,56996.0,57580.0,56507.0,57077.0,78.49332361 +2024-05-14 16:00:00,57089.0,57123.0,56505.0,56645.0,46.32141697 +2024-05-14 18:00:00,56644.0,56987.0,56558.0,56931.0,32.75231357 +2024-05-14 20:00:00,56930.0,57126.0,56823.0,57027.0,23.93690916 +2024-05-14 22:00:00,57024.0,57100.0,56902.0,56933.0,11.75711387 +2024-05-15 00:00:00,56919.0,57113.0,56737.0,57007.0,13.03290894 +2024-05-15 02:00:00,56999.0,57293.0,56999.0,57222.0,6.65066326 +2024-05-15 04:00:00,57219.0,57343.0,57108.0,57206.0,17.79424952 +2024-05-15 06:00:00,57227.0,57540.0,57137.0,57466.0,17.43260738 +2024-05-15 08:00:00,57475.0,58101.0,57189.0,57882.0,37.58611995 +2024-05-15 10:00:00,57882.0,58178.0,57508.0,57682.0,81.83715698 +2024-05-15 12:00:00,57680.0,59581.0,57614.0,59184.0,214.31337372 +2024-05-15 14:00:00,59213.0,59848.0,58987.0,59529.0,150.81551914 +2024-05-15 16:00:00,59594.0,59930.0,58703.0,59721.0,105.50281339 +2024-05-15 18:00:00,59701.0,60884.0,59373.0,60517.0,149.29165004 +2024-05-15 20:00:00,60510.0,60598.0,59900.0,60283.0,116.51575672 +2024-05-15 22:00:00,60298.0,60776.0,60000.0,60558.0,25.99900224 +2024-05-16 00:00:00,60573.0,60960.0,60236.0,60381.0,11.70063096 +2024-05-16 02:00:00,60380.0,60531.0,60247.0,60378.0,8.67508779 +2024-05-16 04:00:00,60389.0,60433.0,59872.0,60088.0,28.96682599 +2024-05-16 06:00:00,60108.0,60766.0,59255.0,60606.0,92.24548281 +2024-05-16 08:00:00,60586.0,60931.0,60533.0,60886.0,62.65230308 +2024-05-16 10:00:00,60915.0,61000.0,60567.0,61000.0,45.68675621 +2024-05-16 12:00:00,61000.0,61184.0,59500.0,60877.0,100.02482195 +2024-05-16 14:00:00,60877.0,60902.0,59500.0,60288.0,84.88145955 +2024-05-16 16:00:00,60288.0,60313.0,58900.0,59568.0,91.8595333 +2024-05-16 18:00:00,59510.0,60261.0,59400.0,59820.0,61.88601383 +2024-05-16 20:00:00,59864.0,60130.0,59710.0,60107.0,28.4656103 +2024-05-16 22:00:00,60106.0,60111.0,59790.0,59856.0,9.80280171 +2024-05-17 00:00:00,59873.0,60144.0,59790.0,60035.0,6.2861263 +2024-05-17 02:00:00,60049.0,60499.0,59888.0,60266.0,14.03192244 +2024-05-17 04:00:00,60267.0,60417.0,60053.0,60376.0,23.30748847 +2024-05-17 06:00:00,60385.0,61091.0,60183.0,61011.0,79.30006949 +2024-05-17 08:00:00,61011.0,61076.0,60750.0,61018.0,44.58551993 +2024-05-17 10:00:00,61027.0,61310.0,60872.0,61006.0,58.7356611 +2024-05-17 12:00:00,61004.0,61314.0,60640.0,60707.0,78.97420417 +2024-05-17 14:00:00,60711.0,62018.0,60699.0,61794.0,115.15232201 +2024-05-17 16:00:00,61795.0,61895.0,61259.0,61301.0,55.15386677 +2024-05-17 18:00:00,61301.0,61625.0,60839.0,61625.0,63.95845644 +2024-05-17 20:00:00,61606.0,61606.0,61360.0,61437.0,21.49178796 +2024-05-17 22:00:00,61426.0,61652.0,61286.0,61614.0,11.1802144 +2024-05-18 00:00:00,61618.0,61675.0,61360.0,61575.0,16.6780772 +2024-05-18 02:00:00,61550.0,61655.0,61432.0,61543.0,4.99991194 +2024-05-18 04:00:00,61534.0,61589.0,61413.0,61455.0,13.15769895 +2024-05-18 06:00:00,61463.0,61816.0,61339.0,61504.0,27.38634379 +2024-05-18 08:00:00,61494.0,61774.0,61459.0,61751.0,32.84840431 +2024-05-18 10:00:00,61719.0,61967.0,61668.0,61813.0,34.64837633 +2024-05-18 12:00:00,61818.0,61840.0,61418.0,61486.0,28.84888703 +2024-05-18 14:00:00,61470.0,61655.0,61228.0,61409.0,23.37077678 +2024-05-18 16:00:00,61445.0,61594.0,61321.0,61445.0,22.13736121 +2024-05-18 18:00:00,61431.0,61550.0,61374.0,61514.0,10.8236594 +2024-05-18 20:00:00,61510.0,61601.0,61412.0,61491.0,13.44215216 +2024-05-18 22:00:00,61491.0,61651.0,61429.0,61525.0,5.77274084 +2024-05-19 00:00:00,61537.0,61590.0,61452.0,61511.0,13.4429642 +2024-05-19 02:00:00,61539.0,61846.0,61534.0,61744.0,4.70159117 +2024-05-19 04:00:00,61737.0,61743.0,61574.0,61677.0,6.24041013 +2024-05-19 06:00:00,61678.0,61884.0,61524.0,61878.0,20.02773333 +2024-05-19 08:00:00,61873.0,61896.0,61550.0,61734.0,18.65205618 +2024-05-19 10:00:00,61739.0,62194.0,61519.0,61872.0,44.86547563 +2024-05-19 12:00:00,61870.0,61870.0,61288.0,61611.0,25.65533216 +2024-05-19 14:00:00,61608.0,61689.0,61317.0,61462.0,16.5017599 +2024-05-19 16:00:00,61462.0,61562.0,61147.0,61304.0,35.37181072 +2024-05-19 18:00:00,61297.0,61352.0,60529.0,60660.0,81.84854399 +2024-05-19 20:00:00,60633.0,60978.0,60622.0,60891.0,26.24875523 +2024-05-19 22:00:00,60870.0,61049.0,60823.0,60887.0,18.61732893 +2024-05-20 00:00:00,60882.0,61151.0,60700.0,61112.0,8.37762721 +2024-05-20 02:00:00,61090.0,61329.0,61090.0,61233.0,11.04973682 +2024-05-20 04:00:00,61200.0,61769.0,61183.0,61642.0,19.9846302 +2024-05-20 06:00:00,61655.0,61656.0,60853.0,61389.0,44.91318504 +2024-05-20 08:00:00,61389.0,61599.0,61316.0,61481.0,30.51891249 +2024-05-20 10:00:00,61479.0,61897.0,61442.0,61605.0,42.38468849 +2024-05-20 12:00:00,61607.0,61797.0,61400.0,61683.0,31.35339499 +2024-05-20 14:00:00,61705.0,62082.0,61390.0,62028.0,66.8632227 +2024-05-20 16:00:00,62023.0,63049.0,61969.0,62802.0,161.84459854 +2024-05-20 18:00:00,62825.0,64300.0,62768.0,63961.0,232.80921829 +2024-05-20 20:00:00,64038.0,64100.0,62483.0,63390.0,180.35579138 +2024-05-20 22:00:00,63451.0,64424.0,63243.0,64186.0,73.84390725 +2024-05-21 00:00:00,64248.0,64890.0,64074.0,64747.0,68.8861711 +2024-05-21 02:00:00,64742.0,65000.0,64077.0,64974.0,47.60493408 +2024-05-21 04:00:00,64974.0,64989.0,63635.0,64124.0,113.28588184 +2024-05-21 06:00:00,64124.0,65178.0,64000.0,64180.0,121.34779503 +2024-05-21 08:00:00,64521.0,65000.0,64112.0,64898.0,68.10428832 +2024-05-21 10:00:00,64887.0,65402.0,64300.0,65107.0,106.79819416 +2024-05-21 12:00:00,65107.0,65423.0,64520.0,64563.0,110.84242221 +2024-05-21 14:00:00,64572.0,65008.0,63113.0,63705.0,107.86172168 +2024-05-21 16:00:00,63617.0,64219.0,63125.0,64010.0,93.19435788 +2024-05-21 18:00:00,64018.0,64114.0,63000.0,63417.0,87.8170388 +2024-05-21 20:00:00,63415.0,64023.0,63366.0,64008.0,39.15252326 +2024-05-21 22:00:00,63970.0,64478.0,63969.0,64262.0,30.10007463 +2024-05-22 00:00:00,64276.0,64426.0,64185.0,64294.0,10.37965793 +2024-05-22 02:00:00,64330.0,64491.0,64074.0,64186.0,8.87478769 +2024-05-22 04:00:00,64229.0,64229.0,63477.0,64211.0,31.20741102 +2024-05-22 06:00:00,64202.0,64333.0,63912.0,64045.0,51.05921455 +2024-05-22 08:00:00,64038.0,64536.0,63967.0,64442.0,32.84218659 +2024-05-22 10:00:00,64438.0,64784.0,64359.0,64370.0,42.69754102 +2024-05-22 12:00:00,64355.0,64671.0,64019.0,64127.0,52.59699391 +2024-05-22 14:00:00,64194.0,65000.0,64019.0,64923.0,63.57392267 +2024-05-22 16:00:00,64925.0,65096.0,64213.0,64394.0,71.98918302 +2024-05-22 18:00:00,64390.0,64477.0,63945.0,64265.0,65.17994568 +2024-05-22 20:00:00,64330.0,64621.0,63600.0,64177.0,46.08895953 +2024-05-22 22:00:00,64153.0,64206.0,63723.0,63828.0,28.00464437 +2024-05-23 00:00:00,63863.0,64201.0,63858.0,64079.0,7.92251177 +2024-05-23 02:00:00,64079.0,64156.0,63902.0,64025.0,12.04452689 +2024-05-23 04:00:00,64036.0,64197.0,63975.0,64104.0,13.61030392 +2024-05-23 06:00:00,64090.0,64434.0,64030.0,64336.0,37.2461362 +2024-05-23 08:00:00,64327.0,64411.0,64123.0,64162.0,32.59682439 +2024-05-23 10:00:00,64162.0,64544.0,64082.0,64483.0,39.64220001 +2024-05-23 12:00:00,64472.0,64550.0,62416.0,62726.0,161.19100466 +2024-05-23 14:00:00,62727.0,63089.0,62416.0,62855.0,109.24591956 +2024-05-23 16:00:00,62854.0,62998.0,62577.0,62596.0,58.82705656 +2024-05-23 18:00:00,62619.0,62998.0,61773.0,62162.0,145.09956815 +2024-05-23 20:00:00,62167.0,63254.0,61477.0,62880.0,103.63637301 +2024-05-23 22:00:00,62932.0,62943.0,62462.0,62927.0,24.03308798 +2024-05-24 00:00:00,62916.0,62983.0,62637.0,62722.0,14.79398619 +2024-05-24 02:00:00,62720.0,62972.0,62649.0,62865.0,6.96501595 +2024-05-24 04:00:00,62876.0,62891.0,62118.0,62298.0,23.28874326 +2024-05-24 06:00:00,62283.0,62570.0,61801.0,62064.0,41.47181343 +2024-05-24 08:00:00,62072.0,62318.0,61560.0,62243.0,56.65996864 +2024-05-24 10:00:00,62242.0,62313.0,62118.0,62178.0,23.24773344 +2024-05-24 12:00:00,62177.0,62374.0,61760.0,61890.0,36.61122779 +2024-05-24 14:00:00,61891.0,63118.0,61787.0,63033.0,63.46074369 +2024-05-24 16:00:00,63031.0,63597.0,62684.0,63584.0,58.05714886 +2024-05-24 18:00:00,63575.0,63899.0,63453.0,63795.0,48.04091799 +2024-05-24 20:00:00,63793.0,63864.0,63489.0,63567.0,32.53775579 +2024-05-24 22:00:00,63568.0,63568.0,63246.0,63267.0,16.0533587 +2024-05-25 00:00:00,63267.0,63395.0,63212.0,63314.0,4.99320485 +2024-05-25 02:00:00,63314.0,63553.0,63296.0,63437.0,3.39072915 +2024-05-25 04:00:00,63422.0,63486.0,63355.0,63392.0,5.0007507 +2024-05-25 06:00:00,63392.0,63492.0,63310.0,63452.0,12.2634134 +2024-05-25 08:00:00,63447.0,63833.0,63438.0,63771.0,20.98627475 +2024-05-25 10:00:00,63770.0,64231.0,63701.0,63790.0,38.37766729 +2024-05-25 12:00:00,63793.0,63984.0,63590.0,63721.0,24.37338591 +2024-05-25 14:00:00,63727.0,63888.0,63565.0,63627.0,11.49323708 +2024-05-25 16:00:00,63632.0,63780.0,63556.0,63748.0,10.51069271 +2024-05-25 18:00:00,63747.0,63925.0,63742.0,63822.0,16.33608092 +2024-05-25 20:00:00,63820.0,63879.0,63719.0,63804.0,10.8157103 +2024-05-25 22:00:00,63814.0,64000.0,63715.0,63925.0,4.28789041 +2024-05-26 00:00:00,63945.0,63967.0,63807.0,63827.0,3.87178612 +2024-05-26 02:00:00,63838.0,63839.0,63540.0,63733.0,2.99675261 +2024-05-26 04:00:00,63704.0,63780.0,63591.0,63776.0,3.36930058 +2024-05-26 06:00:00,63780.0,64039.0,63686.0,63950.0,7.01376091 +2024-05-26 08:00:00,63944.0,64123.0,63656.0,63750.0,19.01310379 +2024-05-26 10:00:00,63749.0,63869.0,63692.0,63762.0,13.05114115 +2024-05-26 12:00:00,63762.0,63773.0,63550.0,63731.0,16.19078594 +2024-05-26 14:00:00,63730.0,63951.0,63300.0,63475.0,22.26296514 +2024-05-26 16:00:00,63478.0,63595.0,63356.0,63435.0,19.17097148 +2024-05-26 18:00:00,63429.0,63557.0,63366.0,63543.0,13.80329256 +2024-05-26 20:00:00,63549.0,63549.0,62926.0,63178.0,26.47192414 +2024-05-26 22:00:00,63146.0,63337.0,63031.0,63175.0,6.26697775 +2024-05-27 00:00:00,63172.0,63881.0,63141.0,63689.0,2.73465649 +2024-05-27 02:00:00,63670.0,63861.0,63431.0,63467.0,8.16588883 +2024-05-27 04:00:00,63470.0,63480.0,62974.0,63150.0,9.31964106 +2024-05-27 06:00:00,63144.0,63324.0,62979.0,63245.0,28.48235921 +2024-05-27 08:00:00,63248.0,63494.0,63026.0,63074.0,39.48625051 +2024-05-27 10:00:00,63074.0,63184.0,62772.0,62966.0,39.30701667 +2024-05-27 12:00:00,62967.0,63569.0,62966.0,63437.0,34.86331453 +2024-05-27 14:00:00,63442.0,64900.0,63351.0,64714.0,112.41647212 +2024-05-27 16:00:00,64722.0,64979.0,64354.0,64502.0,92.11756536 +2024-05-27 18:00:00,64543.0,64578.0,63500.0,63648.0,70.69506606 +2024-05-27 20:00:00,63650.0,64241.0,63600.0,64177.0,26.92046733 +2024-05-27 22:00:00,64176.0,64176.0,63754.0,63868.0,11.44300384 +2024-05-28 00:00:00,63852.0,63957.0,63020.0,63074.0,10.90081084 +2024-05-28 02:00:00,63039.0,63310.0,62288.0,62557.0,45.90848784 +2024-05-28 04:00:00,62529.0,62658.0,62031.0,62604.0,68.83018212 +2024-05-28 06:00:00,62596.0,62609.0,62203.0,62245.0,46.64307609 +2024-05-28 08:00:00,62239.0,63016.0,62150.0,62830.0,45.45851999 +2024-05-28 10:00:00,62816.0,63326.0,62695.0,62808.0,36.33015904 +2024-05-28 12:00:00,62801.0,62979.0,62215.0,62323.0,44.55915923 +2024-05-28 14:00:00,62340.0,62877.0,62123.0,62795.0,40.65032624 +2024-05-28 16:00:00,62811.0,62871.0,62193.0,62323.0,39.64875375 +2024-05-28 18:00:00,62336.0,63145.0,61935.0,62951.0,45.87104391 +2024-05-28 20:00:00,62963.0,63062.0,62685.0,62916.0,17.02208833 +2024-05-28 22:00:00,62897.0,63168.0,62897.0,62957.0,6.82728182 +2024-05-29 00:00:00,62958.0,63232.0,62867.0,63106.0,3.73024776 +2024-05-29 02:00:00,63122.0,63428.0,63037.0,63358.0,19.42589463 +2024-05-29 04:00:00,63339.0,63454.0,63118.0,63148.0,19.69383199 +2024-05-29 06:00:00,63152.0,63209.0,62520.0,62520.0,26.08048489 +2024-05-29 08:00:00,62544.0,62710.0,62320.0,62522.0,31.55650484 +2024-05-29 10:00:00,62522.0,62669.0,62362.0,62394.0,17.18159598 +2024-05-29 12:00:00,62397.0,62918.0,62225.0,62566.0,32.98739241 +2024-05-29 14:00:00,62596.0,62700.0,62222.0,62287.0,22.55710518 +2024-05-29 16:00:00,62289.0,62590.0,62077.0,62484.0,34.87196187 +2024-05-29 18:00:00,62501.0,62700.0,62160.0,62224.0,20.25311371 +2024-05-29 20:00:00,62236.0,62734.0,62128.0,62602.0,17.6738697 +2024-05-29 22:00:00,62624.0,62738.0,62509.0,62591.0,6.2601253 +2024-05-30 00:00:00,62563.0,62752.0,62450.0,62720.0,7.27751134 +2024-05-30 02:00:00,62718.0,63089.0,62718.0,62997.0,4.23828406 +2024-05-30 04:00:00,63030.0,63286.0,62885.0,63066.0,25.60651098 +2024-05-30 06:00:00,63081.0,63110.0,62425.0,62488.0,31.34669308 +2024-05-30 08:00:00,62488.0,62643.0,62066.0,62635.0,38.40210148 +2024-05-30 10:00:00,62629.0,62917.0,62461.0,62663.0,21.02225824 +2024-05-30 12:00:00,62665.0,63400.0,62614.0,63377.0,51.95169272 +2024-05-30 14:00:00,63387.0,63500.0,62870.0,63214.0,47.32899521 +2024-05-30 16:00:00,63261.0,64061.0,63058.0,63916.0,72.01703428 +2024-05-30 18:00:00,63917.0,63999.0,63113.0,63309.0,63.02821992 +2024-05-30 20:00:00,63309.0,63309.0,62773.0,63109.0,32.1534363 +2024-05-30 22:00:00,63093.0,63223.0,62952.0,63076.0,6.38584237 +2024-05-31 00:00:00,63071.0,63340.0,63001.0,63197.0,1.93023809 +2024-05-31 02:00:00,63224.0,63473.0,63216.0,63313.0,5.64965961 +2024-05-31 04:00:00,63333.0,63422.0,63087.0,63224.0,8.57822752 +2024-05-31 06:00:00,63224.0,63225.0,62870.0,62961.0,18.90319627 +2024-05-31 08:00:00,62962.0,63076.0,62611.0,62647.0,28.93904176 +2024-05-31 10:00:00,62646.0,63066.0,62626.0,62980.0,24.13212295 +2024-05-31 12:00:00,62984.0,63600.0,62575.0,62637.0,49.32311824 +2024-05-31 14:00:00,62617.0,62617.0,61961.0,61974.0,113.9502432 +2024-05-31 16:00:00,61974.0,62219.0,61500.0,62110.0,71.07192069 +2024-05-31 18:00:00,62115.0,62658.0,61920.0,62314.0,37.85871812 +2024-05-31 20:00:00,62362.0,62473.0,62236.0,62270.0,15.23514648 +2024-05-31 22:00:00,62283.0,62371.0,61983.0,62261.0,12.03742697 +2024-06-01 00:00:00,62303.0,62383.0,62183.0,62280.0,1.20844037 +2024-06-01 02:00:00,62276.0,62461.0,62276.0,62386.0,2.55085122 +2024-06-01 04:00:00,62437.0,62471.0,62308.0,62373.0,6.89349088 +2024-06-01 06:00:00,62370.0,62457.0,62300.0,62363.0,7.12812317 +2024-06-01 08:00:00,62360.0,62467.0,62360.0,62437.0,10.39797848 +2024-06-01 10:00:00,62436.0,62468.0,62366.0,62404.0,7.56001665 +2024-06-01 12:00:00,62405.0,62598.0,62383.0,62441.0,19.24554129 +2024-06-01 14:00:00,62436.0,62563.0,62399.0,62412.0,8.52245999 +2024-06-01 16:00:00,62412.0,62565.0,62300.0,62509.0,10.53924677 +2024-06-01 18:00:00,62503.0,62527.0,62393.0,62466.0,5.11812047 +2024-06-01 20:00:00,62436.0,62509.0,62394.0,62446.0,6.93428893 +2024-06-01 22:00:00,62438.0,62556.0,62404.0,62464.0,4.07524579 +2024-06-02 00:00:00,62464.0,62590.0,62413.0,62441.0,2.10844947 +2024-06-02 02:00:00,62407.0,62502.0,62368.0,62486.0,1.66955134 +2024-06-02 04:00:00,62481.0,62544.0,62416.0,62428.0,1.66466998 +2024-06-02 06:00:00,62408.0,62544.0,62408.0,62464.0,8.91490235 +2024-06-02 08:00:00,62438.0,62520.0,62127.0,62237.0,9.36581977 +2024-06-02 10:00:00,62245.0,62960.0,62136.0,62918.0,26.87170534 +2024-06-02 12:00:00,62927.0,62967.0,62493.0,62816.0,19.31124643 +2024-06-02 14:00:00,62811.0,63069.0,62666.0,62798.0,38.91369029 +2024-06-02 16:00:00,62801.0,62858.0,62508.0,62562.0,20.39167418 +2024-06-02 18:00:00,62531.0,62531.0,62047.0,62457.0,26.55309089 +2024-06-02 20:00:00,62455.0,62601.0,62291.0,62535.0,9.91408747 +2024-06-02 22:00:00,62526.0,62677.0,62464.0,62464.0,8.16816484 +2024-06-03 00:00:00,62465.0,63116.0,62315.0,63026.0,10.29690249 +2024-06-03 02:00:00,63112.0,63350.0,62825.0,63027.0,23.96921863 +2024-06-03 04:00:00,63034.0,63354.0,62921.0,63278.0,22.28894455 +2024-06-03 06:00:00,63295.0,63753.0,63220.0,63515.0,75.7108661 +2024-06-03 08:00:00,63529.0,63917.0,63524.0,63644.0,50.51754292 +2024-06-03 10:00:00,63677.0,63836.0,63462.0,63651.0,41.2652284 +2024-06-03 12:00:00,63650.0,64689.0,63650.0,64206.0,134.29366785 +2024-06-03 14:00:00,64189.0,64311.0,62959.0,63900.0,123.62934824 +2024-06-03 16:00:00,63900.0,63980.0,63197.0,63580.0,26.58488611 +2024-06-03 18:00:00,63572.0,63716.0,63307.0,63497.0,22.60110506 +2024-06-03 20:00:00,63464.0,63739.0,63197.0,63338.0,21.12485361 +2024-06-03 22:00:00,63328.0,63377.0,63000.0,63088.0,17.66823117 +2024-06-04 00:00:00,63066.0,63455.0,62918.0,63455.0,11.46743235 +2024-06-04 02:00:00,63422.0,63584.0,63338.0,63394.0,3.69688074 +2024-06-04 04:00:00,63353.0,63484.0,63194.0,63219.0,10.64303885 +2024-06-04 06:00:00,63213.0,63408.0,63041.0,63359.0,15.39038044 +2024-06-04 08:00:00,63354.0,63529.0,63053.0,63190.0,24.52255564 +2024-06-04 10:00:00,63191.0,63500.0,63182.0,63487.0,15.84759247 +2024-06-04 12:00:00,63476.0,64211.0,63346.0,63957.0,48.91706606 +2024-06-04 14:00:00,63975.0,64726.0,63719.0,64696.0,169.30385618 +2024-06-04 16:00:00,64698.0,65192.0,63450.0,64672.0,212.88090118 +2024-06-04 18:00:00,64680.0,65110.0,64222.0,64541.0,95.94482484 +2024-06-04 20:00:00,64534.0,64766.0,64309.0,64727.0,36.8894654 +2024-06-04 22:00:00,64759.0,64855.0,64551.0,64675.0,10.82822179 +2024-06-05 00:00:00,64682.0,65297.0,64540.0,65022.0,24.24925081 +2024-06-05 02:00:00,64991.0,65147.0,64739.0,65014.0,8.8954393 +2024-06-05 04:00:00,65015.0,65309.0,64910.0,65113.0,38.50075054 +2024-06-05 06:00:00,65107.0,65500.0,65000.0,65404.0,74.01185913 +2024-06-05 08:00:00,65393.0,65444.0,65031.0,65094.0,44.40609963 +2024-06-05 10:00:00,65098.0,65304.0,64925.0,65206.0,46.01228926 +2024-06-05 12:00:00,65203.0,65299.0,64789.0,64908.0,39.15391349 +2024-06-05 14:00:00,64920.0,65900.0,64740.0,65814.0,119.06233836 +2024-06-05 16:00:00,65800.0,66000.0,65475.0,65826.0,65.30876166 +2024-06-05 18:00:00,65823.0,65923.0,65112.0,65476.0,63.94534253 +2024-06-05 20:00:00,65472.0,65565.0,65251.0,65358.0,22.199402 +2024-06-05 22:00:00,65357.0,65477.0,64992.0,65315.0,13.35058014 +2024-06-06 00:00:00,65312.0,65378.0,65066.0,65212.0,5.88349541 +2024-06-06 02:00:00,65227.0,65319.0,65151.0,65179.0,11.3364372 +2024-06-06 04:00:00,65176.0,65237.0,64958.0,65047.0,20.20239601 +2024-06-06 06:00:00,65052.0,65239.0,65003.0,65208.0,25.1747731 +2024-06-06 08:00:00,65208.0,65332.0,65108.0,65183.0,25.33085715 +2024-06-06 10:00:00,65202.0,65500.0,65116.0,65469.0,26.46613158 +2024-06-06 12:00:00,65469.0,65666.0,65254.0,65346.0,55.83247073 +2024-06-06 14:00:00,65304.0,65800.0,65219.0,65470.0,37.31553405 +2024-06-06 16:00:00,65475.0,65552.0,65015.0,65253.0,38.18839563 +2024-06-06 18:00:00,65248.0,65294.0,64672.0,64694.0,35.04113407 +2024-06-06 20:00:00,64685.0,65074.0,64346.0,64977.0,51.94363952 +2024-06-06 22:00:00,64972.0,65143.0,64874.0,64984.0,16.82272508 +2024-06-07 00:00:00,64982.0,65080.0,64885.0,65024.0,4.47360345 +2024-06-07 02:00:00,65005.0,65153.0,64850.0,65141.0,2.74993126 +2024-06-07 04:00:00,65157.0,65571.0,65157.0,65431.0,22.09180398 +2024-06-07 06:00:00,65448.0,65494.0,65190.0,65233.0,18.07079321 +2024-06-07 08:00:00,65238.0,65372.0,65167.0,65370.0,29.05148984 +2024-06-07 10:00:00,65372.0,65697.0,65297.0,65697.0,80.35672668 diff --git a/tests/resources/settings.py b/tests/resources/settings.py index b549bec6..599620e9 100644 --- a/tests/resources/settings.py +++ b/tests/resources/settings.py @@ -6,4 +6,4 @@ 'DATABASE_TYPE': 'sqlite3', 'DATABASE_NAME': 'test_db', 'DATABASE_DIRECTORY_PATH': BASE_DIR -} \ No newline at end of file +} diff --git a/tests/resources/stubs/market_service_stub.py b/tests/resources/stubs/market_service_stub.py index b3274cce..b8dad6ce 100644 --- a/tests/resources/stubs/market_service_stub.py +++ b/tests/resources/stubs/market_service_stub.py @@ -157,7 +157,8 @@ def get_balance(self, market) -> Dict[str, float]: return self._balances def get_order(self, order, market): - symbol = f"{order.target_symbol.upper()}/{order.trading_symbol.upper()}" + symbol = f"{order.target_symbol.upper()}" \ + f"/{order.trading_symbol.upper()}" order_data = { 'info': { 'orderId': 'e8f8a3f7-0930-4778-a102-5145ed7e7873', @@ -228,7 +229,8 @@ def get_order(self, order, market): 'id': '16d3b5b7-a460-472b-ab6d-964b890f7d03', 'symbol': 'DOT/EUR', 'timestamp': 1674386553405, 'datetime': '2023-01-22T11:22:33.405Z', 'order': None, - 'order_type': None, 'order_side': None, 'takerOrMaker': 'taker', + 'order_type': None, 'order_side': None, + 'takerOrMaker': 'taker', 'price': 5.7915, 'amount': 2.99863309, 'cost': 17.366583540735, 'fee': {'cost': 0.043416459265, 'currency': 'EUR'}, diff --git a/tests/resources/utils.py b/tests/resources/utils.py index 02c042ce..2c40fa1a 100644 --- a/tests/resources/utils.py +++ b/tests/resources/utils.py @@ -5,7 +5,7 @@ def random_string(n, spaces: bool = False): if spaces: - return ''.join(random.choice(string.ascii_lowercase + ' ') for _ in range(n)) + return ''.join(random.choice(string.ascii_lowercase + ' ') + for _ in range(n)) return ''.join(random.choice(string.ascii_lowercase) for _ in range(n)) - diff --git a/tests/services/test_order_backtest_service.py b/tests/services/test_order_backtest_service.py index 83b90b3e..50c58db3 100644 --- a/tests/services/test_order_backtest_service.py +++ b/tests/services/test_order_backtest_service.py @@ -64,12 +64,12 @@ def setUp(self) -> None: order_repository=self.app.container.order_repository(), position_repository=self.app.container.position_repository(), portfolio_repository=self.app.container.portfolio_repository(), - portfolio_configuration_service=self.app.container\ - .portfolio_configuration_service(), - portfolio_snapshot_service=self.app.container\ - .portfolio_snapshot_service(), - configuration_service=self.app.container.\ - configuration_service(), + portfolio_configuration_service=self.app.container. + portfolio_configuration_service(), + portfolio_snapshot_service=self.app.container. + portfolio_snapshot_service(), + configuration_service=self.app.container. + configuration_service(), market_data_source_service=backtest_market_data_source_service ) ) @@ -230,7 +230,7 @@ def test_update_buy_order_with_successful_order_filled(self): def test_update_sell_order_with_successful_order(self): pass - def test_update_sell_order_with_successful_order_filled_and_closing_partial_buy_orders(self): + def test_update_closing_partial_buy_orders(self): order_service = self.app.container.order_service() config = self.app.config config[BACKTESTING_INDEX_DATETIME] = datetime.utcnow() diff --git a/tests/services/test_order_service.py b/tests/services/test_order_service.py index 162442ad..e275967a 100644 --- a/tests/services/test_order_service.py +++ b/tests/services/test_order_service.py @@ -169,7 +169,7 @@ def test_update_buy_order_with_successful_order_filled(self): def test_update_sell_order_with_successful_order(self): pass - def test_update_sell_order_with_successful_order_filled_and_closing_partial_buy_orders(self): + def test_update_sell_order_closing_partial_buy_orders(self): order_service = self.app.container.order_service() buy_order_one = order_service.create( { diff --git a/tests/services/test_portfolio_sync_service.py b/tests/services/test_portfolio_sync_service.py index 7861c964..8f7b3b81 100644 --- a/tests/services/test_portfolio_sync_service.py +++ b/tests/services/test_portfolio_sync_service.py @@ -164,9 +164,10 @@ def test_sync_unallocated_with_initial_size(self): def test_sync_unallocated_with_stateless(self): """ Test to sync the unallocated amount with initial load set to false. - This means that if the available balance is less than the initial balance - of the portfolio configuration, the unallocated balance should be set to the - available balance. It should not raise an OperationalException. + This means that if the available balance is less than the + initial balance of the portfolio configuration, the + unallocated balance should be set to the available balance. It + should not raise an OperationalException. """ self.app.add_portfolio_configuration( PortfolioConfiguration( diff --git a/tests/test_create_app.py b/tests/test_create_app.py index 5ae2971a..dc1cd7e8 100644 --- a/tests/test_create_app.py +++ b/tests/test_create_app.py @@ -76,7 +76,9 @@ def test_create_app_web(self): secret_key="secret_key" ) ) - app.container.market_service.override(MarketServiceStub(app.container.market_credential_service())) + app.container.market_service.override( + MarketServiceStub(app.container.market_credential_service()) + ) app.initialize() self.assertIsNotNone(app) self.assertIsNotNone(app._flask_app) From 47d75e89beedd7c31b00ec0c3fcb402452217c76 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 23:49:43 +0200 Subject: [PATCH 22/31] Fix flake8 warnings --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 5c2ca51b..3a73f7bd 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -__version__='v3.6.0' +__version__ = 'v3.6.0' From b1a44a20dcef6a0f214d52ac47c0c3cfbcda85e4 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Mon, 1 Jul 2024 23:55:04 +0200 Subject: [PATCH 23/31] Update poetry lock --- poetry.lock | 1090 ++++++++++++++++++++++++++------------------------- 1 file changed, 562 insertions(+), 528 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5008e6e1..b98d24cc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "aiodns" -version = "3.1.1" +version = "3.2.0" description = "Simple DNS resolver for asyncio" optional = false python-versions = "*" files = [ - {file = "aiodns-3.1.1-py3-none-any.whl", hash = "sha256:a387b63da4ced6aad35b1dda2d09620ad608a1c7c0fb71efa07ebb4cd511928d"}, - {file = "aiodns-3.1.1.tar.gz", hash = "sha256:1073eac48185f7a4150cad7f96a5192d6911f12b4fb894de80a088508c9b3a99"}, + {file = "aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5"}, + {file = "aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72"}, ] [package.dependencies] @@ -16,87 +16,87 @@ pycares = ">=4.0.0" [[package]] name = "aiohttp" -version = "3.9.3" +version = "3.9.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, - {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, - {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, - {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, - {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, - {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, - {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, - {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, - {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, - {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, - {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, - {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"}, + {file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"}, + {file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"}, + {file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"}, + {file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"}, + {file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"}, + {file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"}, + {file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"}, + {file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"}, + {file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"}, + {file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"}, + {file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"}, + {file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"}, + {file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"}, + {file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"}, + {file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8"}, + {file = "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11"}, + {file = "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031"}, + {file = "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe"}, + {file = "aiohttp-3.9.5-cp38-cp38-win32.whl", hash = "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da"}, + {file = "aiohttp-3.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a"}, + {file = "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106"}, + {file = "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46"}, + {file = "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2"}, + {file = "aiohttp-3.9.5-cp39-cp39-win32.whl", hash = "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09"}, + {file = "aiohttp-3.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1"}, + {file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"}, ] [package.dependencies] @@ -126,13 +126,13 @@ frozenlist = ">=1.1.0" [[package]] name = "alembic" -version = "1.13.1" +version = "1.13.2" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, ] [package.dependencies] @@ -147,13 +147,13 @@ tz = ["backports.zoneinfo"] [[package]] name = "anyio" -version = "4.3.0" +version = "4.4.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, ] [package.dependencies] @@ -318,13 +318,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "babel" -version = "2.14.0" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, - {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] [package.dependencies] @@ -385,24 +385,24 @@ css = ["tinycss2 (>=1.1.0,<1.3)"] [[package]] name = "blinker" -version = "1.7.0" +version = "1.8.2" description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.8" files = [ - {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, - {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, ] [[package]] name = "ccxt" -version = "4.2.48" +version = "4.3.55" description = "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges" optional = false python-versions = "*" files = [ - {file = "ccxt-4.2.48-py2.py3-none-any.whl", hash = "sha256:2e12117e4e3b203943c80f96696995e0c726a89ba49183dcf7f2ace3c85abdc2"}, - {file = "ccxt-4.2.48.tar.gz", hash = "sha256:73b212d8beb6f439f17591cb5a6e38392268e8023f35443552b844d96ed55cac"}, + {file = "ccxt-4.3.55-py2.py3-none-any.whl", hash = "sha256:65d387eba959250b4f373c5bc07566960ce33c7c9e5e45be98c2228d11380e58"}, + {file = "ccxt-4.3.55.tar.gz", hash = "sha256:f40588e66e068dd52cd9f4d18a3b511bab7cfa304b5f8d47533c2e36c35a12dd"}, ] [package.dependencies] @@ -421,13 +421,13 @@ type = ["mypy (==1.6.1)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -701,43 +701,43 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.4" +version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:ffc73996c4fca3d2b6c1c8c12bfd3ad00def8621da24f547626bf06441400449"}, - {file = "cryptography-42.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:db4b65b02f59035037fde0998974d84244a64c3265bdef32a827ab9b63d61b18"}, - {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad9c385ba8ee025bb0d856714f71d7840020fe176ae0229de618f14dae7a6e2"}, - {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69b22ab6506a3fe483d67d1ed878e1602bdd5912a134e6202c1ec672233241c1"}, - {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e09469a2cec88fb7b078e16d4adec594414397e8879a4341c6ace96013463d5b"}, - {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3e970a2119507d0b104f0a8e281521ad28fc26f2820687b3436b8c9a5fcf20d1"}, - {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e53dc41cda40b248ebc40b83b31516487f7db95ab8ceac1f042626bc43a2f992"}, - {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c3a5cbc620e1e17009f30dd34cb0d85c987afd21c41a74352d1719be33380885"}, - {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bfadd884e7280df24d26f2186e4e07556a05d37393b0f220a840b083dc6a824"}, - {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01911714117642a3f1792c7f376db572aadadbafcd8d75bb527166009c9f1d1b"}, - {file = "cryptography-42.0.4-cp37-abi3-win32.whl", hash = "sha256:fb0cef872d8193e487fc6bdb08559c3aa41b659a7d9be48b2e10747f47863925"}, - {file = "cryptography-42.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c1f25b252d2c87088abc8bbc4f1ecbf7c919e05508a7e8628e6875c40bc70923"}, - {file = "cryptography-42.0.4-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:15a1fb843c48b4a604663fa30af60818cd28f895572386e5f9b8a665874c26e7"}, - {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1327f280c824ff7885bdeef8578f74690e9079267c1c8bd7dc5cc5aa065ae52"}, - {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ffb03d419edcab93b4b19c22ee80c007fb2d708429cecebf1dd3258956a563a"}, - {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1df6fcbf60560d2113b5ed90f072dc0b108d64750d4cbd46a21ec882c7aefce9"}, - {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:44a64043f743485925d3bcac548d05df0f9bb445c5fcca6681889c7c3ab12764"}, - {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3c6048f217533d89f2f8f4f0fe3044bf0b2090453b7b73d0b77db47b80af8dff"}, - {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6d0fbe73728c44ca3a241eff9aefe6496ab2656d6e7a4ea2459865f2e8613257"}, - {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:887623fe0d70f48ab3f5e4dbf234986b1329a64c066d719432d0698522749929"}, - {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ce8613beaffc7c14f091497346ef117c1798c202b01153a8cc7b8e2ebaaf41c0"}, - {file = "cryptography-42.0.4-cp39-abi3-win32.whl", hash = "sha256:810bcf151caefc03e51a3d61e53335cd5c7316c0a105cc695f0959f2c638b129"}, - {file = "cryptography-42.0.4-cp39-abi3-win_amd64.whl", hash = "sha256:a0298bdc6e98ca21382afe914c642620370ce0470a01e1bef6dd9b5354c36854"}, - {file = "cryptography-42.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f8907fcf57392cd917892ae83708761c6ff3c37a8e835d7246ff0ad251d9298"}, - {file = "cryptography-42.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:12d341bd42cdb7d4937b0cabbdf2a94f949413ac4504904d0cdbdce4a22cbf88"}, - {file = "cryptography-42.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1cdcdbd117681c88d717437ada72bdd5be9de117f96e3f4d50dab3f59fd9ab20"}, - {file = "cryptography-42.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0e89f7b84f421c56e7ff69f11c441ebda73b8a8e6488d322ef71746224c20fce"}, - {file = "cryptography-42.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f1e85a178384bf19e36779d91ff35c7617c885da487d689b05c1366f9933ad74"}, - {file = "cryptography-42.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d2a27aca5597c8a71abbe10209184e1a8e91c1fd470b5070a2ea60cafec35bcd"}, - {file = "cryptography-42.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4e36685cb634af55e0677d435d425043967ac2f3790ec652b2b88ad03b85c27b"}, - {file = "cryptography-42.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f47be41843200f7faec0683ad751e5ef11b9a56a220d57f300376cd8aba81660"}, - {file = "cryptography-42.0.4.tar.gz", hash = "sha256:831a4b37accef30cccd34fcb916a5d7b5be3cbbe27268a02832c3e450aea39cb"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, ] [package.dependencies] @@ -755,33 +755,33 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -924,13 +924,13 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastjsonschema" -version = "2.19.1" +version = "2.20.0" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, + {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, + {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, ] [package.extras] @@ -1260,43 +1260,43 @@ socks = ["socksio (==1.*)"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "8.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"}, + {file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.1" +version = "6.4.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, - {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, + {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, + {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, ] [package.dependencies] @@ -1304,17 +1304,17 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] +testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "ipykernel" -version = "6.29.4" +version = "6.29.5" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, - {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, + {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, + {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, ] [package.dependencies] @@ -1380,21 +1380,21 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa [[package]] name = "ipywidgets" -version = "8.1.2" +version = "8.1.3" description = "Jupyter interactive widgets" optional = false python-versions = ">=3.7" files = [ - {file = "ipywidgets-8.1.2-py3-none-any.whl", hash = "sha256:bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60"}, - {file = "ipywidgets-8.1.2.tar.gz", hash = "sha256:d0b9b41e49bae926a866e613a39b0f0097745d2b9f1f3dd406641b4a57ec42c9"}, + {file = "ipywidgets-8.1.3-py3-none-any.whl", hash = "sha256:efafd18f7a142248f7cb0ba890a68b96abd4d6e88ddbda483c9130d12667eaf2"}, + {file = "ipywidgets-8.1.3.tar.gz", hash = "sha256:f5f9eeaae082b1823ce9eac2575272952f40d748893972956dc09700a6392d9c"}, ] [package.dependencies] comm = ">=0.1.3" ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.10,<3.1.0" +jupyterlab-widgets = ">=3.0.11,<3.1.0" traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.10,<4.1.0" +widgetsnbextension = ">=4.0.11,<4.1.0" [package.extras] test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] @@ -1415,13 +1415,13 @@ arrow = ">=0.15.0" [[package]] name = "itsdangerous" -version = "2.1.2" +version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] [[package]] @@ -1445,13 +1445,13 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jinja2" -version = "3.1.3" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -1473,13 +1473,13 @@ files = [ [[package]] name = "jsonpointer" -version = "2.4" +version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +python-versions = ">=3.7" files = [ - {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, - {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, ] [[package]] @@ -1550,13 +1550,13 @@ qtconsole = "*" [[package]] name = "jupyter-client" -version = "8.6.1" +version = "8.6.2" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, - {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, + {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, + {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, ] [package.dependencies] @@ -1569,7 +1569,7 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-console" @@ -1657,13 +1657,13 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.14.0" +version = "2.14.1" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server-2.14.0-py3-none-any.whl", hash = "sha256:fb6be52c713e80e004fac34b35a0990d6d36ba06fd0a2b2ed82b899143a64210"}, - {file = "jupyter_server-2.14.0.tar.gz", hash = "sha256:659154cea512083434fd7c93b7fe0897af7a2fd0b9dd4749282b42eaac4ae677"}, + {file = "jupyter_server-2.14.1-py3-none-any.whl", hash = "sha256:16f7177c3a4ea8fe37784e2d31271981a812f0b2874af17339031dc3510cc2a5"}, + {file = "jupyter_server-2.14.1.tar.gz", hash = "sha256:12558d158ec7a0653bf96cc272bc7ad79e0127d503b982ed144399346694f726"}, ] [package.dependencies] @@ -1688,7 +1688,7 @@ traitlets = ">=5.6.0" websocket-client = ">=1.7" [package.extras] -docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] +docs = ["ipykernel", "jinja2", "jupyter-client", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.7)", "pytest-timeout", "requests"] [[package]] @@ -1712,13 +1712,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.1.8" +version = "4.2.3" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.1.8-py3-none-any.whl", hash = "sha256:c3baf3a2f91f89d110ed5786cd18672b9a357129d4e389d2a0dead15e11a4d2c"}, - {file = "jupyterlab-4.1.8.tar.gz", hash = "sha256:3384aded8680e7ce504fd63b8bb89a39df21c9c7694d9e7dc4a68742cdb30f9b"}, + {file = "jupyterlab-4.2.3-py3-none-any.whl", hash = "sha256:0b59d11808e84bb84105c73364edfa867dd475492429ab34ea388a52f2e2e596"}, + {file = "jupyterlab-4.2.3.tar.gz", hash = "sha256:df6e46969ea51d66815167f23d92f105423b7f1f06fa604d4f44aeb018c82c7b"}, ] [package.dependencies] @@ -1734,16 +1734,17 @@ jupyter-server = ">=2.4.0,<3" jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2" packaging = "*" +setuptools = ">=40.1.0" tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} tornado = ">=6.2.0" traitlets = "*" [package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.2.0)"] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.3.5)"] docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.2.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.1)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.0.post6)", "matplotlib (==3.8.2)", "nbconvert (>=7.0.0)", "pandas (==2.2.0)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] +docs-screenshots = ["altair (==5.3.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.2)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.1.post2)", "matplotlib (==3.8.3)", "nbconvert (>=7.0.0)", "pandas (==2.2.1)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] -upgrade-extension = ["copier (>=8.0,<9.0)", "jinja2-time (<0.3)", "pydantic (<2.0)", "pyyaml-include (<2.0)", "tomli-w (<2.0)"] +upgrade-extension = ["copier (>=8,<10)", "jinja2-time (<0.3)", "pydantic (<2.0)", "pyyaml-include (<2.0)", "tomli-w (<2.0)"] [[package]] name = "jupyterlab-pygments" @@ -1758,13 +1759,13 @@ files = [ [[package]] name = "jupyterlab-server" -version = "2.27.1" +version = "2.27.2" description = "A set of server components for JupyterLab and JupyterLab like applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab_server-2.27.1-py3-none-any.whl", hash = "sha256:f5e26156e5258b24d532c84e7c74cc212e203bff93eb856f81c24c16daeecc75"}, - {file = "jupyterlab_server-2.27.1.tar.gz", hash = "sha256:097b5ac709b676c7284ac9c5e373f11930a561f52cd5a86e4fc7e5a9c8a8631d"}, + {file = "jupyterlab_server-2.27.2-py3-none-any.whl", hash = "sha256:54aa2d64fd86383b5438d9f0c032f043c4d8c0264b8af9f60bd061157466ea43"}, + {file = "jupyterlab_server-2.27.2.tar.gz", hash = "sha256:15cbb349dc45e954e09bacf81b9f9bcb10815ff660fb2034ecd7417db3a7ea27"}, ] [package.dependencies] @@ -1784,24 +1785,24 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v [[package]] name = "jupyterlab-widgets" -version = "3.0.10" +version = "3.0.11" description = "Jupyter interactive widgets for JupyterLab" optional = false python-versions = ">=3.7" files = [ - {file = "jupyterlab_widgets-3.0.10-py3-none-any.whl", hash = "sha256:dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64"}, - {file = "jupyterlab_widgets-3.0.10.tar.gz", hash = "sha256:04f2ac04976727e4f9d0fa91cdc2f1ab860f965e504c29dbd6a65c882c9d04c0"}, + {file = "jupyterlab_widgets-3.0.11-py3-none-any.whl", hash = "sha256:78287fd86d20744ace330a61625024cf5521e1c012a352ddc0a3cdc2348becd0"}, + {file = "jupyterlab_widgets-3.0.11.tar.gz", hash = "sha256:dd5ac679593c969af29c9bed054c24f26842baa51352114736756bc035deee27"}, ] [[package]] name = "mako" -version = "1.3.2" +version = "1.3.5" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, - {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, + {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, + {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, ] [package.dependencies] @@ -1883,22 +1884,21 @@ files = [ [[package]] name = "marshmallow" -version = "3.20.2" +version = "3.21.3" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ - {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, - {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, + {file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"}, + {file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["pre-commit (>=2.4,<4.0)"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -2130,26 +2130,26 @@ files = [ [[package]] name = "notebook" -version = "7.1.3" +version = "7.2.1" description = "Jupyter Notebook - A web-based notebook environment for interactive computing" optional = false python-versions = ">=3.8" files = [ - {file = "notebook-7.1.3-py3-none-any.whl", hash = "sha256:919b911e59f41f6e3857ce93c9d93535ba66bb090059712770e5968c07e1004d"}, - {file = "notebook-7.1.3.tar.gz", hash = "sha256:41fcebff44cf7bb9377180808bcbae066629b55d8c7722f1ebbe75ca44f9cfc1"}, + {file = "notebook-7.2.1-py3-none-any.whl", hash = "sha256:f45489a3995746f2195a137e0773e2130960b51c9ac3ce257dbc2705aab3a6ca"}, + {file = "notebook-7.2.1.tar.gz", hash = "sha256:4287b6da59740b32173d01d641f763d292f49c30e7a51b89c46ba8473126341e"}, ] [package.dependencies] jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.1.1,<4.2" -jupyterlab-server = ">=2.22.1,<3" +jupyterlab = ">=4.2.0,<4.3" +jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2,<0.3" tornado = ">=6.2.0" [package.extras] dev = ["hatch", "pre-commit"] docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.22.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] +test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.27.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] [[package]] name = "notebook-shim" @@ -2218,13 +2218,13 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -2264,8 +2264,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -2358,13 +2358,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.1" +version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, - {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] @@ -2372,19 +2372,34 @@ docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx- test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] type = ["mypy (>=1.8)"] +[[package]] +name = "plotly" +version = "5.22.0" +description = "An open-source, interactive data visualization library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "plotly-5.22.0-py3-none-any.whl", hash = "sha256:68fc1901f098daeb233cc3dd44ec9dc31fb3ca4f4e53189344199c43496ed006"}, + {file = "plotly-5.22.0.tar.gz", hash = "sha256:859fdadbd86b5770ae2466e542b761b247d1c6b49daed765b95bb8c7063e7469"}, +] + +[package.dependencies] +packaging = "*" +tenacity = ">=6.2.0" + [[package]] name = "polars" -version = "0.20.10" +version = "0.20.31" description = "Blazingly fast DataFrame library" optional = false python-versions = ">=3.8" files = [ - {file = "polars-0.20.10-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:14b126dbe626c8df34a9cc1449dea270dbafd64deff88fc3620046e69e06f84c"}, - {file = "polars-0.20.10-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6d5f485dba006aa1ce443980b351a5cb8ff481cbbc51343debfbf66fb9594269"}, - {file = "polars-0.20.10-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff934fe816856db7b72565b35abf1656db485772cd3bc5631071cef7ec1d10c7"}, - {file = "polars-0.20.10-cp38-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:f5b7222ca39a4cbd286d9927d4924d2bc2ce6d7fc83a256bfd20b4199482722f"}, - {file = "polars-0.20.10-cp38-abi3-win_amd64.whl", hash = "sha256:082a22c0c1bfa1fe0c24198e646ffb19478b893f594ecf8e330c7cdc136f6e6b"}, - {file = "polars-0.20.10.tar.gz", hash = "sha256:ab32a232916df61c9377edcb5893d0b1624d810444d8fa627f9885d33819a8b7"}, + {file = "polars-0.20.31-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:86454ade5ed302bbf87f145cfcb1b14f7a5765a9440e448659e1f3dba6ac4e79"}, + {file = "polars-0.20.31-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:67f2fe842262b7e1b9371edad21b760f6734d28b74c78dda88dff1bf031b9499"}, + {file = "polars-0.20.31-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b82441f93409e0e8abd6f427b029db102f02b8de328cee9a680f84b84e3736"}, + {file = "polars-0.20.31-cp38-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:87f43bce4d41abf8c8c5658d881e4b8378e5c61010a696bfea8b4106b908e916"}, + {file = "polars-0.20.31-cp38-abi3-win_amd64.whl", hash = "sha256:2d7567c9fd9d3b9aa93387ca9880d9e8f7acea3c0a0555c03d8c0c2f0715d43c"}, + {file = "polars-0.20.31.tar.gz", hash = "sha256:00f62dec6bf43a4e2a5db58b99bf0e79699fe761c80ae665868eaea5168f3bbb"}, ] [package.dependencies] @@ -2393,13 +2408,16 @@ pandas = {version = "*", optional = true, markers = "extra == \"pandas\""} pyarrow = {version = ">=7.0.0", optional = true, markers = "extra == \"pandas\""} [package.extras] -adbc = ["adbc_driver_sqlite"] -all = ["polars[adbc,cloudpickle,connectorx,deltalake,fsspec,gevent,numpy,pandas,plot,pyarrow,pydantic,pyiceberg,sqlalchemy,timezone,xlsx2csv,xlsxwriter]"] +adbc = ["adbc-driver-manager", "adbc-driver-sqlite"] +all = ["polars[adbc,async,cloudpickle,connectorx,deltalake,fastexcel,fsspec,gevent,iceberg,numpy,pandas,plot,pyarrow,pydantic,sqlalchemy,timezone,xlsx2csv,xlsxwriter]"] +async = ["nest-asyncio"] cloudpickle = ["cloudpickle"] connectorx = ["connectorx (>=0.3.2)"] -deltalake = ["deltalake (>=0.14.0)"] +deltalake = ["deltalake (>=0.15.0)"] +fastexcel = ["fastexcel (>=0.9)"] fsspec = ["fsspec"] gevent = ["gevent"] +iceberg = ["pyiceberg (>=0.5.0)"] matplotlib = ["matplotlib"] numpy = ["numpy (>=1.16.0)"] openpyxl = ["openpyxl (>=3.0.0)"] @@ -2407,10 +2425,9 @@ pandas = ["pandas", "pyarrow (>=7.0.0)"] plot = ["hvplot (>=0.9.1)"] pyarrow = ["pyarrow (>=7.0.0)"] pydantic = ["pydantic"] -pyiceberg = ["pyiceberg (>=0.5.0)"] pyxlsb = ["pyxlsb (>=1.0)"] sqlalchemy = ["pandas", "sqlalchemy"] -timezone = ["backports.zoneinfo", "tzdata"] +timezone = ["backports-zoneinfo", "tzdata"] xlsx2csv = ["xlsx2csv (>=0.8.0)"] xlsxwriter = ["xlsxwriter"] @@ -2430,13 +2447,13 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.43" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] @@ -2444,27 +2461,28 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.8" +version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, - {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, - {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, - {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, - {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, - {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, - {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, - {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, - {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, - {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, - {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, - {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, - {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, + {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, + {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, + {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, + {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, + {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, + {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, + {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, + {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, + {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, + {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, ] [package.extras] @@ -2497,51 +2515,51 @@ tests = ["pytest"] [[package]] name = "pyarrow" -version = "15.0.0" +version = "16.1.0" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-15.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0a524532fd6dd482edaa563b686d754c70417c2f72742a8c990b322d4c03a15d"}, - {file = "pyarrow-15.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:60a6bdb314affa9c2e0d5dddf3d9cbb9ef4a8dddaa68669975287d47ece67642"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66958fd1771a4d4b754cd385835e66a3ef6b12611e001d4e5edfcef5f30391e2"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f500956a49aadd907eaa21d4fff75f73954605eaa41f61cb94fb008cf2e00c6"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6f87d9c4f09e049c2cade559643424da84c43a35068f2a1c4653dc5b1408a929"}, - {file = "pyarrow-15.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85239b9f93278e130d86c0e6bb455dcb66fc3fd891398b9d45ace8799a871a1e"}, - {file = "pyarrow-15.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b8d43e31ca16aa6e12402fcb1e14352d0d809de70edd185c7650fe80e0769e3"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:fa7cd198280dbd0c988df525e50e35b5d16873e2cdae2aaaa6363cdb64e3eec5"}, - {file = "pyarrow-15.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8780b1a29d3c8b21ba6b191305a2a607de2e30dab399776ff0aa09131e266340"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0ec198ccc680f6c92723fadcb97b74f07c45ff3fdec9dd765deb04955ccf19"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036a7209c235588c2f07477fe75c07e6caced9b7b61bb897c8d4e52c4b5f9555"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2bd8a0e5296797faf9a3294e9fa2dc67aa7f10ae2207920dbebb785c77e9dbe5"}, - {file = "pyarrow-15.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e8ebed6053dbe76883a822d4e8da36860f479d55a762bd9e70d8494aed87113e"}, - {file = "pyarrow-15.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d53a9d1b2b5bd7d5e4cd84d018e2a45bc9baaa68f7e6e3ebed45649900ba99"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9950a9c9df24090d3d558b43b97753b8f5867fb8e521f29876aa021c52fda351"}, - {file = "pyarrow-15.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:003d680b5e422d0204e7287bb3fa775b332b3fce2996aa69e9adea23f5c8f970"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f75fce89dad10c95f4bf590b765e3ae98bcc5ba9f6ce75adb828a334e26a3d40"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca9cb0039923bec49b4fe23803807e4ef39576a2bec59c32b11296464623dc2"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ed5a78ed29d171d0acc26a305a4b7f83c122d54ff5270810ac23c75813585e4"}, - {file = "pyarrow-15.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6eda9e117f0402dfcd3cd6ec9bfee89ac5071c48fc83a84f3075b60efa96747f"}, - {file = "pyarrow-15.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a3a6180c0e8f2727e6f1b1c87c72d3254cac909e609f35f22532e4115461177"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:19a8918045993349b207de72d4576af0191beef03ea655d8bdb13762f0cd6eac"}, - {file = "pyarrow-15.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0ec076b32bacb6666e8813a22e6e5a7ef1314c8069d4ff345efa6246bc38593"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5db1769e5d0a77eb92344c7382d6543bea1164cca3704f84aa44e26c67e320fb"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2617e3bf9df2a00020dd1c1c6dce5cc343d979efe10bc401c0632b0eef6ef5b"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:d31c1d45060180131caf10f0f698e3a782db333a422038bf7fe01dace18b3a31"}, - {file = "pyarrow-15.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:c8c287d1d479de8269398b34282e206844abb3208224dbdd7166d580804674b7"}, - {file = "pyarrow-15.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:07eb7f07dc9ecbb8dace0f58f009d3a29ee58682fcdc91337dfeb51ea618a75b"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:47af7036f64fce990bb8a5948c04722e4e3ea3e13b1007ef52dfe0aa8f23cf7f"}, - {file = "pyarrow-15.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93768ccfff85cf044c418bfeeafce9a8bb0cee091bd8fd19011aff91e58de540"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6ee87fd6892700960d90abb7b17a72a5abb3b64ee0fe8db6c782bcc2d0dc0b4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:001fca027738c5f6be0b7a3159cc7ba16a5c52486db18160909a0831b063c4e4"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:d1c48648f64aec09accf44140dccb92f4f94394b8d79976c426a5b79b11d4fa7"}, - {file = "pyarrow-15.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:972a0141be402bb18e3201448c8ae62958c9c7923dfaa3b3d4530c835ac81aed"}, - {file = "pyarrow-15.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:f01fc5cf49081426429127aa2d427d9d98e1cb94a32cb961d583a70b7c4504e6"}, - {file = "pyarrow-15.0.0.tar.gz", hash = "sha256:876858f549d540898f927eba4ef77cd549ad8d24baa3207cf1b72e5788b50e83"}, -] - -[package.dependencies] -numpy = ">=1.16.6,<2" + {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, + {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, + {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, + {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, + {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, + {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, + {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, + {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, + {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, + {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f"}, + {file = "pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15"}, + {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed"}, + {file = "pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, + {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, + {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, + {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, + {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, +] + +[package.dependencies] +numpy = ">=1.16.6" [[package]] name = "pycares" @@ -2622,13 +2640,13 @@ files = [ [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] @@ -2644,28 +2662,27 @@ files = [ [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -2892,13 +2909,13 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} [[package]] name = "qtconsole" -version = "5.5.1" +version = "5.5.2" description = "Jupyter Qt console" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "qtconsole-5.5.1-py3-none-any.whl", hash = "sha256:8c75fa3e9b4ed884880ff7cea90a1b67451219279ec33deaee1d59e3df1a5d2b"}, - {file = "qtconsole-5.5.1.tar.gz", hash = "sha256:a0e806c6951db9490628e4df80caec9669b65149c7ba40f9bf033c025a5b56bc"}, + {file = "qtconsole-5.5.2-py3-none-any.whl", hash = "sha256:42d745f3d05d36240244a04e1e1ec2a86d5d9b6edb16dbdef582ccb629e87e0b"}, + {file = "qtconsole-5.5.2.tar.gz", hash = "sha256:6b5fb11274b297463706af84dcbbd5c92273b1f619e6d25d08874b0a88516989"}, ] [package.dependencies] @@ -2949,13 +2966,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -2995,123 +3012,126 @@ files = [ [[package]] name = "rpds-py" -version = "0.18.0" +version = "0.18.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, - {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, - {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, - {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, - {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, - {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, - {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, - {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, - {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, - {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, - {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, - {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, - {file = "rpds_py-0.18.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0"}, - {file = "rpds_py-0.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3"}, - {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f"}, - {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7"}, - {file = "rpds_py-0.18.0-cp312-none-win32.whl", hash = "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98"}, - {file = "rpds_py-0.18.0-cp312-none-win_amd64.whl", hash = "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec"}, - {file = "rpds_py-0.18.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e"}, - {file = "rpds_py-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d"}, - {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c"}, - {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594"}, - {file = "rpds_py-0.18.0-cp38-none-win32.whl", hash = "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e"}, - {file = "rpds_py-0.18.0-cp38-none-win_amd64.whl", hash = "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1"}, - {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, - {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, - {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, - {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, - {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, - {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, - {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, - {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, - {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, - {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, ] [[package]] name = "schedule" -version = "1.2.1" +version = "1.2.2" description = "Job scheduling for humans." optional = false python-versions = ">=3.7" files = [ - {file = "schedule-1.2.1-py2.py3-none-any.whl", hash = "sha256:14cdeb083a596aa1de6dc77639a1b2ac8bf6eaafa82b1c9279d3612823063d01"}, - {file = "schedule-1.2.1.tar.gz", hash = "sha256:843bc0538b99c93f02b8b50e3e39886c06f2d003b24f48e1aa4cadfa3f341279"}, + {file = "schedule-1.2.2-py3-none-any.whl", hash = "sha256:5bef4a2a0183abf44046ae0d164cadcac21b1db011bdd8102e4a0c1e91e06a7d"}, + {file = "schedule-1.2.2.tar.gz", hash = "sha256:15fe9c75fe5fd9b9627f3f19cc0ef1420508f9f9a46f45cd0769ef75ede5f0b7"}, ] +[package.extras] +timezone = ["pytz"] + [[package]] name = "send2trash" version = "1.8.3" @@ -3130,19 +3150,18 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "69.1.0" +version = "70.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, - {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, + {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"}, + {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -3179,64 +3198,64 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.27" +version = "2.0.31" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d04e579e911562f1055d26dab1868d3e0bb905db3bccf664ee8ad109f035618a"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa67d821c1fd268a5a87922ef4940442513b4e6c377553506b9db3b83beebbd8"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c7a596d0be71b7baa037f4ac10d5e057d276f65a9a611c46970f012752ebf2d"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954d9735ee9c3fa74874c830d089a815b7b48df6f6b6e357a74130e478dbd951"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5cd20f58c29bbf2680039ff9f569fa6d21453fbd2fa84dbdb4092f006424c2e6"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:03f448ffb731b48323bda68bcc93152f751436ad6037f18a42b7e16af9e91c07"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win32.whl", hash = "sha256:d997c5938a08b5e172c30583ba6b8aad657ed9901fc24caf3a7152eeccb2f1b4"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win_amd64.whl", hash = "sha256:eb15ef40b833f5b2f19eeae65d65e191f039e71790dd565c2af2a3783f72262f"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c5bad7c60a392850d2f0fee8f355953abaec878c483dd7c3836e0089f046bf6"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3012ab65ea42de1be81fff5fb28d6db893ef978950afc8130ba707179b4284a"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbcd77c4d94b23e0753c5ed8deba8c69f331d4fd83f68bfc9db58bc8983f49cd"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d177b7e82f6dd5e1aebd24d9c3297c70ce09cd1d5d37b43e53f39514379c029c"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:680b9a36029b30cf063698755d277885d4a0eab70a2c7c6e71aab601323cba45"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1306102f6d9e625cebaca3d4c9c8f10588735ef877f0360b5cdb4fdfd3fd7131"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win32.whl", hash = "sha256:5b78aa9f4f68212248aaf8943d84c0ff0f74efc65a661c2fc68b82d498311fd5"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win_amd64.whl", hash = "sha256:15e19a84b84528f52a68143439d0c7a3a69befcd4f50b8ef9b7b69d2628ae7c4"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0de1263aac858f288a80b2071990f02082c51d88335a1db0d589237a3435fe71"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce850db091bf7d2a1f2fdb615220b968aeff3849007b1204bf6e3e50a57b3d32"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dfc936870507da96aebb43e664ae3a71a7b96278382bcfe84d277b88e379b18"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4fbe6a766301f2e8a4519f4500fe74ef0a8509a59e07a4085458f26228cd7cc"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4535c49d961fe9a77392e3a630a626af5baa967172d42732b7a43496c8b28876"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0fb3bffc0ced37e5aa4ac2416f56d6d858f46d4da70c09bb731a246e70bff4d5"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win32.whl", hash = "sha256:7f470327d06400a0aa7926b375b8e8c3c31d335e0884f509fe272b3c700a7254"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win_amd64.whl", hash = "sha256:f9374e270e2553653d710ece397df67db9d19c60d2647bcd35bfc616f1622dcd"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e97cf143d74a7a5a0f143aa34039b4fecf11343eed66538610debc438685db4a"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7b5a3e2120982b8b6bd1d5d99e3025339f7fb8b8267551c679afb39e9c7c7f1"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e36aa62b765cf9f43a003233a8c2d7ffdeb55bc62eaa0a0380475b228663a38f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5ada0438f5b74c3952d916c199367c29ee4d6858edff18eab783b3978d0db16d"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b1d9d1bfd96eef3c3faedb73f486c89e44e64e40e5bfec304ee163de01cf996f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win32.whl", hash = "sha256:ca891af9f3289d24a490a5fde664ea04fe2f4984cd97e26de7442a4251bd4b7c"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win_amd64.whl", hash = "sha256:fd8aafda7cdff03b905d4426b714601c0978725a19efc39f5f207b86d188ba01"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec1f5a328464daf7a1e4e385e4f5652dd9b1d12405075ccba1df842f7774b4fc"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad862295ad3f644e3c2c0d8b10a988e1600d3123ecb48702d2c0f26771f1c396"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48217be1de7d29a5600b5c513f3f7664b21d32e596d69582be0a94e36b8309cb"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e56afce6431450442f3ab5973156289bd5ec33dd618941283847c9fd5ff06bf"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:611068511b5531304137bcd7fe8117c985d1b828eb86043bd944cebb7fae3910"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b86abba762ecfeea359112b2bb4490802b340850bbee1948f785141a5e020de8"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win32.whl", hash = "sha256:30d81cc1192dc693d49d5671cd40cdec596b885b0ce3b72f323888ab1c3863d5"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win_amd64.whl", hash = "sha256:120af1e49d614d2525ac247f6123841589b029c318b9afbfc9e2b70e22e1827d"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d07ee7793f2aeb9b80ec8ceb96bc8cc08a2aec8a1b152da1955d64e4825fcbac"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb0845e934647232b6ff5150df37ceffd0b67b754b9fdbb095233deebcddbd4a"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc19ae2e07a067663dd24fca55f8ed06a288384f0e6e3910420bf4b1270cc51"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90053be91973a6fb6020a6e44382c97739736a5a9d74e08cc29b196639eb979"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5c9dfb0b9ab5e3a8a00249534bdd838d943ec4cfb9abe176a6c33408430230"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33e8bde8fff203de50399b9039c4e14e42d4d227759155c21f8da4a47fc8053c"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win32.whl", hash = "sha256:d873c21b356bfaf1589b89090a4011e6532582b3a8ea568a00e0c3aab09399dd"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win_amd64.whl", hash = "sha256:ff2f1b7c963961d41403b650842dc2039175b906ab2093635d8319bef0b7d620"}, - {file = "SQLAlchemy-2.0.27-py3-none-any.whl", hash = "sha256:1ab4e0448018d01b142c916cc7119ca573803a4745cfe341b8f95657812700ac"}, - {file = "SQLAlchemy-2.0.27.tar.gz", hash = "sha256:86a6ed69a71fe6b88bf9331594fa390a2adda4a49b5c06f98e47bf0d392534f8"}, -] - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win32.whl", hash = "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win32.whl", hash = "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win32.whl", hash = "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win_amd64.whl", hash = "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win32.whl", hash = "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win32.whl", hash = "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win32.whl", hash = "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc"}, + {file = "SQLAlchemy-2.0.31-py3-none-any.whl", hash = "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911"}, + {file = "SQLAlchemy-2.0.31.tar.gz", hash = "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] @@ -3297,6 +3316,21 @@ files = [ [package.extras] widechars = ["wcwidth"] +[[package]] +name = "tenacity" +version = "8.4.2" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tenacity-8.4.2-py3-none-any.whl", hash = "sha256:9e6f7cf7da729125c7437222f8a522279751cdfbe6b67bfe64f75d3a348661b2"}, + {file = "tenacity-8.4.2.tar.gz", hash = "sha256:cd80a53a79336edba8489e767f729e4f391c896956b57140b5d7511a64bbd3ef"}, +] + +[package.extras] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] + [[package]] name = "terminado" version = "0.18.1" @@ -3349,33 +3383,33 @@ files = [ [[package]] name = "tornado" -version = "6.4" +version = "6.4.1" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, - {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, - {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, - {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, - {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, - {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, - {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, + {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, + {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, + {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, ] [[package]] name = "tqdm" -version = "4.66.2" +version = "4.66.4" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, - {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, + {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, + {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, ] [package.dependencies] @@ -3415,13 +3449,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -3451,13 +3485,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] @@ -3479,18 +3513,18 @@ files = [ [[package]] name = "webcolors" -version = "1.13" +version = "24.6.0" description = "A library for working with the color formats defined by HTML and CSS." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, - {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, + {file = "webcolors-24.6.0-py3-none-any.whl", hash = "sha256:8cf5bc7e28defd1d48b9e83d5fc30741328305a8195c29a8e668fa45586568a1"}, + {file = "webcolors-24.6.0.tar.gz", hash = "sha256:1d160d1de46b3e81e58d0a280d0c78b467dc80f47294b91b1ad8029d2cedb55b"}, ] [package.extras] docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] -tests = ["pytest", "pytest-cov"] +tests = ["coverage[toml]"] [[package]] name = "webencodings" @@ -3521,13 +3555,13 @@ test = ["websockets"] [[package]] name = "werkzeug" -version = "3.0.1" +version = "3.0.3" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, - {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, + {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, + {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, ] [package.dependencies] @@ -3538,13 +3572,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "widgetsnbextension" -version = "4.0.10" +version = "4.0.11" description = "Jupyter interactive widgets for Jupyter Notebook" optional = false python-versions = ">=3.7" files = [ - {file = "widgetsnbextension-4.0.10-py3-none-any.whl", hash = "sha256:d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc"}, - {file = "widgetsnbextension-4.0.10.tar.gz", hash = "sha256:64196c5ff3b9a9183a8e699a4227fb0b7002f252c814098e66c4d1cd0644688f"}, + {file = "widgetsnbextension-4.0.11-py3-none-any.whl", hash = "sha256:55d4d6949d100e0d08b94948a42efc3ed6dfdc0e9468b2c4b128c9a2ce3a7a36"}, + {file = "widgetsnbextension-4.0.11.tar.gz", hash = "sha256:8b22a8f1910bfd188e596fe7fc05dcbd87e810c8a4ba010bdb3da86637398474"}, ] [[package]] @@ -3731,20 +3765,20 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.17.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "ccc8302927ae1b2b6a906e25a9bcc991faf2f8ca6dafc7d606618dfabe81f977" +content-hash = "40dbc94cbd9f3248ef1caf81aab5813fbfe894f0e22c2b160829233890121618" From 05b421fcb43bce1c7f82839d4c5abafb59a3bb82 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 2 Jul 2024 10:31:50 +0200 Subject: [PATCH 24/31] Fix tests with existing data sources --- ..._ccxt_ohlcv_backtest_market_data_source.py | 8 +- ..._15m_2023-12-14:21:45_2023-12-25:00:00.csv | 971 ++++++++++++++++++ 2 files changed, 975 insertions(+), 4 deletions(-) create mode 100644 tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv diff --git a/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py b/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py index a79980a6..373cf615 100644 --- a/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py +++ b/tests/infrastructure/market_data_sources/test_ccxt_ohlcv_backtest_market_data_source.py @@ -57,7 +57,7 @@ def test_file_path(self): data_source.prepare_data( config={ RESOURCE_DIRECTORY: self.resource_dir, - BACKTEST_DATA_DIRECTORY_NAME: "market_data_sources" + BACKTEST_DATA_DIRECTORY_NAME: "market_data_sources_for_testing" }, backtest_start_date=datetime(2023, 12, 17, 00, 00), backtest_end_date=datetime(2023, 12, 25, 00, 00), @@ -77,7 +77,7 @@ def test_window_size(self): data_source.prepare_data( config={ RESOURCE_DIRECTORY: self.resource_dir, - BACKTEST_DATA_DIRECTORY_NAME: "market_data_sources" + BACKTEST_DATA_DIRECTORY_NAME: "market_data_sources_for_testing" }, backtest_start_date=datetime(2023, 12, 17, 00, 00), backtest_end_date=datetime(2023, 12, 25, 00, 00), @@ -88,7 +88,7 @@ def test_window_size(self): def test_right_columns(self): correct_file_name = \ "OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv" - csv_file_path = f"{self.resource_dir}/market_data_sources" \ + csv_file_path = f"{self.resource_dir}/market_data_sources_for_testing"\ f"/{correct_file_name}" data_source = CCXTOHLCVBacktestMarketDataSource( identifier="OHLCV_BTC_EUR_BINANCE_15m", @@ -101,7 +101,7 @@ def test_right_columns(self): data_source.prepare_data( config={ RESOURCE_DIRECTORY: self.resource_dir, - BACKTEST_DATA_DIRECTORY_NAME: "market_data_sources" + BACKTEST_DATA_DIRECTORY_NAME: "market_data_sources_for_testing" }, backtest_start_date=datetime(2023, 12, 17, 00, 00), backtest_end_date=datetime(2023, 12, 25, 00, 00), diff --git a/tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv b/tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv new file mode 100644 index 00000000..892a2b1f --- /dev/null +++ b/tests/resources/market_data_sources_for_testing/OHLCV_BTC-EUR_BINANCE_15m_2023-12-14:21:45_2023-12-25:00:00.csv @@ -0,0 +1,971 @@ +Datetime,Open,High,Low,Close,Volume +2023-12-14 21:45:00,39128.08,39141.69,39052.04,39095.74,1.50493 +2023-12-14 22:00:00,39100.0,39189.55,39057.71,39189.55,2.25035 +2023-12-14 22:15:00,39195.79,39236.46,39126.93,39137.79,1.92944 +2023-12-14 22:30:00,39142.4,39222.4,39142.36,39161.67,0.96785 +2023-12-14 22:45:00,39160.24,39246.26,39160.24,39202.63,0.76673 +2023-12-14 23:00:00,39209.46,39305.64,39207.07,39229.76,0.79119 +2023-12-14 23:15:00,39224.96,39294.6,39160.24,39192.18,0.92677 +2023-12-14 23:30:00,39191.27,39191.27,39084.45,39117.64,1.43354 +2023-12-14 23:45:00,39120.3,39160.89,39073.6,39151.11,1.67524 +2023-12-15 00:00:00,39158.21,39188.05,39104.87,39178.29,0.49335 +2023-12-15 00:15:00,39187.42,39246.16,39164.68,39245.52,0.84414 +2023-12-15 00:30:00,39241.0,39241.0,39095.72,39137.32,0.50505 +2023-12-15 00:45:00,39151.47,39194.76,39067.4,39067.4,1.55358 +2023-12-15 01:00:00,39072.93,39123.73,39072.93,39112.46,0.25896 +2023-12-15 01:15:00,39115.95,39208.48,39115.95,39202.42,1.14945 +2023-12-15 01:30:00,39206.74,39211.54,39136.06,39138.28,0.54573 +2023-12-15 01:45:00,39155.94,39160.12,39095.7,39133.28,1.74717 +2023-12-15 02:00:00,39150.15,39164.56,38994.52,39008.79,0.66182 +2023-12-15 02:15:00,39026.38,39056.67,38986.81,39023.16,0.80843 +2023-12-15 02:30:00,39016.43,39063.8,38998.72,39062.41,0.24632 +2023-12-15 02:45:00,39064.99,39064.99,38996.14,38998.53,0.38179 +2023-12-15 03:00:00,38990.07,39011.15,38967.43,38982.06,0.64302 +2023-12-15 03:15:00,38971.93,38971.93,38725.6,38925.03,3.99347 +2023-12-15 03:30:00,38945.83,38945.83,38852.34,38935.25,0.71094 +2023-12-15 03:45:00,38922.8,38950.61,38878.17,38931.13,0.77336 +2023-12-15 04:00:00,38935.02,38941.5,38849.69,38912.16,0.32987 +2023-12-15 04:15:00,38930.2,38930.2,38851.95,38915.33,0.80297 +2023-12-15 04:30:00,38908.24,38918.42,38861.43,38871.19,0.81997 +2023-12-15 04:45:00,38875.83,38957.28,38864.44,38933.19,0.78211 +2023-12-15 05:00:00,38951.39,39013.74,38938.36,38950.18,1.0549 +2023-12-15 05:15:00,38921.87,38976.38,38892.1,38898.9,0.47329 +2023-12-15 05:30:00,38899.74,38899.74,38767.14,38815.63,2.13139 +2023-12-15 05:45:00,38819.96,38843.64,38771.36,38802.56,1.90694 +2023-12-15 06:00:00,38808.46,38846.66,38792.66,38807.35,1.13561 +2023-12-15 06:15:00,38809.95,38838.32,38739.99,38831.89,1.52963 +2023-12-15 06:30:00,38832.31,38839.72,38771.67,38777.96,1.19033 +2023-12-15 06:45:00,38783.98,38824.68,38761.67,38773.02,1.53758 +2023-12-15 07:00:00,38777.24,38832.14,38763.31,38823.38,0.80825 +2023-12-15 07:15:00,38819.39,38901.64,38814.19,38877.06,1.49995 +2023-12-15 07:30:00,38879.39,38885.75,38811.78,38838.95,2.23735 +2023-12-15 07:45:00,38848.83,38886.3,38804.88,38886.1,0.41555 +2023-12-15 08:00:00,38878.37,38927.79,38812.67,38825.93,1.48409 +2023-12-15 08:15:00,38828.42,39008.92,38828.42,38979.91,5.47409 +2023-12-15 08:30:00,38987.57,39073.94,38987.57,39073.94,3.7093 +2023-12-15 08:45:00,39076.99,39178.46,39076.99,39172.86,4.19757 +2023-12-15 09:00:00,39174.73,39300.0,39143.54,39287.17,3.08622 +2023-12-15 09:15:00,39273.99,39273.99,39170.98,39179.9,3.74289 +2023-12-15 09:30:00,39171.38,39221.99,39157.26,39211.67,2.38251 +2023-12-15 09:45:00,39201.95,39234.28,39109.52,39120.4,2.8906 +2023-12-15 10:00:00,39129.21,39173.26,39115.69,39142.02,2.24934 +2023-12-15 10:15:00,39142.03,39167.58,39097.72,39156.54,5.96554 +2023-12-15 10:30:00,39156.18,39159.98,39043.66,39136.46,3.10558 +2023-12-15 10:45:00,39144.34,39155.69,39102.62,39129.26,3.03655 +2023-12-15 11:00:00,39126.39,39140.9,39030.01,39074.69,1.71026 +2023-12-15 11:15:00,39074.84,39080.88,38998.19,39020.6,2.05227 +2023-12-15 11:30:00,39033.79,39070.98,39022.22,39051.4,1.09561 +2023-12-15 11:45:00,39047.73,39047.73,39014.41,39032.03,1.90381 +2023-12-15 12:00:00,39029.54,39029.54,38923.22,38930.15,2.7417 +2023-12-15 12:15:00,38920.95,39025.41,38907.42,39024.36,1.63503 +2023-12-15 12:30:00,39030.68,39057.1,38998.64,39042.4,1.13589 +2023-12-15 12:45:00,39047.05,39055.46,38941.22,38950.12,1.52624 +2023-12-15 13:00:00,38958.48,38969.75,38807.34,38934.27,2.48859 +2023-12-15 13:15:00,38934.85,38959.93,38808.28,38849.11,1.39204 +2023-12-15 13:30:00,38842.07,38881.67,38756.75,38808.07,10.08832 +2023-12-15 13:45:00,38792.75,38844.68,38659.14,38764.8,4.14371 +2023-12-15 14:00:00,38757.85,38818.78,38718.34,38809.43,4.0068 +2023-12-15 14:15:00,38802.64,38802.67,38621.92,38650.45,6.94247 +2023-12-15 14:30:00,38666.87,38702.09,38538.9,38615.72,7.3631 +2023-12-15 14:45:00,38611.14,38670.32,38502.11,38658.36,4.62101 +2023-12-15 15:00:00,38657.16,38736.73,38550.84,38583.82,2.50173 +2023-12-15 15:15:00,38580.92,38633.99,38472.48,38521.07,5.66228 +2023-12-15 15:30:00,38514.07,38517.91,38248.38,38345.77,10.04536 +2023-12-15 15:45:00,38317.58,38427.32,38250.0,38402.02,5.73895 +2023-12-15 16:00:00,38420.23,38500.31,38373.9,38417.65,4.26629 +2023-12-15 16:15:00,38410.53,38602.26,38384.73,38504.6,2.65684 +2023-12-15 16:30:00,38503.84,38516.65,38450.01,38460.0,1.97999 +2023-12-15 16:45:00,38450.0,38454.45,38281.39,38355.1,2.90183 +2023-12-15 17:00:00,38362.18,38478.39,38332.02,38454.99,3.13168 +2023-12-15 17:15:00,38457.37,38555.6,38410.81,38499.36,4.49227 +2023-12-15 17:30:00,38498.95,38571.27,38464.79,38469.76,2.44359 +2023-12-15 17:45:00,38462.59,38465.44,38364.53,38392.29,1.82633 +2023-12-15 18:00:00,38373.61,38470.37,38369.05,38458.0,1.44368 +2023-12-15 18:15:00,38451.28,38583.01,38451.28,38521.93,4.74364 +2023-12-15 18:30:00,38524.82,38611.61,38500.0,38600.29,1.76305 +2023-12-15 18:45:00,38600.44,38705.99,38594.19,38694.95,2.34391 +2023-12-15 19:00:00,38696.37,38700.61,38632.62,38664.47,0.6308 +2023-12-15 19:15:00,38654.05,38697.6,38598.92,38697.6,3.26833 +2023-12-15 19:30:00,38696.85,38768.47,38668.49,38670.2,3.11239 +2023-12-15 19:45:00,38668.56,38672.26,38564.02,38659.45,6.85901 +2023-12-15 20:00:00,38660.45,38697.76,38640.04,38689.76,1.41998 +2023-12-15 20:15:00,38690.01,38780.01,38689.02,38745.94,3.04764 +2023-12-15 20:30:00,38742.89,38743.23,38668.63,38688.97,2.30103 +2023-12-15 20:45:00,38704.64,38812.78,38692.63,38791.82,1.62191 +2023-12-15 21:00:00,38791.82,38810.08,38758.67,38777.45,0.83142 +2023-12-15 21:15:00,38771.57,38799.86,38732.48,38772.83,1.49553 +2023-12-15 21:30:00,38772.84,38816.53,38706.94,38767.71,0.75798 +2023-12-15 21:45:00,38757.2,38805.01,38716.9,38799.04,1.73261 +2023-12-15 22:00:00,38802.44,38820.21,38744.47,38753.29,4.92629 +2023-12-15 22:15:00,38751.13,38774.21,38584.93,38598.2,5.41262 +2023-12-15 22:30:00,38592.23,38674.12,38526.91,38674.12,2.96492 +2023-12-15 22:45:00,38674.12,38761.89,38625.44,38627.29,0.65205 +2023-12-15 23:00:00,38628.26,38729.86,38628.26,38721.55,0.82905 +2023-12-15 23:15:00,38747.6,38747.6,38523.87,38570.37,2.87934 +2023-12-15 23:30:00,38571.47,38598.13,38501.0,38548.28,3.13122 +2023-12-15 23:45:00,38563.18,38604.06,38511.89,38521.35,0.76466 +2023-12-16 00:00:00,38547.32,38624.26,38526.52,38616.17,1.87288 +2023-12-16 00:15:00,38621.25,38646.49,38478.16,38491.24,0.83872 +2023-12-16 00:30:00,38486.6,38501.21,38270.0,38396.82,7.97893 +2023-12-16 00:45:00,38395.42,38524.27,38365.02,38513.95,1.23354 +2023-12-16 01:00:00,38508.23,38662.28,38507.9,38656.71,2.2743 +2023-12-16 01:15:00,38659.86,38738.97,38650.23,38691.25,1.36671 +2023-12-16 01:30:00,38711.9,38722.76,38674.62,38703.52,0.29 +2023-12-16 01:45:00,38693.7,38732.73,38661.14,38670.75,0.7511 +2023-12-16 02:00:00,38670.65,38827.27,38661.74,38733.84,3.50706 +2023-12-16 02:15:00,38736.69,38788.73,38686.4,38757.28,1.73305 +2023-12-16 02:30:00,38744.09,38744.09,38696.64,38708.93,1.2348 +2023-12-16 02:45:00,38717.09,38752.1,38703.31,38752.1,0.60273 +2023-12-16 03:00:00,38756.35,38770.64,38729.01,38748.31,2.22797 +2023-12-16 03:15:00,38752.65,38771.63,38710.43,38771.63,0.70321 +2023-12-16 03:30:00,38796.88,38824.09,38779.8,38813.77,0.67873 +2023-12-16 03:45:00,38830.33,38982.48,38830.33,38912.76,4.37119 +2023-12-16 04:00:00,38935.89,38943.41,38858.06,38901.09,0.95272 +2023-12-16 04:15:00,38899.89,38938.2,38881.62,38906.29,0.34669 +2023-12-16 04:30:00,38901.63,38901.63,38848.78,38869.0,0.21627 +2023-12-16 04:45:00,38867.63,38886.0,38837.11,38878.48,0.68225 +2023-12-16 05:00:00,38876.64,38897.15,38851.59,38854.43,0.39946 +2023-12-16 05:15:00,38853.43,38869.92,38825.56,38825.56,0.87444 +2023-12-16 05:30:00,38839.07,38843.37,38779.21,38788.52,1.41874 +2023-12-16 05:45:00,38794.86,38836.93,38792.02,38826.67,0.54326 +2023-12-16 06:00:00,38837.58,38878.85,38800.47,38801.88,1.18896 +2023-12-16 06:15:00,38805.08,38806.18,38743.67,38775.32,0.72066 +2023-12-16 06:30:00,38776.13,38788.84,38711.57,38749.1,0.7719 +2023-12-16 06:45:00,38771.44,38778.57,38754.87,38775.54,0.14446 +2023-12-16 07:00:00,38763.06,38835.41,38754.78,38832.99,0.44791 +2023-12-16 07:15:00,38819.8,38828.25,38742.53,38768.55,0.55582 +2023-12-16 07:30:00,38759.3,38782.67,38742.58,38766.75,0.48703 +2023-12-16 07:45:00,38770.9,38802.64,38752.34,38794.89,0.51688 +2023-12-16 08:00:00,38795.79,38828.94,38761.95,38824.18,0.44038 +2023-12-16 08:15:00,38824.18,38827.77,38767.43,38781.73,1.65242 +2023-12-16 08:30:00,38784.82,38785.05,38689.49,38722.82,1.723 +2023-12-16 08:45:00,38720.44,38770.76,38717.84,38761.36,0.73359 +2023-12-16 09:00:00,38764.01,38860.4,38764.01,38840.72,1.07469 +2023-12-16 09:15:00,38845.28,38850.28,38809.72,38822.61,0.72666 +2023-12-16 09:30:00,38826.85,38838.5,38767.5,38800.12,0.66904 +2023-12-16 09:45:00,38794.64,38808.37,38761.9,38787.49,0.85644 +2023-12-16 10:00:00,38795.51,38825.29,38775.23,38784.23,0.80309 +2023-12-16 10:15:00,38785.64,38793.71,38764.64,38778.76,0.39897 +2023-12-16 10:30:00,38783.41,38803.03,38778.4,38796.99,1.13789 +2023-12-16 10:45:00,38808.11,38828.79,38791.14,38821.56,0.6265 +2023-12-16 11:00:00,38821.56,38853.18,38785.2,38795.88,0.79338 +2023-12-16 11:15:00,38803.14,38845.79,38795.0,38822.19,1.54604 +2023-12-16 11:30:00,38835.39,38881.24,38828.44,38847.82,0.78127 +2023-12-16 11:45:00,38853.89,38884.19,38847.85,38872.73,1.26279 +2023-12-16 12:00:00,38878.76,38885.31,38809.0,38821.07,1.32943 +2023-12-16 12:15:00,38823.01,38890.41,38817.34,38871.63,5.21268 +2023-12-16 12:30:00,38872.51,39009.38,38868.13,38983.99,2.55642 +2023-12-16 12:45:00,38995.18,38996.28,38917.67,38939.79,1.34263 +2023-12-16 13:00:00,38947.15,39059.77,38936.96,38984.85,5.57618 +2023-12-16 13:15:00,38995.19,38997.8,38861.56,38888.76,2.62163 +2023-12-16 13:30:00,38888.77,38913.12,38787.12,38872.65,3.68659 +2023-12-16 13:45:00,38872.65,38934.05,38872.65,38911.57,1.72882 +2023-12-16 14:00:00,38920.33,38966.55,38878.77,38933.35,1.00798 +2023-12-16 14:15:00,38934.11,38941.8,38837.08,38842.76,2.33842 +2023-12-16 14:30:00,38845.59,38862.84,38830.0,38861.64,1.99295 +2023-12-16 14:45:00,38861.64,38873.54,38831.09,38861.76,2.19682 +2023-12-16 15:00:00,38861.18,38933.4,38851.6,38864.72,2.81658 +2023-12-16 15:15:00,38858.14,38865.09,38802.99,38854.44,2.60712 +2023-12-16 15:30:00,38854.47,38993.18,38844.56,38932.68,1.09301 +2023-12-16 15:45:00,38922.28,39079.05,38905.12,39066.37,3.69001 +2023-12-16 16:00:00,39071.37,39094.0,38956.2,38963.87,2.06734 +2023-12-16 16:15:00,38963.11,39046.91,38963.11,39026.29,0.86076 +2023-12-16 16:30:00,39029.97,39174.98,38986.4,39143.39,2.84865 +2023-12-16 16:45:00,39145.57,39145.57,39000.0,39031.53,1.07781 +2023-12-16 17:00:00,39031.18,39034.8,38963.95,38971.81,1.39095 +2023-12-16 17:15:00,38969.96,39037.92,38963.79,38998.41,0.49874 +2023-12-16 17:30:00,39011.16,39011.17,38920.43,38982.01,0.86834 +2023-12-16 17:45:00,38978.64,39019.5,38951.57,38966.83,1.2677 +2023-12-16 18:00:00,38966.83,38966.83,38887.91,38900.17,1.88246 +2023-12-16 18:15:00,38889.15,38914.12,38833.24,38871.18,1.11452 +2023-12-16 18:30:00,38863.56,38929.51,38858.27,38912.01,1.10296 +2023-12-16 18:45:00,38916.51,38942.36,38842.14,38933.28,1.09705 +2023-12-16 19:00:00,38922.88,38986.36,38867.34,38884.16,0.73322 +2023-12-16 19:15:00,38880.66,38950.35,38869.87,38896.45,1.28539 +2023-12-16 19:30:00,38899.36,38912.19,38800.28,38821.63,1.21743 +2023-12-16 19:45:00,38821.63,38874.4,38809.74,38809.8,0.45654 +2023-12-16 20:00:00,38800.07,38854.88,38783.0,38805.96,0.63513 +2023-12-16 20:15:00,38807.84,38807.84,38759.56,38785.06,1.63378 +2023-12-16 20:30:00,38781.56,38807.9,38755.57,38767.38,0.78453 +2023-12-16 20:45:00,38769.37,38820.09,38721.97,38795.14,1.1935 +2023-12-16 21:00:00,38803.97,38818.07,38689.14,38798.53,2.11447 +2023-12-16 21:15:00,38804.67,38815.62,38731.07,38749.47,4.49177 +2023-12-16 21:30:00,38749.47,38811.66,38718.35,38718.35,2.02621 +2023-12-16 21:45:00,38718.35,38796.79,38655.2,38770.34,4.84391 +2023-12-16 22:00:00,38787.93,38787.93,38600.07,38720.1,1.9227 +2023-12-16 22:15:00,38731.4,38747.42,38694.04,38739.44,0.41578 +2023-12-16 22:30:00,38738.58,38760.09,38667.52,38746.66,0.8923 +2023-12-16 22:45:00,38744.03,38774.15,38722.83,38763.22,0.39877 +2023-12-16 23:00:00,38762.6,38793.22,38680.66,38686.14,0.67917 +2023-12-16 23:15:00,38663.38,38728.25,38663.38,38703.8,0.46704 +2023-12-16 23:30:00,38699.88,38732.51,38690.0,38710.95,0.66646 +2023-12-16 23:45:00,38703.84,38769.87,38692.32,38753.14,0.62154 +2023-12-17 00:00:00,38767.06,38794.41,38737.78,38771.39,0.33613 +2023-12-17 00:15:00,38763.37,38769.45,38720.96,38733.07,0.67716 +2023-12-17 00:30:00,38746.42,38776.27,38723.14,38730.02,0.12557 +2023-12-17 00:45:00,38730.01,38730.01,38670.5,38673.38,0.2783 +2023-12-17 01:00:00,38650.66,38752.0,38650.0,38746.34,0.42893 +2023-12-17 01:15:00,38743.91,38743.91,38690.6,38692.58,0.3063 +2023-12-17 01:30:00,38690.18,38695.35,38565.34,38603.24,1.13005 +2023-12-17 01:45:00,38604.51,38612.77,38425.73,38546.64,4.05907 +2023-12-17 02:00:00,38531.14,38646.24,38522.69,38625.38,0.44623 +2023-12-17 02:15:00,38634.39,38634.4,38568.79,38579.17,0.39436 +2023-12-17 02:30:00,38575.67,38577.97,38509.14,38513.28,0.25462 +2023-12-17 02:45:00,38514.34,38517.6,38428.55,38437.45,1.10104 +2023-12-17 03:00:00,38429.69,38504.54,38429.69,38482.67,0.61654 +2023-12-17 03:15:00,38473.48,38558.24,38472.79,38557.63,0.76696 +2023-12-17 03:30:00,38563.78,38569.65,38483.24,38505.68,0.22423 +2023-12-17 03:45:00,38487.37,38517.76,38460.58,38478.27,0.67442 +2023-12-17 04:00:00,38483.87,38544.58,38471.2,38536.32,0.74008 +2023-12-17 04:15:00,38549.31,38567.08,38526.99,38567.08,0.20098 +2023-12-17 04:30:00,38567.06,38577.54,38547.51,38566.49,0.42167 +2023-12-17 04:45:00,38555.33,38593.19,38530.95,38538.77,0.643 +2023-12-17 05:00:00,38538.84,38595.39,38530.84,38580.01,0.79578 +2023-12-17 05:15:00,38580.75,38597.53,38550.04,38550.04,5.15406 +2023-12-17 05:30:00,38547.11,38552.98,38401.97,38439.14,1.55023 +2023-12-17 05:45:00,38434.82,38500.31,38351.29,38450.4,2.28798 +2023-12-17 06:00:00,38467.13,38536.23,38461.85,38509.62,0.19247 +2023-12-17 06:15:00,38509.41,38532.72,38457.19,38504.44,1.13993 +2023-12-17 06:30:00,38507.63,38507.63,38382.8,38434.15,1.78603 +2023-12-17 06:45:00,38418.78,38585.7,38381.16,38567.61,1.50975 +2023-12-17 07:00:00,38573.12,38596.86,38539.95,38584.52,1.36139 +2023-12-17 07:15:00,38578.01,38589.26,38501.9,38516.07,0.78287 +2023-12-17 07:30:00,38516.07,38546.73,38455.89,38523.54,0.81312 +2023-12-17 07:45:00,38550.13,38559.26,38443.83,38459.27,0.799 +2023-12-17 08:00:00,38459.26,38481.12,38310.22,38314.24,3.80497 +2023-12-17 08:15:00,38313.8,38417.89,38262.29,38406.77,1.92488 +2023-12-17 08:30:00,38405.89,38453.96,38380.97,38453.96,0.69146 +2023-12-17 08:45:00,38439.18,38474.2,38426.79,38470.79,0.57756 +2023-12-17 09:00:00,38478.36,38530.29,38465.33,38477.54,2.14861 +2023-12-17 09:15:00,38477.54,38486.45,38428.11,38442.46,4.74242 +2023-12-17 09:30:00,38446.02,38459.72,38394.33,38401.88,1.42896 +2023-12-17 09:45:00,38401.71,38548.52,38399.16,38531.29,1.09234 +2023-12-17 10:00:00,38537.0,38571.22,38494.77,38527.1,1.02591 +2023-12-17 10:15:00,38525.02,38531.25,38481.87,38502.85,7.22343 +2023-12-17 10:30:00,38503.51,38503.51,38426.27,38447.94,6.08166 +2023-12-17 10:45:00,38448.35,38513.42,38441.05,38466.17,2.13282 +2023-12-17 11:00:00,38466.16,38466.16,38377.58,38416.22,2.19875 +2023-12-17 11:15:00,38412.24,38490.16,38401.59,38437.82,0.94168 +2023-12-17 11:30:00,38439.05,38515.61,38439.05,38515.61,1.18229 +2023-12-17 11:45:00,38510.1,38513.93,38477.16,38484.39,0.6599 +2023-12-17 12:00:00,38488.5,38538.36,38421.04,38437.94,1.3653 +2023-12-17 12:15:00,38434.19,38494.3,38416.57,38463.32,1.81261 +2023-12-17 12:30:00,38464.98,38475.17,38435.7,38436.68,0.79554 +2023-12-17 12:45:00,38451.39,38480.78,38435.85,38439.84,2.24003 +2023-12-17 13:00:00,38449.66,38454.1,38380.14,38383.71,0.93793 +2023-12-17 13:15:00,38377.46,38404.18,38330.15,38404.18,1.73079 +2023-12-17 13:30:00,38404.2,38407.45,38266.03,38278.35,1.87765 +2023-12-17 13:45:00,38281.03,38342.88,38260.0,38324.94,0.95222 +2023-12-17 14:00:00,38327.64,38417.06,38317.51,38380.6,1.34757 +2023-12-17 14:15:00,38380.13,38383.91,38204.04,38220.04,1.17234 +2023-12-17 14:30:00,38223.72,38230.95,38023.0,38184.36,5.11248 +2023-12-17 14:45:00,38202.71,38231.62,38064.96,38087.52,2.20117 +2023-12-17 15:00:00,38087.52,38181.78,38042.05,38134.91,1.35712 +2023-12-17 15:15:00,38135.42,38173.32,38076.28,38096.87,1.10532 +2023-12-17 15:30:00,38093.08,38138.78,38070.11,38122.23,1.89182 +2023-12-17 15:45:00,38124.2,38269.99,38124.2,38221.19,0.69281 +2023-12-17 16:00:00,38227.06,38240.37,38149.05,38200.43,1.35893 +2023-12-17 16:15:00,38202.39,38347.67,38131.65,38342.45,1.17121 +2023-12-17 16:30:00,38336.61,38454.48,38322.32,38403.84,2.62524 +2023-12-17 16:45:00,38408.45,38575.61,38401.3,38547.38,1.09817 +2023-12-17 17:00:00,38547.75,38839.44,38544.91,38839.44,5.14374 +2023-12-17 17:15:00,38829.5,38830.27,38583.13,38661.76,6.29497 +2023-12-17 17:30:00,38661.73,38729.72,38550.79,38550.79,2.10711 +2023-12-17 17:45:00,38575.66,38598.47,38385.02,38438.75,2.76516 +2023-12-17 18:00:00,38439.57,38474.18,38066.61,38146.91,6.08378 +2023-12-17 18:15:00,38142.06,38432.73,38040.49,38358.51,16.14679 +2023-12-17 18:30:00,38357.64,38401.97,38275.97,38342.92,7.2775 +2023-12-17 18:45:00,38350.98,38402.98,38310.0,38366.66,6.6492 +2023-12-17 19:00:00,38373.42,38410.67,38328.43,38369.51,3.20928 +2023-12-17 19:15:00,38378.67,38393.1,38330.39,38344.59,1.96349 +2023-12-17 19:30:00,38352.16,38352.16,38271.33,38334.55,1.71175 +2023-12-17 19:45:00,38332.04,38352.97,38288.83,38308.98,2.11639 +2023-12-17 20:00:00,38312.81,38411.25,38301.76,38411.24,0.78463 +2023-12-17 20:15:00,38411.24,38424.7,38363.75,38424.68,0.72184 +2023-12-17 20:30:00,38439.47,38450.56,38373.03,38416.6,0.54706 +2023-12-17 20:45:00,38404.79,38437.87,38378.3,38379.08,0.85047 +2023-12-17 21:00:00,38379.86,38379.86,38310.64,38314.55,1.0563 +2023-12-17 21:15:00,38306.17,38358.77,38250.0,38255.82,3.40674 +2023-12-17 21:30:00,38250.0,38282.35,38236.78,38267.81,0.46865 +2023-12-17 21:45:00,38259.95,38260.36,38203.95,38219.1,0.54331 +2023-12-17 22:00:00,38208.55,38221.99,38074.51,38080.71,1.63907 +2023-12-17 22:15:00,38104.3,38104.3,37960.01,37968.64,7.42146 +2023-12-17 22:30:00,37960.0,38044.43,37856.27,37999.47,8.08962 +2023-12-17 22:45:00,37999.47,38346.0,37993.0,38253.75,2.65015 +2023-12-17 23:00:00,38253.74,38303.57,38214.08,38214.08,3.68265 +2023-12-17 23:15:00,38223.39,38235.14,38127.33,38139.66,3.01412 +2023-12-17 23:30:00,38139.61,38172.93,37874.8,37986.19,6.60591 +2023-12-17 23:45:00,37997.04,38063.9,37962.79,37965.95,3.94594 +2023-12-18 00:00:00,37974.63,38044.5,37829.0,37843.67,8.92192 +2023-12-18 00:15:00,37833.01,37994.81,37813.67,37992.52,3.30047 +2023-12-18 00:30:00,37982.86,38023.97,37945.76,37963.77,2.76576 +2023-12-18 00:45:00,37954.48,38008.93,37928.1,37961.45,3.1156 +2023-12-18 01:00:00,37960.57,38000.0,37882.68,38000.0,1.32095 +2023-12-18 01:15:00,38004.69,38004.69,37849.7,37875.26,1.23172 +2023-12-18 01:30:00,37858.36,37858.36,37542.05,37618.39,10.32335 +2023-12-18 01:45:00,37633.96,37787.39,37615.98,37615.98,1.83187 +2023-12-18 02:00:00,37624.46,37728.9,37616.28,37709.27,2.00555 +2023-12-18 02:15:00,37714.25,37724.6,37579.14,37605.35,1.27214 +2023-12-18 02:30:00,37596.01,37604.81,37436.35,37522.64,5.27926 +2023-12-18 02:45:00,37497.36,37570.79,37461.83,37518.82,2.66313 +2023-12-18 03:00:00,37507.5,37645.27,37479.49,37597.87,1.9464 +2023-12-18 03:15:00,37573.97,37639.9,37564.97,37622.4,0.70927 +2023-12-18 03:30:00,37620.66,37662.31,37579.14,37662.31,0.59524 +2023-12-18 03:45:00,37676.05,37676.05,37624.98,37658.96,1.34989 +2023-12-18 04:00:00,37668.76,37674.4,37608.15,37655.79,0.53707 +2023-12-18 04:15:00,37652.34,37737.85,37652.32,37722.92,0.50873 +2023-12-18 04:30:00,37745.87,37746.24,37675.58,37708.86,0.36234 +2023-12-18 04:45:00,37715.01,37766.51,37699.73,37765.02,0.46448 +2023-12-18 05:00:00,37745.99,37745.99,37672.2,37683.36,0.90705 +2023-12-18 05:15:00,37674.26,37758.9,37663.84,37742.44,0.84844 +2023-12-18 05:30:00,37736.39,37749.65,37636.61,37656.29,1.17557 +2023-12-18 05:45:00,37646.69,37656.29,37558.62,37571.26,5.4158 +2023-12-18 06:00:00,37550.09,37618.63,37544.53,37598.62,1.45315 +2023-12-18 06:15:00,37596.82,37771.27,37574.13,37750.57,1.93381 +2023-12-18 06:30:00,37734.37,37752.36,37694.79,37714.65,0.5077 +2023-12-18 06:45:00,37705.61,37801.43,37681.26,37717.05,2.65906 +2023-12-18 07:00:00,37722.37,37757.54,37690.69,37754.26,1.00618 +2023-12-18 07:15:00,37752.3,37769.34,37730.37,37741.11,0.50681 +2023-12-18 07:30:00,37741.12,37816.79,37661.42,37670.58,5.59974 +2023-12-18 07:45:00,37659.87,37677.44,37599.74,37622.51,2.24221 +2023-12-18 08:00:00,37625.6,37662.51,37551.79,37569.01,2.5593 +2023-12-18 08:15:00,37567.85,37734.67,37559.81,37732.43,1.36362 +2023-12-18 08:30:00,37712.49,37751.93,37679.07,37751.93,1.11017 +2023-12-18 08:45:00,37751.94,37767.11,37683.68,37715.53,2.21945 +2023-12-18 09:00:00,37714.87,37728.75,37575.57,37576.93,3.87887 +2023-12-18 09:15:00,37573.23,37612.41,37355.0,37430.86,7.40783 +2023-12-18 09:30:00,37432.35,37673.63,37415.58,37634.55,4.48074 +2023-12-18 09:45:00,37627.57,37668.47,37575.35,37594.23,3.2116 +2023-12-18 10:00:00,37594.16,37615.24,37432.22,37463.45,2.51574 +2023-12-18 10:15:00,37466.45,37529.64,37282.88,37310.72,7.63718 +2023-12-18 10:30:00,37298.64,37366.92,37159.01,37298.05,8.15226 +2023-12-18 10:45:00,37300.0,37403.24,37245.48,37391.79,1.89486 +2023-12-18 11:00:00,37399.68,37750.66,37377.08,37722.98,6.37025 +2023-12-18 11:15:00,37730.59,37733.95,37607.27,37650.3,4.01025 +2023-12-18 11:30:00,37642.91,37649.67,37534.79,37534.79,2.75741 +2023-12-18 11:45:00,37531.2,37678.5,37518.19,37671.29,2.08434 +2023-12-18 12:00:00,37671.21,37678.5,37585.32,37585.32,1.77145 +2023-12-18 12:15:00,37585.31,37644.74,37537.37,37644.74,1.92345 +2023-12-18 12:30:00,37639.94,37644.44,37548.11,37576.21,1.84067 +2023-12-18 12:45:00,37576.19,37576.19,37471.86,37480.24,1.61481 +2023-12-18 13:00:00,37483.3,37609.68,37475.67,37538.32,2.78588 +2023-12-18 13:15:00,37544.86,37699.99,37544.86,37684.53,3.07756 +2023-12-18 13:30:00,37685.04,37791.63,37685.04,37729.97,2.4446 +2023-12-18 13:45:00,37727.29,37918.92,37721.87,37860.3,3.94682 +2023-12-18 14:00:00,37858.59,37909.82,37776.13,37785.61,2.75738 +2023-12-18 14:15:00,37787.42,37981.25,37756.0,37980.25,3.07748 +2023-12-18 14:30:00,37979.62,38190.43,37964.94,38164.18,7.28297 +2023-12-18 14:45:00,38141.59,38211.82,38027.92,38068.59,3.24385 +2023-12-18 15:00:00,38078.08,38125.27,37935.38,37965.83,3.76555 +2023-12-18 15:15:00,37970.5,38015.43,37811.22,37835.09,3.23652 +2023-12-18 15:30:00,37835.9,38008.94,37815.55,37978.19,5.0559 +2023-12-18 15:45:00,37978.53,37989.62,37799.25,37802.75,2.56789 +2023-12-18 16:00:00,37817.2,37867.27,37700.0,37822.71,3.68147 +2023-12-18 16:15:00,37836.38,37941.49,37818.07,37908.58,1.89383 +2023-12-18 16:30:00,37907.41,37926.7,37868.98,37884.31,3.09121 +2023-12-18 16:45:00,37884.33,38014.91,37832.12,38010.55,2.53862 +2023-12-18 17:00:00,38005.6,38050.02,37926.73,37953.6,2.58254 +2023-12-18 17:15:00,37985.09,38102.94,37985.09,38084.88,2.09328 +2023-12-18 17:30:00,38105.4,38134.46,38000.0,38040.76,2.07518 +2023-12-18 17:45:00,38044.84,38101.62,37883.69,37887.03,3.40243 +2023-12-18 18:00:00,37877.21,37952.37,37843.26,37912.88,1.97599 +2023-12-18 18:15:00,37915.21,38015.59,37915.21,37977.13,1.37421 +2023-12-18 18:30:00,37977.15,38050.99,37977.15,38036.94,1.92744 +2023-12-18 18:45:00,38037.46,38128.19,38011.02,38128.09,1.96727 +2023-12-18 19:00:00,38130.21,38210.2,38119.68,38153.75,1.68202 +2023-12-18 19:15:00,38178.09,38215.92,38140.17,38192.41,0.99289 +2023-12-18 19:30:00,38191.32,38206.95,38150.0,38178.19,2.09378 +2023-12-18 19:45:00,38185.22,38234.98,38166.79,38208.66,0.59294 +2023-12-18 20:00:00,38218.52,38327.67,38163.2,38184.27,2.11813 +2023-12-18 20:15:00,38186.74,38229.68,38108.43,38212.49,3.04133 +2023-12-18 20:30:00,38214.89,38439.97,38214.88,38379.9,5.62169 +2023-12-18 20:45:00,38399.0,38522.97,38365.01,38451.76,2.71649 +2023-12-18 21:00:00,38459.15,39000.0,38459.15,38871.33,7.36388 +2023-12-18 21:15:00,38863.74,38929.78,38750.39,38858.57,7.64511 +2023-12-18 21:30:00,38847.74,38920.09,38784.67,38907.63,2.41249 +2023-12-18 21:45:00,38902.78,39130.99,38895.51,39014.37,4.43929 +2023-12-18 22:00:00,39035.59,39097.19,38864.94,39072.83,5.1338 +2023-12-18 22:15:00,39064.67,39093.6,38903.09,38907.28,2.71524 +2023-12-18 22:30:00,38919.64,38924.07,38811.32,38846.15,3.0333 +2023-12-18 22:45:00,38846.17,38932.8,38846.17,38900.61,2.11106 +2023-12-18 23:00:00,38902.95,39078.03,38902.95,39064.48,9.68812 +2023-12-18 23:15:00,39057.08,39091.26,38954.02,38988.3,4.94926 +2023-12-18 23:30:00,38983.58,39037.72,38960.84,39003.07,1.27187 +2023-12-18 23:45:00,38996.68,39095.65,38996.68,39037.34,4.20539 +2023-12-19 00:00:00,39043.44,39223.88,38984.79,39036.78,4.4768 +2023-12-19 00:15:00,39067.34,39150.0,38966.77,38980.0,8.16615 +2023-12-19 00:30:00,38993.4,39184.2,38960.0,39116.17,1.11738 +2023-12-19 00:45:00,39122.42,39162.01,39052.11,39077.38,5.64034 +2023-12-19 01:00:00,39084.09,39116.26,38983.89,39085.63,1.70195 +2023-12-19 01:15:00,39093.42,39190.82,38997.59,39190.82,2.50613 +2023-12-19 01:30:00,39190.87,39237.36,39113.69,39219.2,1.16588 +2023-12-19 01:45:00,39214.62,39668.72,39214.62,39608.91,6.60892 +2023-12-19 02:00:00,39631.74,39758.0,39450.0,39497.81,2.96753 +2023-12-19 02:15:00,39509.18,39512.88,39375.11,39382.74,0.82886 +2023-12-19 02:30:00,39388.71,39524.64,39382.78,39515.13,0.66835 +2023-12-19 02:45:00,39492.46,39494.76,39400.03,39400.03,0.29402 +2023-12-19 03:00:00,39416.94,39447.52,39387.29,39388.84,0.2081 +2023-12-19 03:15:00,39393.95,39432.75,39307.71,39309.88,0.70579 +2023-12-19 03:30:00,39331.35,39371.89,39310.61,39340.6,1.52389 +2023-12-19 03:45:00,39323.36,39399.55,39323.36,39397.44,1.33245 +2023-12-19 04:00:00,39425.1,39444.86,39361.41,39399.59,1.59778 +2023-12-19 04:15:00,39409.09,39434.49,39353.23,39355.55,1.31143 +2023-12-19 04:30:00,39334.62,39334.64,39189.71,39199.82,0.88276 +2023-12-19 04:45:00,39224.65,39288.54,39224.65,39258.41,0.30161 +2023-12-19 05:00:00,39259.7,39303.39,39231.23,39277.67,0.73617 +2023-12-19 05:15:00,39287.23,39315.36,39282.91,39310.98,0.25449 +2023-12-19 05:30:00,39310.02,39310.02,39223.35,39228.56,0.46358 +2023-12-19 05:45:00,39227.47,39295.47,39197.1,39280.63,0.39081 +2023-12-19 06:00:00,39278.76,39278.76,39189.71,39189.71,0.38972 +2023-12-19 06:15:00,39189.72,39261.97,39157.77,39229.57,0.94085 +2023-12-19 06:30:00,39232.62,39274.49,39227.35,39250.61,0.76734 +2023-12-19 06:45:00,39257.3,39299.75,39215.26,39229.62,0.77677 +2023-12-19 07:00:00,39242.79,39320.15,39214.86,39320.15,2.35515 +2023-12-19 07:15:00,39312.27,39317.13,39218.09,39234.66,0.67509 +2023-12-19 07:30:00,39240.15,39325.11,39210.72,39302.31,0.79551 +2023-12-19 07:45:00,39318.98,39401.06,39311.02,39334.22,1.29932 +2023-12-19 08:00:00,39337.37,39449.99,39296.81,39431.64,3.09919 +2023-12-19 08:15:00,39443.75,39459.5,39357.96,39455.49,2.22171 +2023-12-19 08:30:00,39463.45,39464.21,39375.06,39416.29,5.3355 +2023-12-19 08:45:00,39416.36,39443.74,39304.11,39349.26,1.50332 +2023-12-19 09:00:00,39349.83,39449.99,39300.0,39447.53,6.28216 +2023-12-19 09:15:00,39447.42,39449.98,39293.58,39303.47,5.65229 +2023-12-19 09:30:00,39300.18,39365.66,39226.86,39334.99,4.60119 +2023-12-19 09:45:00,39355.97,39392.51,39295.73,39313.09,1.01905 +2023-12-19 10:00:00,39322.44,39328.39,39270.01,39288.62,1.86223 +2023-12-19 10:15:00,39279.7,39336.2,39246.87,39322.7,2.13288 +2023-12-19 10:30:00,39324.67,39511.8,39289.63,39479.39,2.19183 +2023-12-19 10:45:00,39500.35,39546.76,39418.49,39430.44,9.12144 +2023-12-19 11:00:00,39429.01,39504.36,39408.04,39439.38,2.33599 +2023-12-19 11:15:00,39446.81,39475.98,39365.42,39392.8,1.26287 +2023-12-19 11:30:00,39377.73,39479.7,39345.23,39449.61,2.01931 +2023-12-19 11:45:00,39449.56,39461.9,39294.84,39301.86,7.01028 +2023-12-19 12:00:00,39301.85,39325.94,39270.68,39299.83,1.78632 +2023-12-19 12:15:00,39315.87,39318.45,39191.02,39240.43,3.50532 +2023-12-19 12:30:00,39234.12,39271.21,39184.7,39200.29,0.9553 +2023-12-19 12:45:00,39208.11,39243.63,39142.0,39156.12,2.68056 +2023-12-19 13:00:00,39156.12,39259.01,39146.1,39225.74,3.30967 +2023-12-19 13:15:00,39215.62,39251.52,39174.33,39202.87,3.10381 +2023-12-19 13:30:00,39200.42,39243.55,39161.93,39196.94,3.60181 +2023-12-19 13:45:00,39184.71,39191.36,39092.35,39103.24,3.73577 +2023-12-19 14:00:00,39102.54,39150.53,38815.48,38899.16,5.63667 +2023-12-19 14:15:00,38879.99,38982.53,38805.32,38971.64,6.50937 +2023-12-19 14:30:00,38977.14,38982.18,38862.24,38868.52,2.12852 +2023-12-19 14:45:00,38869.99,38889.44,38463.17,38578.94,11.91488 +2023-12-19 15:00:00,38578.94,38836.13,38487.45,38802.49,8.03972 +2023-12-19 15:15:00,38787.52,38924.55,38734.73,38924.55,4.06851 +2023-12-19 15:30:00,38927.8,38932.08,38783.6,38840.63,2.55197 +2023-12-19 15:45:00,38840.35,38841.63,38650.78,38680.43,7.48027 +2023-12-19 16:00:00,38667.56,38847.62,38647.9,38834.53,4.66312 +2023-12-19 16:15:00,38844.65,38848.93,38650.49,38685.58,2.6847 +2023-12-19 16:30:00,38685.29,38728.94,38665.89,38666.67,2.75534 +2023-12-19 16:45:00,38666.35,38666.35,38528.8,38559.92,3.58123 +2023-12-19 17:00:00,38560.47,38594.0,38247.15,38277.05,5.61005 +2023-12-19 17:15:00,38281.0,38285.22,38148.85,38227.99,10.00426 +2023-12-19 17:30:00,38236.79,38338.59,38141.35,38295.48,4.48207 +2023-12-19 17:45:00,38288.39,38359.98,38109.62,38142.86,5.04869 +2023-12-19 18:00:00,38124.24,38318.26,38099.53,38316.26,3.424 +2023-12-19 18:15:00,38311.96,38428.47,38299.52,38428.47,3.98557 +2023-12-19 18:30:00,38415.66,38491.91,38366.67,38430.05,3.96269 +2023-12-19 18:45:00,38429.18,38485.8,38394.64,38468.78,1.70053 +2023-12-19 19:00:00,38468.15,38487.84,38404.04,38412.49,2.78462 +2023-12-19 19:15:00,38412.72,38522.28,38412.68,38485.76,1.72538 +2023-12-19 19:30:00,38493.07,38717.44,38493.07,38537.64,2.05228 +2023-12-19 19:45:00,38511.28,38579.5,38462.62,38569.71,1.72295 +2023-12-19 20:00:00,38571.18,38631.2,38519.27,38562.14,2.09612 +2023-12-19 20:15:00,38560.01,38598.71,38500.42,38539.21,2.00457 +2023-12-19 20:30:00,38520.75,38521.52,38391.49,38453.0,2.87744 +2023-12-19 20:45:00,38469.95,38541.88,38431.45,38462.81,1.45451 +2023-12-19 21:00:00,38454.14,38547.51,38454.14,38530.4,2.35364 +2023-12-19 21:15:00,38522.21,38628.85,38502.18,38594.73,0.9989 +2023-12-19 21:30:00,38600.0,38631.91,38559.69,38608.39,0.82337 +2023-12-19 21:45:00,38613.59,38723.21,38601.33,38715.84,1.92443 +2023-12-19 22:00:00,38731.34,38731.34,38519.27,38575.26,1.99255 +2023-12-19 22:15:00,38569.12,38593.53,38513.86,38534.26,2.40714 +2023-12-19 22:30:00,38534.26,38599.97,38482.62,38482.62,0.47798 +2023-12-19 22:45:00,38492.07,38621.11,38492.07,38542.8,0.60587 +2023-12-19 23:00:00,38541.95,38619.05,38525.0,38525.0,1.01653 +2023-12-19 23:15:00,38516.78,38516.78,38468.6,38505.13,0.97804 +2023-12-19 23:30:00,38513.37,38581.05,38438.52,38451.87,1.29126 +2023-12-19 23:45:00,38467.78,38528.27,38467.78,38501.36,0.4129 +2023-12-20 00:00:00,38512.95,38616.07,38485.91,38569.79,1.31487 +2023-12-20 00:15:00,38577.59,38629.67,38554.25,38580.47,2.38634 +2023-12-20 00:30:00,38571.41,38675.66,38568.85,38638.09,1.58327 +2023-12-20 00:45:00,38629.89,38680.01,38629.89,38673.68,0.64803 +2023-12-20 01:00:00,38660.94,38713.28,38660.94,38709.56,0.50645 +2023-12-20 01:15:00,38722.65,38722.65,38631.75,38633.16,0.9652 +2023-12-20 01:30:00,38633.17,38661.24,38554.22,38589.18,0.74014 +2023-12-20 01:45:00,38590.51,38615.45,38511.74,38575.84,1.66342 +2023-12-20 02:00:00,38590.05,38624.12,38490.14,38561.27,1.85544 +2023-12-20 02:15:00,38557.93,38650.52,38557.93,38644.06,0.80246 +2023-12-20 02:30:00,38652.14,38706.09,38652.14,38679.58,2.9622 +2023-12-20 02:45:00,38696.5,38720.93,38663.85,38707.38,0.52735 +2023-12-20 03:00:00,38693.53,38734.96,38686.15,38734.4,0.75551 +2023-12-20 03:15:00,38731.33,38733.0,38692.66,38695.05,0.57082 +2023-12-20 03:30:00,38684.38,38721.88,38665.05,38665.05,0.29847 +2023-12-20 03:45:00,38672.42,38696.95,38632.41,38672.35,0.95526 +2023-12-20 04:00:00,38692.67,38693.09,38649.3,38677.5,1.16382 +2023-12-20 04:15:00,38694.64,38899.35,38680.38,38855.15,5.08438 +2023-12-20 04:30:00,38852.27,38936.12,38847.16,38847.16,0.53617 +2023-12-20 04:45:00,38876.13,39118.63,38838.68,39057.6,11.37948 +2023-12-20 05:00:00,39056.99,39056.99,38896.24,38915.4,3.92165 +2023-12-20 05:15:00,38902.97,38922.48,38852.28,38862.29,1.2388 +2023-12-20 05:30:00,38872.25,38893.41,38838.22,38851.1,1.26556 +2023-12-20 05:45:00,38873.78,38972.33,38868.26,38954.04,1.08137 +2023-12-20 06:00:00,38934.16,38988.43,38886.59,38988.43,1.60691 +2023-12-20 06:15:00,38989.12,39242.4,38987.23,39169.19,6.41915 +2023-12-20 06:30:00,39203.79,39203.79,39042.4,39060.9,3.21857 +2023-12-20 06:45:00,39053.43,39167.0,39044.98,39112.95,3.14589 +2023-12-20 07:00:00,39122.7,39177.72,39075.4,39160.1,1.86279 +2023-12-20 07:15:00,39159.69,39159.69,39058.93,39058.93,2.27921 +2023-12-20 07:30:00,39063.08,39139.55,39042.96,39114.4,2.06091 +2023-12-20 07:45:00,39114.64,39177.66,39105.21,39140.7,2.1936 +2023-12-20 08:00:00,39168.53,39202.99,39038.51,39049.37,3.62284 +2023-12-20 08:15:00,39049.99,39119.07,39041.14,39070.75,1.31301 +2023-12-20 08:30:00,39081.76,39107.37,39044.51,39073.96,1.52795 +2023-12-20 08:45:00,39074.78,39084.47,39004.01,39031.16,1.35826 +2023-12-20 09:00:00,39039.17,39122.7,39039.17,39122.7,3.54293 +2023-12-20 09:15:00,39134.28,39207.89,39091.1,39207.88,2.69479 +2023-12-20 09:30:00,39206.17,39206.84,39086.58,39100.71,2.70111 +2023-12-20 09:45:00,39100.72,39104.76,38987.24,39041.9,4.79613 +2023-12-20 10:00:00,39047.66,39114.62,39004.52,39109.74,2.25758 +2023-12-20 10:15:00,39109.65,39125.38,38954.39,39044.48,3.53699 +2023-12-20 10:30:00,39044.48,39136.82,39044.48,39119.08,7.23509 +2023-12-20 10:45:00,39124.91,39151.3,39056.34,39151.3,4.81495 +2023-12-20 11:00:00,39160.83,39208.11,39095.48,39117.12,4.98683 +2023-12-20 11:15:00,39118.97,39179.28,39113.24,39118.91,1.34664 +2023-12-20 11:30:00,39134.74,39172.8,39091.29,39169.64,1.80823 +2023-12-20 11:45:00,39169.72,39302.52,39169.72,39200.65,4.04268 +2023-12-20 12:00:00,39207.97,39219.45,39083.4,39131.28,3.42722 +2023-12-20 12:15:00,39147.97,39255.3,39107.95,39255.3,1.66344 +2023-12-20 12:30:00,39270.59,39318.0,39227.1,39260.88,1.1194 +2023-12-20 12:45:00,39260.01,39317.99,39199.34,39304.36,1.96 +2023-12-20 13:00:00,39315.21,39494.61,39315.21,39450.04,9.45821 +2023-12-20 13:15:00,39441.15,39648.11,39397.18,39634.98,8.88867 +2023-12-20 13:30:00,39638.99,39666.99,39511.44,39666.99,4.4319 +2023-12-20 13:45:00,39666.98,39945.14,39654.11,39926.89,11.37345 +2023-12-20 14:00:00,39939.3,40069.99,39797.92,39804.91,10.24296 +2023-12-20 14:15:00,39806.08,40240.35,39777.94,40183.88,8.44582 +2023-12-20 14:30:00,40186.36,40267.62,40062.96,40079.43,3.18446 +2023-12-20 14:45:00,40083.32,40191.29,40000.0,40000.0,4.92552 +2023-12-20 15:00:00,40000.0,40367.26,39969.03,40362.06,6.37018 +2023-12-20 15:15:00,40367.27,40367.27,40191.1,40278.58,4.16011 +2023-12-20 15:30:00,40245.84,40346.9,40101.01,40120.23,3.56021 +2023-12-20 15:45:00,40120.98,40267.2,40081.4,40117.52,7.84367 +2023-12-20 16:00:00,40125.0,40196.02,40000.0,40008.8,6.92982 +2023-12-20 16:15:00,40014.03,40093.03,39995.14,40040.53,2.12691 +2023-12-20 16:30:00,40025.31,40102.72,40018.76,40074.74,2.42417 +2023-12-20 16:45:00,40050.17,40093.88,39690.28,39869.13,7.4376 +2023-12-20 17:00:00,39862.02,39952.44,39773.93,39802.59,4.88025 +2023-12-20 17:15:00,39798.51,40072.67,39774.36,40067.17,3.27605 +2023-12-20 17:30:00,40072.51,40100.0,40049.71,40092.8,2.03136 +2023-12-20 17:45:00,40086.36,40189.0,40045.24,40154.2,7.2544 +2023-12-20 18:00:00,40163.92,40260.56,40140.51,40226.38,2.57179 +2023-12-20 18:15:00,40217.67,40229.72,40101.93,40118.66,4.79125 +2023-12-20 18:30:00,40114.36,40304.07,40105.32,40285.95,3.81891 +2023-12-20 18:45:00,40274.43,40343.17,40270.36,40286.24,1.60671 +2023-12-20 19:00:00,40297.55,40391.74,40190.89,40217.22,5.33167 +2023-12-20 19:15:00,40205.61,40296.92,40200.2,40209.12,0.83638 +2023-12-20 19:30:00,40214.62,40252.8,39991.87,40069.0,6.09639 +2023-12-20 19:45:00,40065.08,40152.07,39961.46,39961.47,4.58116 +2023-12-20 20:00:00,39978.13,40012.61,39512.07,39819.03,10.55686 +2023-12-20 20:15:00,39800.0,39976.19,39800.0,39854.13,4.74645 +2023-12-20 20:30:00,39867.44,40033.17,39867.44,39999.08,2.88389 +2023-12-20 20:45:00,39989.27,40003.24,39707.6,39726.66,4.01677 +2023-12-20 21:00:00,39745.84,39956.01,39723.07,39909.35,2.62231 +2023-12-20 21:15:00,39908.1,39961.39,39834.47,39933.77,4.7965 +2023-12-20 21:30:00,39898.0,39902.83,39785.45,39785.88,2.23223 +2023-12-20 21:45:00,39793.99,39818.73,39621.86,39733.88,2.80945 +2023-12-20 22:00:00,39732.97,39799.81,39700.47,39784.3,1.33508 +2023-12-20 22:15:00,39802.0,39943.24,39802.0,39921.7,0.6309 +2023-12-20 22:30:00,39925.6,39981.0,39839.43,39852.01,1.80163 +2023-12-20 22:45:00,39862.92,39903.92,39788.35,39884.09,0.57819 +2023-12-20 23:00:00,39860.53,39862.46,39736.95,39780.27,1.70167 +2023-12-20 23:15:00,39765.12,39867.67,39737.57,39855.4,2.20285 +2023-12-20 23:30:00,39868.09,39907.77,39850.37,39904.05,0.94072 +2023-12-20 23:45:00,39901.12,39923.44,39879.22,39923.44,1.03746 +2023-12-21 00:00:00,39933.58,39934.44,39818.65,39818.65,1.47293 +2023-12-21 00:15:00,39828.66,39916.85,39796.45,39907.76,1.39205 +2023-12-21 00:30:00,39906.6,39972.31,39898.18,39911.96,1.26098 +2023-12-21 00:45:00,39924.24,39933.73,39822.34,39833.07,1.9982 +2023-12-21 01:00:00,39834.39,39855.74,39630.33,39678.71,2.01319 +2023-12-21 01:15:00,39669.59,39753.39,39623.07,39660.01,1.94038 +2023-12-21 01:30:00,39656.14,39707.59,39627.19,39656.75,0.52178 +2023-12-21 01:45:00,39619.35,39742.71,39619.35,39706.26,1.6978 +2023-12-21 02:00:00,39699.11,39706.89,39604.33,39668.6,1.59482 +2023-12-21 02:15:00,39679.49,39796.35,39679.49,39785.85,1.77756 +2023-12-21 02:30:00,39780.03,39811.71,39724.91,39749.01,0.87752 +2023-12-21 02:45:00,39732.78,39740.3,39565.56,39636.36,3.56636 +2023-12-21 03:00:00,39660.08,39784.37,39640.7,39784.37,1.69485 +2023-12-21 03:15:00,39794.6,39923.11,39794.6,39877.93,2.21149 +2023-12-21 03:30:00,39863.51,39895.56,39805.6,39805.6,1.48092 +2023-12-21 03:45:00,39808.86,39921.41,39802.0,39900.8,0.96388 +2023-12-21 04:00:00,39882.3,39907.77,39877.12,39877.24,0.54942 +2023-12-21 04:15:00,39901.01,39929.2,39873.15,39891.62,1.95915 +2023-12-21 04:30:00,39862.4,39935.47,39841.15,39845.63,1.85458 +2023-12-21 04:45:00,39851.23,39904.16,39844.13,39867.56,1.13355 +2023-12-21 05:00:00,39863.55,39893.42,39841.78,39863.47,2.01356 +2023-12-21 05:15:00,39860.45,39925.22,39857.29,39872.14,2.29486 +2023-12-21 05:30:00,39864.9,39878.1,39770.6,39797.84,1.74466 +2023-12-21 05:45:00,39795.92,39795.94,39705.9,39743.24,3.35509 +2023-12-21 06:00:00,39738.05,39797.52,39711.21,39762.81,1.79606 +2023-12-21 06:15:00,39760.18,39897.38,39760.18,39893.88,3.096 +2023-12-21 06:30:00,39893.88,39915.51,39862.61,39885.64,2.26629 +2023-12-21 06:45:00,39889.18,40051.0,39877.06,40034.28,1.12989 +2023-12-21 07:00:00,40038.69,40096.05,39964.67,40085.45,3.4111 +2023-12-21 07:15:00,40082.39,40085.85,40013.89,40020.74,6.21927 +2023-12-21 07:30:00,40016.74,40028.01,39961.47,39996.49,6.17566 +2023-12-21 07:45:00,39987.1,40031.62,39967.01,39994.02,2.2679 +2023-12-21 08:00:00,39991.65,40019.48,39962.01,40018.84,3.76829 +2023-12-21 08:15:00,40018.84,40142.29,40018.84,40133.45,4.05565 +2023-12-21 08:30:00,40137.38,40137.44,40056.81,40085.29,3.74595 +2023-12-21 08:45:00,40085.31,40093.36,39921.89,39931.18,6.60248 +2023-12-21 09:00:00,39957.52,40013.87,39903.94,40003.3,3.97104 +2023-12-21 09:15:00,39998.73,40004.82,39856.02,39901.88,7.10749 +2023-12-21 09:30:00,39889.47,39922.58,39859.96,39898.19,2.03923 +2023-12-21 09:45:00,39908.76,39995.53,39896.49,39995.53,1.74204 +2023-12-21 10:00:00,40002.19,40136.09,40002.19,40039.05,7.28567 +2023-12-21 10:15:00,40034.11,40098.39,40001.63,40067.22,2.1985 +2023-12-21 10:30:00,40066.4,40106.96,40034.77,40048.64,6.97588 +2023-12-21 10:45:00,40044.81,40228.74,40044.8,40193.37,16.09982 +2023-12-21 11:00:00,40178.47,40265.06,40120.61,40222.78,11.24761 +2023-12-21 11:15:00,40221.19,40227.81,40095.14,40122.01,6.44964 +2023-12-21 11:30:00,40120.44,40141.46,40007.86,40049.79,11.73287 +2023-12-21 11:45:00,40050.85,40069.45,39985.38,40037.96,4.60232 +2023-12-21 12:00:00,40063.72,40201.07,40049.52,40164.35,3.88128 +2023-12-21 12:15:00,40172.72,40289.99,40149.79,40182.27,4.27354 +2023-12-21 12:30:00,40199.21,40286.63,40149.81,40284.79,3.20882 +2023-12-21 12:45:00,40259.37,40277.53,40150.39,40161.84,15.215 +2023-12-21 13:00:00,40169.22,40169.22,40042.24,40142.06,2.68488 +2023-12-21 13:15:00,40166.14,40196.51,40073.92,40096.01,2.76568 +2023-12-21 13:30:00,40093.84,40176.38,40075.44,40174.17,4.62934 +2023-12-21 13:45:00,40190.32,40282.78,40168.85,40197.71,6.16858 +2023-12-21 14:00:00,40220.72,40245.8,39940.41,39971.2,8.26943 +2023-12-21 14:15:00,39973.07,40013.06,39813.25,39877.79,9.47101 +2023-12-21 14:30:00,39889.17,39923.67,39699.99,39727.35,13.1734 +2023-12-21 14:45:00,39741.62,39823.41,39574.56,39612.53,6.88792 +2023-12-21 15:00:00,39605.55,39779.43,39500.0,39746.36,13.19232 +2023-12-21 15:15:00,39748.38,40013.87,39731.64,39959.33,10.47401 +2023-12-21 15:30:00,39952.16,39959.16,39820.79,39896.93,7.83508 +2023-12-21 15:45:00,39896.92,39909.54,39780.82,39899.51,3.9158 +2023-12-21 16:00:00,39903.93,39994.68,39883.29,39894.29,4.15979 +2023-12-21 16:15:00,39909.07,39934.48,39780.08,39780.08,4.07738 +2023-12-21 16:30:00,39775.82,39803.52,39668.5,39702.63,3.72011 +2023-12-21 16:45:00,39723.88,39760.02,39632.66,39757.32,6.60418 +2023-12-21 17:00:00,39757.52,39761.12,39570.77,39585.59,7.98607 +2023-12-21 17:15:00,39611.82,39731.54,39563.61,39705.65,4.67496 +2023-12-21 17:30:00,39702.51,39762.21,39624.29,39637.06,5.94439 +2023-12-21 17:45:00,39630.37,39667.31,39513.01,39588.27,8.01345 +2023-12-21 18:00:00,39582.51,39707.57,39582.51,39667.42,5.80148 +2023-12-21 18:15:00,39674.06,39749.56,39659.79,39737.78,6.12223 +2023-12-21 18:30:00,39727.11,39728.94,39640.01,39668.68,2.23836 +2023-12-21 18:45:00,39673.59,39741.11,39605.22,39680.85,3.05182 +2023-12-21 19:00:00,39683.15,39953.39,39683.15,39729.81,33.53614 +2023-12-21 19:15:00,39720.95,39749.77,39558.21,39575.78,7.82032 +2023-12-21 19:30:00,39568.49,39630.81,39503.52,39566.71,9.98785 +2023-12-21 19:45:00,39566.72,39672.11,39533.12,39659.46,4.79123 +2023-12-21 20:00:00,39659.46,39725.0,39643.27,39724.91,4.05678 +2023-12-21 20:15:00,39725.0,39768.09,39674.63,39754.34,3.97746 +2023-12-21 20:30:00,39747.67,39793.13,39713.27,39764.77,3.18992 +2023-12-21 20:45:00,39773.57,39830.0,39761.36,39830.0,5.70788 +2023-12-21 21:00:00,39832.27,39832.27,39766.6,39804.0,1.77658 +2023-12-21 21:15:00,39797.16,39840.08,39768.85,39811.35,1.48088 +2023-12-21 21:30:00,39813.25,40041.55,39811.2,40000.25,9.01832 +2023-12-21 21:45:00,40013.77,40110.18,39967.75,39987.66,6.2391 +2023-12-21 22:00:00,39997.07,40025.2,39903.94,39991.1,7.76696 +2023-12-21 22:15:00,39984.27,40006.28,39953.61,39994.33,5.08257 +2023-12-21 22:30:00,39994.32,39994.32,39903.93,39983.07,3.5167 +2023-12-21 22:45:00,39989.8,40005.35,39930.02,39967.65,1.49227 +2023-12-21 23:00:00,39967.51,39974.0,39885.07,39930.94,2.38547 +2023-12-21 23:15:00,39924.67,39944.36,39886.11,39919.83,1.79555 +2023-12-21 23:30:00,39919.83,39926.85,39832.79,39851.87,2.55228 +2023-12-21 23:45:00,39839.58,39889.25,39814.14,39883.76,0.81907 +2023-12-22 00:00:00,39884.89,39892.85,39824.51,39825.01,3.21037 +2023-12-22 00:15:00,39826.68,39946.26,39789.68,39946.26,2.96767 +2023-12-22 00:30:00,39917.66,39959.75,39872.91,39872.91,1.46639 +2023-12-22 00:45:00,39877.81,39900.39,39842.56,39862.79,1.24464 +2023-12-22 01:00:00,39862.2,39973.83,39862.2,39950.37,1.97934 +2023-12-22 01:15:00,39956.14,40042.64,39922.65,40032.56,3.71373 +2023-12-22 01:30:00,40030.95,40214.52,40000.01,40150.45,6.01637 +2023-12-22 01:45:00,40160.95,40260.59,40083.89,40132.27,4.35153 +2023-12-22 02:00:00,40137.69,40169.04,40087.23,40106.2,2.03548 +2023-12-22 02:15:00,40117.04,40159.08,39954.73,39954.86,4.67855 +2023-12-22 02:30:00,39982.48,40103.74,39978.52,40048.63,1.96725 +2023-12-22 02:45:00,40051.2,40068.86,39991.76,39997.58,0.66608 +2023-12-22 03:00:00,40014.26,40061.97,39970.31,39970.31,0.94747 +2023-12-22 03:15:00,39956.99,40022.42,39953.09,39980.1,0.93748 +2023-12-22 03:30:00,39978.41,39987.2,39932.3,39960.02,2.78575 +2023-12-22 03:45:00,39966.42,40033.05,39966.42,40031.0,1.22819 +2023-12-22 04:00:00,40045.63,40048.47,39980.34,39988.28,0.97991 +2023-12-22 04:15:00,39991.45,40104.97,39964.44,40102.98,1.03615 +2023-12-22 04:30:00,40096.0,40111.95,40048.9,40085.11,0.99297 +2023-12-22 04:45:00,40090.9,40163.67,40078.14,40132.85,0.90812 +2023-12-22 05:00:00,40133.88,40176.12,40115.25,40169.08,0.66248 +2023-12-22 05:15:00,40169.08,40224.97,40136.39,40193.6,0.88117 +2023-12-22 05:30:00,40190.59,40228.88,40172.93,40210.4,1.64461 +2023-12-22 05:45:00,40207.18,40260.59,40126.59,40177.86,6.29685 +2023-12-22 06:00:00,40174.75,40195.61,40122.12,40159.11,1.25796 +2023-12-22 06:15:00,40150.43,40207.83,40076.96,40189.03,3.20608 +2023-12-22 06:30:00,40184.15,40409.97,40042.55,40052.32,12.96148 +2023-12-22 06:45:00,40042.35,40108.35,39892.16,39939.81,6.94387 +2023-12-22 07:00:00,39926.18,40002.26,39794.05,39985.29,4.26696 +2023-12-22 07:15:00,39985.68,39996.37,39837.15,39910.74,2.27438 +2023-12-22 07:30:00,39887.26,39913.58,39757.32,39795.82,4.04997 +2023-12-22 07:45:00,39795.55,39820.8,39606.78,39658.76,5.95791 +2023-12-22 08:00:00,39652.83,39793.96,39645.34,39766.49,6.23159 +2023-12-22 08:15:00,39755.94,39823.95,39701.11,39808.12,6.54249 +2023-12-22 08:30:00,39809.74,39837.35,39678.44,39695.29,5.23056 +2023-12-22 08:45:00,39679.9,39757.21,39650.72,39653.57,3.61943 +2023-12-22 09:00:00,39672.14,39731.37,39630.25,39640.93,9.15537 +2023-12-22 09:15:00,39634.6,39677.16,39507.7,39640.34,5.25588 +2023-12-22 09:30:00,39646.58,39740.67,39577.08,39740.66,5.21831 +2023-12-22 09:45:00,39740.02,39823.59,39712.15,39787.69,2.89567 +2023-12-22 10:00:00,39790.06,39794.72,39730.01,39757.42,4.27672 +2023-12-22 10:15:00,39756.42,39760.77,39680.5,39717.39,3.13783 +2023-12-22 10:30:00,39722.8,39734.37,39659.8,39729.99,4.63235 +2023-12-22 10:45:00,39729.99,39748.96,39690.89,39690.89,1.13414 +2023-12-22 11:00:00,39684.68,39684.68,39629.04,39660.27,4.91698 +2023-12-22 11:15:00,39660.12,39758.93,39660.12,39716.66,6.37977 +2023-12-22 11:30:00,39716.67,39778.0,39670.27,39771.32,3.82206 +2023-12-22 11:45:00,39762.68,39777.03,39707.61,39718.83,0.79459 +2023-12-22 12:00:00,39718.83,39751.57,39555.8,39555.8,7.80996 +2023-12-22 12:15:00,39564.16,39598.09,39508.91,39534.3,6.96686 +2023-12-22 12:30:00,39529.28,39619.12,39529.28,39616.58,1.26769 +2023-12-22 12:45:00,39613.21,39630.32,39524.83,39598.48,4.0824 +2023-12-22 13:00:00,39606.93,39645.1,39548.33,39633.21,1.15972 +2023-12-22 13:15:00,39632.44,39670.53,39579.67,39670.53,12.13879 +2023-12-22 13:30:00,39670.53,39808.78,39644.32,39760.44,5.92796 +2023-12-22 13:45:00,39765.13,39786.88,39679.86,39681.02,8.13014 +2023-12-22 14:00:00,39677.55,39712.68,39510.23,39513.39,5.39949 +2023-12-22 14:15:00,39523.69,39591.66,39430.01,39430.86,6.55232 +2023-12-22 14:30:00,39442.82,39561.83,39431.96,39516.64,2.86927 +2023-12-22 14:45:00,39520.56,39646.64,39493.55,39615.3,1.8332 +2023-12-22 15:00:00,39605.81,39631.33,39537.34,39619.81,3.55147 +2023-12-22 15:15:00,39623.05,39652.34,39557.6,39652.34,5.21255 +2023-12-22 15:30:00,39652.84,39673.67,39595.42,39672.41,1.53599 +2023-12-22 15:45:00,39677.39,39753.6,39658.16,39734.44,1.13442 +2023-12-22 16:00:00,39732.67,39752.7,39697.37,39697.37,1.19766 +2023-12-22 16:15:00,39692.96,39765.52,39692.96,39715.98,3.24105 +2023-12-22 16:30:00,39722.81,39744.36,39574.77,39595.83,2.69252 +2023-12-22 16:45:00,39595.84,39644.8,39555.74,39639.4,1.395 +2023-12-22 17:00:00,39635.39,39748.0,39635.39,39680.71,0.88958 +2023-12-22 17:15:00,39667.57,39721.68,39665.35,39700.82,1.18659 +2023-12-22 17:30:00,39700.82,39772.12,39652.49,39772.0,1.48621 +2023-12-22 17:45:00,39770.96,39785.67,39730.1,39738.0,1.59205 +2023-12-22 18:00:00,39744.2,39805.4,39714.55,39783.94,1.89954 +2023-12-22 18:15:00,39783.94,39949.98,39770.19,39897.15,4.98948 +2023-12-22 18:30:00,39889.23,39986.69,39874.28,39971.17,3.14368 +2023-12-22 18:45:00,39970.46,40019.71,39922.06,39992.08,8.15076 +2023-12-22 19:00:00,39977.51,39983.95,39866.87,39866.87,1.41559 +2023-12-22 19:15:00,39857.66,39857.66,39714.55,39779.39,2.13174 +2023-12-22 19:30:00,39784.19,39813.17,39763.03,39797.21,0.97927 +2023-12-22 19:45:00,39793.94,39793.94,39700.2,39711.81,1.90928 +2023-12-22 20:00:00,39710.01,39789.0,39690.22,39789.0,0.92975 +2023-12-22 20:15:00,39790.24,39812.12,39759.11,39773.29,1.05491 +2023-12-22 20:30:00,39761.37,39785.31,39715.2,39774.94,0.53545 +2023-12-22 20:45:00,39774.99,39818.63,39696.77,39711.92,2.87199 +2023-12-22 21:00:00,39743.25,39759.06,39721.48,39753.57,0.22665 +2023-12-22 21:15:00,39765.53,39781.27,39730.36,39776.0,0.3629 +2023-12-22 21:30:00,39776.0,39843.27,39772.78,39813.93,0.72119 +2023-12-22 21:45:00,39822.29,39835.05,39769.57,39769.57,0.21283 +2023-12-22 22:00:00,39786.45,39824.97,39741.47,39751.74,0.36319 +2023-12-22 22:15:00,39758.37,39779.78,39750.01,39779.17,0.45652 +2023-12-22 22:30:00,39780.0,39848.37,39780.0,39839.95,2.61772 +2023-12-22 22:45:00,39840.07,39861.91,39819.03,39861.91,0.32601 +2023-12-22 23:00:00,39860.64,40013.88,39860.64,39983.75,0.69022 +2023-12-22 23:15:00,39984.94,40085.0,39984.94,40019.3,1.20735 +2023-12-22 23:30:00,40016.76,40100.0,39991.25,40021.64,2.04267 +2023-12-22 23:45:00,40020.81,40054.8,40004.71,40023.67,0.53759 +2023-12-23 00:00:00,40032.99,40047.34,39964.16,40038.23,1.71741 +2023-12-23 00:15:00,40016.69,40020.05,39964.06,39992.41,0.80104 +2023-12-23 00:30:00,39987.76,40020.64,39890.27,39941.31,0.8836 +2023-12-23 00:45:00,39939.59,39974.66,39899.73,39903.95,0.51751 +2023-12-23 01:00:00,39929.2,39975.88,39915.43,39922.18,0.91937 +2023-12-23 01:15:00,39924.3,39940.02,39834.31,39847.23,1.23921 +2023-12-23 01:30:00,39838.89,39874.32,39827.96,39846.45,1.36567 +2023-12-23 01:45:00,39846.45,39888.46,39730.34,39735.42,1.49674 +2023-12-23 02:00:00,39736.36,39774.53,39680.0,39725.53,4.49999 +2023-12-23 02:15:00,39722.52,39756.43,39676.27,39683.54,0.3778 +2023-12-23 02:30:00,39687.79,39728.04,39635.1,39644.64,0.27425 +2023-12-23 02:45:00,39648.68,39688.96,39584.47,39593.78,1.81409 +2023-12-23 03:00:00,39617.28,39704.75,39573.03,39704.75,0.50276 +2023-12-23 03:15:00,39698.38,39701.1,39660.5,39691.1,0.28703 +2023-12-23 03:30:00,39680.16,39693.9,39653.44,39656.66,1.04571 +2023-12-23 03:45:00,39668.15,39702.19,39582.41,39646.62,3.97735 +2023-12-23 04:00:00,39625.74,39625.74,39375.18,39512.47,7.88034 +2023-12-23 04:15:00,39494.07,39564.21,39460.9,39564.21,2.57312 +2023-12-23 04:30:00,39565.19,39572.38,39528.61,39568.31,0.11785 +2023-12-23 04:45:00,39569.56,39622.49,39569.56,39622.37,1.0774 +2023-12-23 05:00:00,39616.71,39627.08,39595.48,39624.72,0.48414 +2023-12-23 05:15:00,39628.92,39683.25,39628.92,39656.38,1.86864 +2023-12-23 05:30:00,39657.69,39687.1,39647.16,39675.81,0.18379 +2023-12-23 05:45:00,39672.54,39716.8,39655.79,39716.8,0.38358 +2023-12-23 06:00:00,39714.86,39715.57,39643.78,39657.65,0.32641 +2023-12-23 06:15:00,39655.99,39707.17,39642.67,39697.1,0.21695 +2023-12-23 06:30:00,39692.83,39729.41,39689.38,39716.08,0.37405 +2023-12-23 06:45:00,39705.7,39746.68,39705.7,39729.99,0.35901 +2023-12-23 07:00:00,39735.55,39758.59,39716.25,39726.23,0.74625 +2023-12-23 07:15:00,39722.08,39722.08,39667.43,39708.51,0.84144 +2023-12-23 07:30:00,39701.01,39701.01,39669.96,39679.18,0.39195 +2023-12-23 07:45:00,39677.91,39705.21,39662.13,39674.03,0.93197 +2023-12-23 08:00:00,39674.03,39731.89,39671.63,39720.47,0.32623 +2023-12-23 08:15:00,39711.02,39738.46,39677.11,39677.11,0.42946 +2023-12-23 08:30:00,39684.02,39700.21,39671.06,39680.33,0.34407 +2023-12-23 08:45:00,39684.3,39725.52,39681.73,39721.97,0.31851 +2023-12-23 09:00:00,39727.11,39752.12,39694.08,39752.12,0.19677 +2023-12-23 09:15:00,39751.38,39770.75,39741.89,39744.57,1.82459 +2023-12-23 09:30:00,39745.71,39745.71,39646.63,39709.46,1.62125 +2023-12-23 09:45:00,39701.16,39760.18,39694.08,39739.66,0.65243 +2023-12-23 10:00:00,39741.7,39751.27,39698.05,39729.99,0.8212 +2023-12-23 10:15:00,39729.99,39753.86,39705.04,39730.54,0.39664 +2023-12-23 10:30:00,39723.13,39723.13,39670.26,39712.55,0.49228 +2023-12-23 10:45:00,39700.63,39719.47,39677.69,39693.11,0.37349 +2023-12-23 11:00:00,39692.85,39696.52,39646.65,39658.5,0.56864 +2023-12-23 11:15:00,39652.28,39658.5,39611.4,39649.7,1.68176 +2023-12-23 11:30:00,39649.13,39690.88,39609.69,39690.88,1.36986 +2023-12-23 11:45:00,39690.35,39727.73,39646.21,39661.51,0.56517 +2023-12-23 12:00:00,39657.97,39781.37,39654.27,39717.28,2.44108 +2023-12-23 12:15:00,39722.5,39768.72,39722.5,39753.51,0.43824 +2023-12-23 12:30:00,39761.47,39817.49,39758.88,39778.22,1.26889 +2023-12-23 12:45:00,39782.03,39860.72,39782.03,39819.49,0.67611 +2023-12-23 13:00:00,39831.86,39875.9,39829.05,39852.04,0.55492 +2023-12-23 13:15:00,39842.52,39868.58,39809.46,39822.35,0.37498 +2023-12-23 13:30:00,39817.08,39825.16,39800.01,39819.47,1.70227 +2023-12-23 13:45:00,39819.47,39874.51,39800.77,39874.51,1.50449 +2023-12-23 14:00:00,39872.91,39900.0,39834.19,39900.0,0.51753 +2023-12-23 14:15:00,39900.0,39912.46,39861.29,39868.01,1.27546 +2023-12-23 14:30:00,39868.02,39892.81,39837.77,39882.46,0.54575 +2023-12-23 14:45:00,39871.54,39942.12,39856.86,39931.51,0.98278 +2023-12-23 15:00:00,39941.7,39964.45,39892.95,39904.65,0.94216 +2023-12-23 15:15:00,39903.84,39963.59,39887.91,39887.91,3.64735 +2023-12-23 15:30:00,39887.91,39902.11,39860.3,39884.86,3.76831 +2023-12-23 15:45:00,39885.35,39964.91,39884.21,39950.49,11.65551 +2023-12-23 16:00:00,39943.95,39971.0,39904.55,39954.08,7.65095 +2023-12-23 16:15:00,39954.08,39993.0,39930.09,39966.89,7.48126 +2023-12-23 16:30:00,39956.42,39999.18,39896.9,39913.33,17.05408 +2023-12-23 16:45:00,39914.03,39962.82,39898.66,39915.46,3.27094 +2023-12-23 17:00:00,39917.17,39950.0,39900.01,39950.0,0.77306 +2023-12-23 17:15:00,39950.0,39964.96,39897.01,39900.66,0.5516 +2023-12-23 17:30:00,39907.68,39917.22,39872.6,39878.41,1.48425 +2023-12-23 17:45:00,39888.89,39898.93,39855.11,39877.21,0.32254 +2023-12-23 18:00:00,39870.74,39877.29,39833.1,39850.92,0.68709 +2023-12-23 18:15:00,39862.02,39899.74,39852.43,39892.37,0.3093 +2023-12-23 18:30:00,39907.86,39949.14,39863.66,39884.33,1.13602 +2023-12-23 18:45:00,39899.78,39982.11,39899.78,39925.16,1.22426 +2023-12-23 19:00:00,39931.5,39962.62,39882.98,39882.99,1.54439 +2023-12-23 19:15:00,39882.98,39918.02,39840.14,39911.75,3.7447 +2023-12-23 19:30:00,39911.77,39914.02,39847.94,39856.08,0.52559 +2023-12-23 19:45:00,39865.36,39873.88,39829.84,39848.14,0.5202 +2023-12-23 20:00:00,39852.9,39882.02,39845.85,39856.36,0.77939 +2023-12-23 20:15:00,39843.6,39871.85,39802.44,39830.3,2.58033 +2023-12-23 20:30:00,39831.67,39873.96,39798.46,39816.71,3.62933 +2023-12-23 20:45:00,39812.9,39891.09,39800.67,39859.57,1.83183 +2023-12-23 21:00:00,39880.78,39890.16,39816.41,39865.65,2.2839 +2023-12-23 21:15:00,39865.44,39956.49,39855.84,39908.61,4.08635 +2023-12-23 21:30:00,39912.64,39971.96,39909.64,39960.8,2.37911 +2023-12-23 21:45:00,39960.8,39970.79,39912.43,39914.29,1.62856 +2023-12-23 22:00:00,39920.81,39931.61,39870.1,39894.8,2.37255 +2023-12-23 22:15:00,39888.05,40009.96,39880.55,39960.31,3.88506 +2023-12-23 22:30:00,39960.31,39987.17,39937.0,39963.3,2.63681 +2023-12-23 22:45:00,39963.3,40016.91,39959.68,39998.59,1.73051 +2023-12-23 23:00:00,39983.22,40028.05,39934.48,40015.88,1.67745 +2023-12-23 23:15:00,40015.4,40030.09,39950.15,39977.28,1.73659 +2023-12-23 23:30:00,39986.36,40010.95,39956.08,39971.48,0.81651 +2023-12-23 23:45:00,39971.49,40003.77,39923.02,39944.37,0.61249 +2023-12-24 00:00:00,39944.35,39951.33,39872.12,39880.73,1.48011 +2023-12-24 00:15:00,39880.73,39961.47,39845.23,39947.12,2.1011 +2023-12-24 00:30:00,39956.41,39963.78,39856.21,39902.69,0.89645 +2023-12-24 00:45:00,39916.61,39942.06,39880.1,39935.12,0.59504 +2023-12-24 01:00:00,39938.25,40091.7,39913.22,40047.78,1.34427 +2023-12-24 01:15:00,40063.88,40134.3,40044.0,40045.26,1.56497 +2023-12-24 01:30:00,40042.77,40092.85,39961.23,39974.6,1.81142 +2023-12-24 01:45:00,39997.43,40028.21,39963.27,40022.35,0.378 +2023-12-24 02:00:00,40024.05,40106.78,40023.14,40087.97,0.54346 +2023-12-24 02:15:00,40083.1,40133.91,40079.67,40086.12,0.4941 +2023-12-24 02:30:00,40088.76,40106.72,40039.08,40044.82,0.33462 +2023-12-24 02:45:00,40047.96,40091.34,40003.65,40091.34,0.78233 +2023-12-24 03:00:00,40091.33,40099.69,40058.01,40062.09,0.38127 +2023-12-24 03:15:00,40058.71,40087.53,40047.6,40074.12,0.47947 +2023-12-24 03:30:00,40079.98,40079.99,40047.25,40056.08,0.60597 +2023-12-24 03:45:00,40057.86,40114.94,40055.44,40070.49,1.12539 +2023-12-24 04:00:00,40075.0,40167.3,40062.09,40130.79,0.84957 +2023-12-24 04:15:00,40122.87,40164.56,40055.45,40055.45,0.51821 +2023-12-24 04:30:00,40060.8,40076.31,40019.38,40019.38,1.54764 +2023-12-24 04:45:00,40015.4,40026.31,39991.29,40023.01,0.84803 +2023-12-24 05:00:00,40019.77,40032.0,39957.46,39960.23,0.42885 +2023-12-24 05:15:00,39960.65,39987.32,39912.52,39912.52,0.42943 +2023-12-24 05:30:00,39907.95,39924.27,39665.98,39756.6,2.11122 +2023-12-24 05:45:00,39751.69,39786.95,39702.65,39726.52,1.40342 +2023-12-24 06:00:00,39735.68,39794.81,39674.91,39730.59,1.02575 +2023-12-24 06:15:00,39716.72,39793.99,39711.66,39752.95,0.98035 +2023-12-24 06:30:00,39758.05,39821.39,39730.76,39810.65,1.44619 +2023-12-24 06:45:00,39827.95,39827.95,39756.63,39813.1,0.84395 +2023-12-24 07:00:00,39816.38,39873.1,39778.13,39873.1,0.75265 +2023-12-24 07:15:00,39880.98,39915.31,39869.44,39902.47,0.49517 +2023-12-24 07:30:00,39894.66,39894.66,39812.8,39871.61,1.39585 +2023-12-24 07:45:00,39868.44,39957.07,39868.44,39957.0,0.46719 +2023-12-24 08:00:00,39960.09,39969.87,39811.83,39833.69,1.25379 +2023-12-24 08:15:00,39833.39,39914.41,39798.23,39906.94,1.81923 +2023-12-24 08:30:00,39911.51,39967.66,39897.27,39941.57,2.58447 +2023-12-24 08:45:00,39943.82,39951.21,39873.42,39904.03,1.10155 +2023-12-24 09:00:00,39893.28,39934.66,39877.62,39933.8,0.59291 +2023-12-24 09:15:00,39933.8,39939.63,39857.51,39915.94,1.14067 +2023-12-24 09:30:00,39915.86,39971.93,39891.46,39966.29,1.20747 +2023-12-24 09:45:00,39962.49,39981.91,39941.28,39974.15,1.29923 +2023-12-24 10:00:00,39974.16,39988.04,39878.67,39885.82,1.77433 +2023-12-24 10:15:00,39878.93,39918.17,39800.01,39829.95,2.65669 +2023-12-24 10:30:00,39830.54,39830.54,39693.37,39764.93,3.65871 +2023-12-24 10:45:00,39783.39,39868.88,39770.26,39861.98,2.20485 +2023-12-24 11:00:00,39858.45,39904.46,39837.19,39841.34,1.49884 +2023-12-24 11:15:00,39846.07,39907.67,39811.48,39900.62,1.7505 +2023-12-24 11:30:00,39898.87,39900.34,39844.29,39867.13,0.83038 +2023-12-24 11:45:00,39859.16,39915.57,39837.14,39906.78,1.53216 +2023-12-24 12:00:00,39906.78,39934.84,39863.83,39894.66,1.54918 +2023-12-24 12:15:00,39894.82,39895.51,39837.14,39842.2,1.18088 +2023-12-24 12:30:00,39847.22,39923.42,39837.13,39914.87,0.7795 +2023-12-24 12:45:00,39918.97,39932.84,39893.98,39913.21,0.74522 +2023-12-24 13:00:00,39915.01,39954.96,39900.0,39941.44,0.95025 +2023-12-24 13:15:00,39947.85,40000.0,39930.74,39977.89,1.47168 +2023-12-24 13:30:00,39984.89,39990.26,39953.83,39957.89,0.94842 +2023-12-24 13:45:00,39953.84,40047.32,39947.56,40032.94,1.08508 +2023-12-24 14:00:00,40042.66,40137.04,40027.67,40133.86,2.07928 +2023-12-24 14:15:00,40133.16,40144.65,40060.59,40110.53,1.55799 +2023-12-24 14:30:00,40110.59,40144.66,40093.48,40102.61,1.45878 +2023-12-24 14:45:00,40102.62,40104.13,39997.47,40045.8,1.88995 +2023-12-24 15:00:00,40042.08,40118.08,39998.46,40082.79,1.92114 +2023-12-24 15:15:00,40077.91,40093.95,40013.89,40021.45,0.90168 +2023-12-24 15:30:00,40029.05,40040.16,39942.01,40035.2,2.02482 +2023-12-24 15:45:00,40035.2,40035.2,39946.65,39950.62,1.27102 +2023-12-24 16:00:00,39950.39,39955.0,39831.83,39884.23,3.78164 +2023-12-24 16:15:00,39870.05,39963.89,39846.1,39941.35,1.55937 +2023-12-24 16:30:00,39923.82,39986.66,39911.62,39953.19,1.30618 +2023-12-24 16:45:00,39960.64,40016.35,39960.64,39976.52,0.47816 +2023-12-24 17:00:00,39979.84,40023.06,39958.56,39999.58,0.9773 +2023-12-24 17:15:00,39994.87,40010.32,39925.9,39954.21,1.11164 +2023-12-24 17:30:00,39959.37,39975.32,39911.79,39919.39,0.75133 +2023-12-24 17:45:00,39928.02,39961.77,39912.4,39930.95,1.37112 +2023-12-24 18:00:00,39942.21,39962.88,39891.28,39929.56,0.39955 +2023-12-24 18:15:00,39933.12,39974.21,39924.23,39935.21,0.30363 +2023-12-24 18:30:00,39935.33,39935.33,39880.16,39910.66,0.55481 +2023-12-24 18:45:00,39907.63,39958.82,39854.02,39940.1,1.09628 +2023-12-24 19:00:00,39945.17,39960.45,39920.03,39957.48,0.367 +2023-12-24 19:15:00,39957.5,39966.22,39931.19,39939.66,0.4054 +2023-12-24 19:30:00,39958.22,39958.22,39854.0,39889.23,0.60278 +2023-12-24 19:45:00,39888.97,39924.54,39878.5,39913.73,0.41998 +2023-12-24 20:00:00,39922.22,39923.93,39870.99,39875.2,0.26134 +2023-12-24 20:15:00,39871.03,39889.11,39840.14,39847.11,0.31066 +2023-12-24 20:30:00,39847.11,39862.21,39760.0,39771.17,0.74711 +2023-12-24 20:45:00,39781.97,39829.32,39745.27,39809.38,0.56619 +2023-12-24 21:00:00,39798.97,39862.22,39767.4,39813.97,1.49937 +2023-12-24 21:15:00,39774.91,39857.8,39744.7,39744.7,0.31483 +2023-12-24 21:30:00,39762.17,39826.21,39703.16,39759.8,1.29088 +2023-12-24 21:45:00,39759.91,39813.77,39726.9,39783.85,1.38803 +2023-12-24 22:00:00,39794.13,39853.1,39250.0,39432.64,6.8475 +2023-12-24 22:15:00,39430.47,39601.51,39000.0,39514.31,12.30994 +2023-12-24 22:30:00,39514.31,39556.29,39035.41,39321.61,13.37947 +2023-12-24 22:45:00,39321.61,39450.63,39214.51,39450.63,4.75264 +2023-12-24 23:00:00,39355.12,39464.16,39296.61,39446.85,8.03087 +2023-12-24 23:15:00,39431.73,39499.3,39399.85,39464.24,2.32564 +2023-12-24 23:30:00,39463.53,39532.4,39410.13,39532.39,0.62889 +2023-12-24 23:45:00,39539.72,39557.32,39357.88,39404.3,1.08645 +2023-12-25 00:00:00,39394.84,39497.32,39347.81,39417.88,1.70173 From 2581ae014ba07c0401590b827d0add198ab6e2bc Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 2 Jul 2024 10:32:11 +0200 Subject: [PATCH 25/31] Refactor data sourcing --- examples/bitvavo_trading_bot/bitvavo.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/bitvavo_trading_bot/bitvavo.py b/examples/bitvavo_trading_bot/bitvavo.py index 3d7ebffd..46bd11a2 100644 --- a/examples/bitvavo_trading_bot/bitvavo.py +++ b/examples/bitvavo_trading_bot/bitvavo.py @@ -5,15 +5,15 @@ create_app, PortfolioConfiguration, Algorithm, SYMBOLS, RESOURCE_DIRECTORY """ -Bitvavo trading bot example with market data sources of bitvavo. +Bitvavo trading bot example with market data sources of bitvavo. Bitvavo does not requires you to have an API key and secret key to access -their market data - -If you just want to backtest your strategy, you don't need to -add a market credential. If your running your strategy live, +their market data. If you just want to backtest your strategy, +you don't need to add a market credential. If your running your strategy live, you need to add a market credential to the app, that accesses your account on bitvavo. """ + + # Define your market credential for bitvavo bitvavo_market_credential = MarketCredential( api_key="", @@ -72,4 +72,3 @@ def apply_strategy(self, algorithm, market_data): if __name__ == "__main__": app.run() - From 3bad0195c32239dfbd3b10a562b816bceca907b3 Mon Sep 17 00:00:00 2001 From: marcvanduyn Date: Tue, 2 Jul 2024 10:32:25 +0200 Subject: [PATCH 26/31] Refactor data sources --- examples/coinbase_trading_bot/coinbase.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/coinbase_trading_bot/coinbase.py b/examples/coinbase_trading_bot/coinbase.py index 8a922122..2c2b1331 100644 --- a/examples/coinbase_trading_bot/coinbase.py +++ b/examples/coinbase_trading_bot/coinbase.py @@ -9,8 +9,9 @@ and secret key to access their market data. You can create them here: https://www.coinbase.com/settings/api -You need to add a market credential to the app, and then add market data sources -to the app. You can then use the market data sources in your trading strategy. +You need to add a market credential to the app, and then add market +data sources to the app. You can then use the market data +sources in your trading strategy. """ # Define your market credential for coinbase coinbase_market_credential = MarketCredential( @@ -41,14 +42,13 @@ class CoinBaseTradingStrategy(TradingStrategy): def apply_strategy(self, algorithm, market_data): pass + config = { SYMBOLS: ["BTC/EUR"], RESOURCE_DIRECTORY: os.path.join(os.path.dirname(__file__), "resources") } - algorithm = Algorithm() algorithm.add_strategy(CoinBaseTradingStrategy) - app = create_app(config=config) app.add_algorithm(algorithm) app.add_market_credential(coinbase_market_credential) @@ -62,4 +62,3 @@ def apply_strategy(self, algorithm, market_data): if __name__ == "__main__": app.run() - From 6a4bbeb227a2ab21182524d9136478f86214dcaa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:46:37 +0200 Subject: [PATCH 27/31] --- (#259) updated-dependencies: - dependency-name: requests dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marc van Duyn --- poetry.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index b98d24cc..7397b478 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiodns" @@ -2264,8 +2264,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" From 6aaa9d9300039000ea6b0cf3c470d48798119f11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:53:30 +0200 Subject: [PATCH 28/31] Bump flask-cors from 3.0.10 to 4.0.1 (#260) Bumps [flask-cors](https://github.com/corydolphin/flask-cors) from 3.0.10 to 4.0.1. - [Release notes](https://github.com/corydolphin/flask-cors/releases) - [Changelog](https://github.com/corydolphin/flask-cors/blob/main/CHANGELOG.md) - [Commits](https://github.com/corydolphin/flask-cors/compare/3.0.10...4.0.1) --- updated-dependencies: - dependency-name: flask-cors dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marc van Duyn --- poetry.lock | 11 ++++++----- pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7397b478..3a6e43d1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -977,18 +977,17 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-cors" -version = "3.0.10" +version = "4.0.1" description = "A Flask extension adding a decorator for CORS support" optional = false python-versions = "*" files = [ - {file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"}, - {file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"}, + {file = "Flask_Cors-4.0.1-py2.py3-none-any.whl", hash = "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677"}, + {file = "flask_cors-4.0.1.tar.gz", hash = "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4"}, ] [package.dependencies] Flask = ">=0.9" -Six = "*" [[package]] name = "flask-migrate" @@ -2773,6 +2772,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -3781,4 +3781,5 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "40dbc94cbd9f3248ef1caf81aab5813fbfe894f0e22c2b160829233890121618" +content-hash = "d24f74b78fea7929fe0af280cd826679405c9a62f5b9d3d29a15887e55044e4c" + diff --git a/pyproject.toml b/pyproject.toml index 0b153ec1..6d0b72df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ python = "^3.8.1" wrapt = "^1.16.0" Flask = "^2.3.2" Flask-Migrate = "^2.6.0" -Flask-Cors = "^3.0.9" +Flask-Cors = ">=3.0.9,<5.0.0" SQLAlchemy = "^2.0.18" marshmallow = "^3.5.0" ccxt = "^4.2.48" From aa2976ed10d6e1aefbe4fc53206cc4bb355b4b53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:02:57 +0200 Subject: [PATCH 29/31] Bump jinja2 from 3.1.3 to 3.1.4 (#258) Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/3.1.3...3.1.4) --- updated-dependencies: - dependency-name: jinja2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From d4927f7707e9e767038ea7537c9f3f63a1821785 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:04:06 +0200 Subject: [PATCH 30/31] Bump werkzeug from 3.0.1 to 3.0.3 (#257) Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.1 to 3.0.3. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/3.0.1...3.0.3) --- updated-dependencies: - dependency-name: werkzeug dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 4b6b5fa02c11fbec4cc9bba80f572b889b8a89bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:18:57 +0200 Subject: [PATCH 31/31] Bump tqdm from 4.66.2 to 4.66.3 (#256) Bumps [tqdm](https://github.com/tqdm/tqdm) from 4.66.2 to 4.66.3. - [Release notes](https://github.com/tqdm/tqdm/releases) - [Commits](https://github.com/tqdm/tqdm/compare/v4.66.2...v4.66.3) --- updated-dependencies: - dependency-name: tqdm dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marc van Duyn --- poetry.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3a6e43d1..20a7314b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3781,5 +3781,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "d24f74b78fea7929fe0af280cd826679405c9a62f5b9d3d29a15887e55044e4c" - +content-hash = "40dbc94cbd9f3248ef1caf81aab5813fbfe894f0e22c2b160829233890121618"