diff --git a/lib/pt_strategy/trading_strategy.py b/lib/pt_strategy/trading_strategy.py
index 8dcf0b3..3d851be 100644
--- a/lib/pt_strategy/trading_strategy.py
+++ b/lib/pt_strategy/trading_strategy.py
@@ -309,96 +309,3 @@ class PtResearchStrategy:
def day_trades(self) -> pd.DataFrame:
return pd.concat(self.trades_, ignore_index=True)
-
-
-def main() -> None:
- import argparse
-
- from tools.config import expand_filename, load_config
-
- parser = argparse.ArgumentParser(description="Run pairs trading backtest.")
- parser.add_argument(
- "--config", type=str, required=True, help="Path to the configuration file."
- )
- parser.add_argument(
- "--date_pattern",
- type=str,
- required=True,
- help="Date YYYYMMDD, allows * and ? wildcards",
- )
- parser.add_argument(
- "--instruments",
- type=str,
- required=True,
- help="Comma-separated list of instrument symbols (e.g., COIN:EQUITY,GBTC:CRYPTO)",
- )
- parser.add_argument(
- "--result_db",
- type=str,
- required=True,
- help="Path to SQLite database for storing results. Use 'NONE' to disable database output.",
- )
-
- args = parser.parse_args()
-
- config: Dict = load_config(args.config)
-
- # Resolve data files (CLI takes priority over config)
- instruments = get_instruments(args, config)
- datafiles = resolve_datafiles(config, args.date_pattern, instruments)
-
- days = list(set([day for day, _ in datafiles]))
- print(f"Found {len(datafiles)} data files to process:")
- for df in datafiles:
- print(f" - {df}")
-
- # Create result database if needed
- if args.result_db.upper() != "NONE":
- args.result_db = expand_filename(args.result_db)
- create_result_database(args.result_db)
-
- # Initialize a dictionary to store all trade results
- all_results: Dict[str, Dict[str, Any]] = {}
- is_config_stored = False
- # Process each data file
-
- results = PairResearchResult(config=config)
- for day in sorted(days):
- md_datafiles = [datafile for md_day, datafile in datafiles if md_day == day]
- if not all([os.path.exists(datafile) for datafile in md_datafiles]):
- print(f"WARNING: insufficient data files: {md_datafiles}")
- continue
- print(f"\n====== Processing {day} ======")
-
- if not is_config_stored:
- store_config_in_database(
- db_path=args.result_db,
- config_file_path=args.config,
- config=config,
- datafiles=datafiles,
- instruments=instruments,
- )
- is_config_stored = True
-
- pt_strategy = PtResearchStrategy(
- config=config, datafiles=md_datafiles, instruments=instruments
- )
- pt_strategy.run()
- results.add_day_results(
- day=day,
- trades=pt_strategy.day_trades(),
- outstanding_positions=pt_strategy.outstanding_positions(),
- )
-
-
- results.analyze_pair_performance()
-
-
- if args.result_db.upper() != "NONE":
- print(f"\nResults stored in database: {args.result_db}")
- else:
- print("No results to display.")
-
-
-if __name__ == "__main__":
- main()
diff --git a/research/backtest_new.py b/research/backtest_new.py
new file mode 100644
index 0000000..daad2fb
--- /dev/null
+++ b/research/backtest_new.py
@@ -0,0 +1,106 @@
+from __future__ import annotations
+
+import os
+from typing import Any, Dict
+
+from pt_strategy.results import (
+ PairResearchResult,
+ create_result_database,
+ store_config_in_database,
+)
+from pt_strategy.trading_strategy import PtResearchStrategy
+from tools.filetools import resolve_datafiles
+from tools.instruments import get_instruments
+
+
+def main() -> None:
+ import argparse
+
+ from tools.config import expand_filename, load_config
+
+ parser = argparse.ArgumentParser(description="Run pairs trading backtest.")
+ parser.add_argument(
+ "--config", type=str, required=True, help="Path to the configuration file."
+ )
+ parser.add_argument(
+ "--date_pattern",
+ type=str,
+ required=True,
+ help="Date YYYYMMDD, allows * and ? wildcards",
+ )
+ parser.add_argument(
+ "--instruments",
+ type=str,
+ required=True,
+ help="Comma-separated list of instrument symbols (e.g., COIN:EQUITY,GBTC:CRYPTO)",
+ )
+ parser.add_argument(
+ "--result_db",
+ type=str,
+ required=True,
+ help="Path to SQLite database for storing results. Use 'NONE' to disable database output.",
+ )
+
+ args = parser.parse_args()
+
+ config: Dict = load_config(args.config)
+
+ # Resolve data files (CLI takes priority over config)
+ instruments = get_instruments(args, config)
+ datafiles = resolve_datafiles(config, args.date_pattern, instruments)
+
+ days = list(set([day for day, _ in datafiles]))
+ print(f"Found {len(datafiles)} data files to process:")
+ for df in datafiles:
+ print(f" - {df}")
+
+ # Create result database if needed
+ if args.result_db.upper() != "NONE":
+ args.result_db = expand_filename(args.result_db)
+ create_result_database(args.result_db)
+
+ # Initialize a dictionary to store all trade results
+ all_results: Dict[str, Dict[str, Any]] = {}
+ is_config_stored = False
+ # Process each data file
+
+ results = PairResearchResult(config=config)
+ for day in sorted(days):
+ md_datafiles = [datafile for md_day, datafile in datafiles if md_day == day]
+ if not all([os.path.exists(datafile) for datafile in md_datafiles]):
+ print(f"WARNING: insufficient data files: {md_datafiles}")
+ continue
+ print(f"\n====== Processing {day} ======")
+
+ if not is_config_stored:
+ store_config_in_database(
+ db_path=args.result_db,
+ config_file_path=args.config,
+ config=config,
+ datafiles=datafiles,
+ instruments=instruments,
+ )
+ is_config_stored = True
+
+ pt_strategy = PtResearchStrategy(
+ config=config, datafiles=md_datafiles, instruments=instruments
+ )
+ pt_strategy.run()
+ results.add_day_results(
+ day=day,
+ trades=pt_strategy.day_trades(),
+ outstanding_positions=pt_strategy.outstanding_positions(),
+ )
+
+
+ results.analyze_pair_performance()
+
+
+ if args.result_db.upper() != "NONE":
+ print(f"\nResults stored in database: {args.result_db}")
+ else:
+ print("No results to display.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/research/notebooks/pair_trading_test_NEW.ipynb b/research/notebooks/pair_trading_test_NEW.ipynb
new file mode 100644
index 0000000..2a44221
--- /dev/null
+++ b/research/notebooks/pair_trading_test_NEW.ipynb
@@ -0,0 +1,1125 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "vscode": {
+ "languageId": "raw"
+ }
+ },
+ "source": [
+ "\n",
+ "# Settings"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Trading Parameters Configuration\n",
+ "# Specify your configuration file, trading symbols and date here\n",
+ "\n",
+ "# Configuration file selection\n",
+ "global CONFIG_FILE\n",
+ "global SYMBOL_A\n",
+ "global SYMBOL_B\n",
+ "global TRADING_DATE\n",
+ "global TRD_DATE\n",
+ "global PT_BT_CONFIG\n",
+ "global DATA_FILE\n",
+ "global FIT_METHOD_TYPE\n",
+ "global pair\n",
+ "global pair_trades\n",
+ "global bt_result\n",
+ "global INSTRUMENTS\n",
+ "\n",
+ "import os\n",
+ "\n",
+ "ROOT_DIR = \"/home/oleg/develop/pairs_trading\"\n",
+ "os.chdir(ROOT_DIR)\n",
+ "\n",
+ "CONFIG_FILE = f\"{ROOT_DIR}/configuration/new_zscore.cfg\"\n",
+ "\n",
+ "# Date for data file selection (format: YYYYMMDD)\n",
+ "TRADING_DATE = \"20250605\" # Change this to your desired date\n",
+ "\n",
+ "# ================================ E Q U I T Y ================================\n",
+ "# INSTRUMENTS = {\n",
+ "# \"A\": {\n",
+ "# \"symbol\": \"COIN\",\n",
+ "# \"exchange_id\": \"ALPACA\",\n",
+ "# \"instrument_type\": \"EQUITY\",\n",
+ "# \"instrument_id_pfx\": \"STOCK-\",\n",
+ "# },\n",
+ "# \"B\": {\n",
+ "# \"symbol\": \"MSTR\",\n",
+ "# \"exchange_id\": \"ALPACA\",\n",
+ "# \"instrument_type\": \"EQUITY\",\n",
+ "# \"instrument_id_pfx\": \"STOCK-\",\n",
+ "# },\n",
+ "# }\n",
+ "# ================================ E Q U I T Y ================================\n",
+ "\n",
+ "# ================================ C R Y P T O ================================\n",
+ "INSTRUMENTS = {\n",
+ " \"A\": {\n",
+ " \"symbol\": \"ADA-USDT\",\n",
+ " \"exchange_id\": \"BNBSPOT\",\n",
+ " \"instrument_type\": \"CRYPTO\",\n",
+ " \"instrument_id_pfx\": \"PAIR-\",\n",
+ " },\n",
+ " \"B\": {\n",
+ " \"symbol\": \"SOL-USDT\",\n",
+ " \"exchange_id\": \"BNBSPOT\",\n",
+ " \"instrument_type\": \"CRYPTO\",\n",
+ " \"instrument_id_pfx\": \"PAIR-\",\n",
+ " },\n",
+ "}\n",
+ "# ================================ C R Y P T O ================================\n",
+ "\n",
+ "# ================================ E Q U I T Y VS. C R Y P T O ================================\n",
+ "# INSTRUMENTS = {\n",
+ "# \"A\": {\n",
+ "# \"symbol\": \"MSTR\",\n",
+ "# \"exchange_id\": \"ALPACA\",\n",
+ "# \"instrument_type\": \"EQUITY\",\n",
+ "# \"instrument_id_pfx\": \"STOCK-\",\n",
+ "# },\n",
+ "# \"B\": {\n",
+ "# \"symbol\": \"ETH-USDT\",\n",
+ "# \"exchange_id\": \"BNBSPOT\",\n",
+ "# \"instrument_type\": \"CRYPTO\",\n",
+ "# \"instrument_id_pfx\": \"PAIR-\",\n",
+ "# },\n",
+ "# }\n",
+ "# ================================ E Q U I T Y VS. C R Y P T O ================================\n",
+ "\n",
+ "SYMBOL_A = INSTRUMENTS[\"A\"][\"symbol\"]\n",
+ "SYMBOL_B = INSTRUMENTS[\"B\"][\"symbol\"]\n",
+ "TRD_DATE = f\"{TRADING_DATE[0:4]}-{TRADING_DATE[4:6]}-{TRADING_DATE[6:8]}\"\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Setup and Configuration"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Code Setup"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def setup() -> None:\n",
+ " import sys\n",
+ " import os\n",
+ " sys.path.append('/home/oleg/develop/pairs_trading/lib')\n",
+ " sys.path.append('/home/coder/pairs_trading/lib')\n",
+ " \n",
+ "\n",
+ " import pandas as pd\n",
+ " import numpy as np\n",
+ " import importlib\n",
+ " from typing import Dict, List, Optional\n",
+ " from IPython.display import clear_output\n",
+ "\n",
+ " # Import our modules\n",
+ " from pt_strategy.trading_pair import TradingPair, PairState\n",
+ " from pt_strategy.results import PairResearchResult\n",
+ "\n",
+ " pd.set_option('display.width', 400)\n",
+ " pd.set_option('display.max_colwidth', None)\n",
+ " pd.set_option('display.max_columns', None)\n",
+ "\n",
+ " print(\"Setup complete!\")\n",
+ " os.chdir(os.path.abspath(os.path.join(os.getcwd(), \"..\", \"..\")))\n",
+ " print(f\"Current working directory: {os.getcwd()}\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "vscode": {
+ "languageId": "raw"
+ }
+ },
+ "source": [
+ "## Load Configuration\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Load Configuration from Configuration Files using HJSON\n",
+ "from typing import Dict, Optional\n",
+ "import hjson\n",
+ "import os\n",
+ "import importlib\n",
+ "\n",
+ "def load_config_from_file() -> Optional[Dict]:\n",
+ " global DB_TABLE_NAME\n",
+ " global PT_BT_CONFIG\n",
+ " \"\"\"Load configuration from configuration files using HJSON\"\"\"\n",
+ " config_file = CONFIG_FILE\n",
+ " config = None\n",
+ " \n",
+ " try:\n",
+ " with open(config_file, 'r') as f:\n",
+ " # HJSON handles comments, trailing commas, and other human-friendly features\n",
+ " config = hjson.load(f)\n",
+ " \n",
+ " # Convert relative paths to absolute paths from notebook perspective\n",
+ " if 'data_directory' in config:\n",
+ " data_dir = config['data_directory']\n",
+ " if data_dir.startswith('./'):\n",
+ " # Convert relative path to absolute path from notebook's perspective\n",
+ " config['data_directory'] = os.path.abspath(f\"../../{data_dir[2:]}\")\n",
+ " \n",
+ " \n",
+ " except FileNotFoundError:\n",
+ " print(f\"Configuration file not found: {config_file}\")\n",
+ " except hjson.HjsonDecodeError as e:\n",
+ " print(f\"HJSON parsing error in {config_file}: {e}\")\n",
+ " except Exception as e:\n",
+ " print(f\"Unexpected error loading config from {config_file}: {e}\")\n",
+ " \n",
+ " assert config is not None\n",
+ " PT_BT_CONFIG = dict(config)\n",
+ " DB_TABLE_NAME = PT_BT_CONFIG[\"market_data_loading\"][INSTRUMENTS[\"A\"][\"instrument_type\"]][\"db_table_name\"]\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Print Configuration"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "def prepare_config() -> None:\n",
+ " global PT_BT_CONFIG\n",
+ " global CONFIG_FILE\n",
+ " global SYMBOL_A\n",
+ " global SYMBOL_B\n",
+ " global TRD_DATE\n",
+ " global DATA_FILES\n",
+ " global FIT_MODEL\n",
+ "\n",
+ " print(f\"Trading Parameters:\")\n",
+ " print(f\" Configuration: {CONFIG_FILE}\")\n",
+ " print(f\" Symbol A: {SYMBOL_A}\")\n",
+ " print(f\" Symbol B: {SYMBOL_B}\")\n",
+ " print(f\" Trading Date: {TRD_DATE}\")\n",
+ "\n",
+ " # Load the specified configuration\n",
+ " print(f\"\\nLoading {CONFIG_FILE} configuration using HJSON...\")\n",
+ "\n",
+ " load_config_from_file()\n",
+ "\n",
+ " if PT_BT_CONFIG:\n",
+ " print(f\"✓ Successfully loaded configuration\")\n",
+ " # print(f\" Data directory: {PT_BT_CONFIG['data_directory']}\")\n",
+ " # print(f\" Database table: {PT_BT_CONFIG['db_table_name']}\")\n",
+ " # print(f\" Exchange: {PT_BT_CONFIG['exchange_id']}\")\n",
+ " print(f\" Training window: {PT_BT_CONFIG['training_size']} minutes\")\n",
+ " print(f\" Open threshold: {PT_BT_CONFIG['dis-equilibrium_open_trshld']}\")\n",
+ " print(f\" Close threshold: {PT_BT_CONFIG['dis-equilibrium_close_trshld']}\")\n",
+ " \n",
+ " # Instantiate strategy from config\n",
+ " # FIT_MODEL = instantiate_fit_method_from_config(PT_BT_CONFIG)\n",
+ " # print(f\" Fit Method: {type(FIT_MODEL).__name__}\")\n",
+ " \n",
+ " # Automatically construct data file name based on date and config type\n",
+ " DATA_FILE = f\"{TRADING_DATE}.mktdata.ohlcv.db\"\n",
+ " data_directory_a = PT_BT_CONFIG[\"market_data_loading\"][INSTRUMENTS[\"A\"][\"instrument_type\"]][\"data_directory\"]\n",
+ " data_directory_b = PT_BT_CONFIG[\"market_data_loading\"][INSTRUMENTS[\"B\"][\"instrument_type\"]][\"data_directory\"]\n",
+ " DATA_FILE_A = f\"{data_directory_a}/{TRADING_DATE}.mktdata.ohlcv.db\"\n",
+ " DATA_FILE_B = f\"{data_directory_b}/{TRADING_DATE}.mktdata.ohlcv.db\"\n",
+ "\n",
+ " PT_BT_CONFIG[\"datafiles\"] = list(set([DATA_FILE_A, DATA_FILE_B]))\n",
+ " \n",
+ " print(f\"\\nData Configuration:\")\n",
+ " print(f\" Data File: {DATA_FILE}\")\n",
+ " \n",
+ " # Verify data file exists\n",
+ " os.chdir(ROOT_DIR)\n",
+ " for data_file_path in PT_BT_CONFIG[\"datafiles\"]:\n",
+ " if os.path.exists(data_file_path):\n",
+ " print(f\" ✓ Data file found: {data_file_path}\")\n",
+ " else:\n",
+ " raise FileNotFoundError(\n",
+ " f\" ⚠ Data file not found: {data_file_path}\\n\"\n",
+ " f\" Please check if the date and file exist in the data directory\"\n",
+ " )\n",
+ " \n",
+ " else:\n",
+ " print(\"⚠ Failed to load configuration. Please check the configuration file.\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "vscode": {
+ "languageId": "raw"
+ }
+ },
+ "source": [
+ "## Run Strategy"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "def run_strategy() -> None: # Load market data\n",
+ " global PT_BT_CONFIG\n",
+ " global INSTRUMENTS\n",
+ " global DATA_FILE\n",
+ " global SYMBOL_A\n",
+ " global SYMBOL_B\n",
+ " global pair\n",
+ " global DB_TABLE_NAME\n",
+ " global PT_RESEARCH_STRATEGY\n",
+ " global PT_RESULTS\n",
+ "\n",
+ " import pandas as pd\n",
+ " from tools.data_loader import load_market_data\n",
+ " from pt_strategy.trading_pair import TradingPair\n",
+ " from pt_strategy.trading_strategy import PtResearchStrategy\n",
+ " from pt_strategy.results import PairResearchResult\n",
+ " from research.research_tools import create_pairs\n",
+ "\n",
+ " # Create trading pair\n",
+ " PT_RESULTS = PairResearchResult(config=PT_BT_CONFIG)\n",
+ " PT_RESEARCH_STRATEGY = PtResearchStrategy(\n",
+ " config=PT_BT_CONFIG, datafiles=PT_BT_CONFIG[\"datafiles\"], instruments=list(INSTRUMENTS.values())\n",
+ " )\n",
+ "\n",
+ " PT_RESEARCH_STRATEGY.run()\n",
+ " PT_RESULTS.add_day_results(\n",
+ " day=TRADING_DATE,\n",
+ " trades=PT_RESEARCH_STRATEGY.day_trades(),\n",
+ " outstanding_positions=PT_RESEARCH_STRATEGY.outstanding_positions(),\n",
+ " )\n",
+ "\n",
+ "\n",
+ " pair = PT_RESEARCH_STRATEGY.trading_pair_\n",
+ " \n",
+ " print(f\"\\nCreated trading pair: {pair}\")\n",
+ " print(f\"Market data shape: {pair.market_data_.shape}\")\n",
+ " print(f\"Column names: {pair.colnames()}\")\n",
+ "\n",
+ " # Display sample data\n",
+ " print(f\"\\nSample data:\")\n",
+ " # with pd.option_context('display.max_rows', None, 'display.max_columns', None):\n",
+ " # print(pair.market_data_)\n",
+ " display(pair.market_data_.head())\n",
+ "\n",
+ " display(pair.market_data_.tail())\n",
+ "\n",
+ "# setup()\n",
+ "# prepare_config()\n",
+ "# run_strategy()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "vscode": {
+ "languageId": "raw"
+ }
+ },
+ "source": [
+ "## Visualize Raw Price Data\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def visualize_prices() -> None:\n",
+ " # Plot raw price data\n",
+ " global price_data\n",
+ " \n",
+ " import matplotlib.pyplot as plt\n",
+ " # Set plotting style\n",
+ " import seaborn as sns\n",
+ "\n",
+ " plt.style.use('seaborn-v0_8')\n",
+ " sns.set_palette(\"husl\")\n",
+ " plt.rcParams['figure.figsize'] = (15, 10)\n",
+ "\n",
+ " # Get column names for the trading pair\n",
+ " colname_a, colname_b = pair.colnames()\n",
+ " price_data = pair.market_data_.copy()\n",
+ "\n",
+ " # # 1. Price data - separate plots for each symbol\n",
+ " # colname_a, colname_b = pair.colnames()\n",
+ " # price_data = pair.market_data_.copy()\n",
+ "\n",
+ " # Create separate subplots for better visibility\n",
+ " fig_price, price_axes = plt.subplots(2, 1, figsize=(18, 10))\n",
+ "\n",
+ " # Plot SYMBOL_A\n",
+ " price_axes[0].plot(price_data['tstamp'], price_data[colname_a], alpha=0.7, \n",
+ " label=f'{SYMBOL_A}', linewidth=1, color='blue')\n",
+ " price_axes[0].set_title(f'{SYMBOL_A} Price Data ({TRD_DATE})')\n",
+ " price_axes[0].set_ylabel(f'{SYMBOL_A} Price')\n",
+ " price_axes[0].legend()\n",
+ " price_axes[0].grid(True)\n",
+ "\n",
+ " # Plot SYMBOL_B\n",
+ " price_axes[1].plot(price_data['tstamp'], price_data[colname_b], alpha=0.7, \n",
+ " label=f'{SYMBOL_B}', linewidth=1, color='red')\n",
+ " price_axes[1].set_title(f'{SYMBOL_B} Price Data ({TRD_DATE})')\n",
+ " price_axes[1].set_ylabel(f'{SYMBOL_B} Price')\n",
+ " price_axes[1].set_xlabel('Time')\n",
+ " price_axes[1].legend()\n",
+ " price_axes[1].grid(True)\n",
+ "\n",
+ " plt.tight_layout()\n",
+ " plt.show()\n",
+ " \n",
+ "\n",
+ " # Plot individual prices\n",
+ " fig, axes = plt.subplots(2, 1, figsize=(18, 12))\n",
+ "\n",
+ " # Normalized prices for comparison\n",
+ " norm_a = price_data[colname_a] / price_data[colname_a].iloc[0]\n",
+ " norm_b = price_data[colname_b] / price_data[colname_b].iloc[0]\n",
+ "\n",
+ " axes[0].plot(price_data['tstamp'], norm_a, label=f'{SYMBOL_A} (normalized)', alpha=0.8, linewidth=1)\n",
+ " axes[0].plot(price_data['tstamp'], norm_b, label=f'{SYMBOL_B} (normalized)', alpha=0.8, linewidth=1)\n",
+ " axes[0].set_title(f'Normalized Price Comparison (Base = 1.0) ({TRD_DATE})')\n",
+ " axes[0].set_ylabel('Normalized Price')\n",
+ " axes[0].legend()\n",
+ " axes[0].grid(True)\n",
+ "\n",
+ " # Price ratio\n",
+ " price_ratio = price_data[colname_a] / price_data[colname_b]\n",
+ " axes[1].plot(price_data['tstamp'], price_ratio, label=f'{SYMBOL_A}/{SYMBOL_B} Ratio', color='green', alpha=0.8, linewidth=1)\n",
+ " axes[1].set_title(f'Price Ratio Px({SYMBOL_A})/Px({SYMBOL_B}) ({TRD_DATE})')\n",
+ " axes[1].set_ylabel('Ratio')\n",
+ " axes[1].set_xlabel('Time')\n",
+ " axes[1].legend()\n",
+ " axes[1].grid(True)\n",
+ "\n",
+ " plt.tight_layout()\n",
+ " plt.show()\n",
+ "\n",
+ " # Print basic statistics\n",
+ " print(f\"\\nPrice Statistics:\")\n",
+ " print(f\" {SYMBOL_A}: Mean=${price_data[colname_a].mean():.2f}, Std=${price_data[colname_a].std():.2f}\")\n",
+ " print(f\" {SYMBOL_B}: Mean=${price_data[colname_b].mean():.2f}, Std=${price_data[colname_b].std():.2f}\")\n",
+ " print(f\" Price Ratio: Mean={price_ratio.mean():.2f}, Std={price_ratio.std():.2f}\")\n",
+ " print(f\" Correlation: {price_data[colname_a].corr(price_data[colname_b]):.4f}\")\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Visualization"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def visualize_trades() -> None:\n",
+ " # global price_data\n",
+ " # global pair_trades\n",
+ " global PT_BT_CONFIG\n",
+ " global SYMBOL_A\n",
+ " global SYMBOL_B\n",
+ " global TRD_DATE\n",
+ " global PREDICTED_RESULT\n",
+ " global PT_RESEARCH_STRATEGY\n",
+ " global PT_RESULTS\n",
+ "\n",
+ " import plotly.graph_objects as go\n",
+ " from plotly.subplots import make_subplots\n",
+ " import plotly.express as px\n",
+ " import plotly.offline as pyo\n",
+ " from IPython.display import HTML\n",
+ " import pandas as pd\n",
+ "\n",
+ "\n",
+ " pair = PT_RESEARCH_STRATEGY.trading_pair_\n",
+ " pair_trades = PT_RESULTS.trades_[TRADING_DATE]\n",
+ " outstanding_positions = PT_RESULTS.outstanding_positions_[TRADING_DATE]\n",
+ "\n",
+ " print(f\"\\nCreated trading pair: {pair}\")\n",
+ " print(f\"Market data shape: {pair.market_data_.shape}\")\n",
+ " print(f\"Column names: {pair.colnames()}\")\n",
+ "\n",
+ " # Configure plotly for offline mode\n",
+ " pyo.init_notebook_mode(connected=True)\n",
+ "\n",
+ " # Strategy-specific interactive visualization\n",
+ " assert PT_BT_CONFIG is not None\n",
+ "\n",
+ " print(\"=== SLIDING FIT INTERACTIVE VISUALIZATION ===\")\n",
+ " print(\"Note: Rolling Fit strategy visualization with interactive plotly charts\")\n",
+ "\n",
+ " # Create consistent timeline - superset of timestamps from both dataframes\n",
+ " market_timestamps = set(pair.market_data_['tstamp'])\n",
+ " predicted_timestamps = set(PREDICTED_RESULT['tstamp'])\n",
+ "\n",
+ " # Create superset of all timestamps\n",
+ " all_timestamps = sorted(market_timestamps.union(predicted_timestamps))\n",
+ "\n",
+ " # Create a unified timeline dataframe for consistent plotting\n",
+ " timeline_df = pd.DataFrame({'tstamp': all_timestamps})\n",
+ "\n",
+ " # Merge with predicted data to get dis-equilibrium values\n",
+ " timeline_df = timeline_df.merge(PREDICTED_RESULT[['tstamp', 'disequilibrium', 'scaled_disequilibrium', 'signed_scaled_disequilibrium']], \n",
+ " on='tstamp', how='left')\n",
+ "\n",
+ " # Get Symbol_A and Symbol_B market data\n",
+ " colname_a, colname_b = pair.colnames()\n",
+ " symbol_a_data = pair.original_market_data_[['tstamp', colname_a]].copy()\n",
+ " symbol_b_data = pair.original_market_data_[['tstamp', colname_b]].copy()\n",
+ "\n",
+ " norm_a = price_data[colname_a] / price_data[colname_a].iloc[0]\n",
+ " norm_b = price_data[colname_b] / price_data[colname_b].iloc[0]\n",
+ "\n",
+ " print(f\"Using consistent timeline with {len(timeline_df)} timestamps\")\n",
+ " print(f\"Timeline range: {timeline_df['tstamp'].min()} to {timeline_df['tstamp'].max()}\")\n",
+ "\n",
+ " # Create subplots with price charts at bottom\n",
+ " fig = make_subplots(\n",
+ " rows=4, cols=1,\n",
+ " row_heights=[0.3, 0.4, 0.15, 0.15],\n",
+ " subplot_titles=[\n",
+ " f'Dis-equilibrium with Trading Thresholds ({TRD_DATE})',\n",
+ " f'Normalized Price Comparison with BUY/SELL Signals - {SYMBOL_A}&{SYMBOL_B} ({TRD_DATE})',\n",
+ " f'{SYMBOL_A} Market Data with Trading Signals ({TRD_DATE})',\n",
+ " f'{SYMBOL_B} Market Data with Trading Signals ({TRD_DATE})',\n",
+ " ],\n",
+ " vertical_spacing=0.06,\n",
+ " specs=[[{\"secondary_y\": False}],\n",
+ " [{\"secondary_y\": False}],\n",
+ " [{\"secondary_y\": False}],\n",
+ " [{\"secondary_y\": False}]]\n",
+ " )\n",
+ "\n",
+ " # 1. Scaled dis-equilibrium with thresholds - using consistent timeline\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=timeline_df['tstamp'],\n",
+ " y=timeline_df['scaled_disequilibrium'],\n",
+ " name='Absolute Scaled Dis-equilibrium',\n",
+ " line=dict(color='green', width=2),\n",
+ " opacity=0.8\n",
+ " ),\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=timeline_df['tstamp'],\n",
+ " y=timeline_df['signed_scaled_disequilibrium'],\n",
+ " name='Scaled Dis-equilibrium',\n",
+ " line=dict(color='darkmagenta', width=2),\n",
+ " opacity=0.8\n",
+ " ),\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " # Add threshold lines to first subplot\n",
+ " fig.add_shape(\n",
+ " type=\"line\",\n",
+ " x0=timeline_df['tstamp'].min(),\n",
+ " x1=timeline_df['tstamp'].max(),\n",
+ " y0=PT_BT_CONFIG['dis-equilibrium_open_trshld'],\n",
+ " y1=PT_BT_CONFIG['dis-equilibrium_open_trshld'],\n",
+ " line=dict(color=\"purple\", width=2, dash=\"dot\"),\n",
+ " opacity=0.7,\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " fig.add_shape(\n",
+ " type=\"line\",\n",
+ " x0=timeline_df['tstamp'].min(),\n",
+ " x1=timeline_df['tstamp'].max(),\n",
+ " y0=-PT_BT_CONFIG['dis-equilibrium_open_trshld'],\n",
+ " y1=-PT_BT_CONFIG['dis-equilibrium_open_trshld'],\n",
+ " line=dict(color=\"purple\", width=2, dash=\"dot\"),\n",
+ " opacity=0.7,\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " fig.add_shape(\n",
+ " type=\"line\",\n",
+ " x0=timeline_df['tstamp'].min(),\n",
+ " x1=timeline_df['tstamp'].max(),\n",
+ " y0=PT_BT_CONFIG['dis-equilibrium_close_trshld'],\n",
+ " y1=PT_BT_CONFIG['dis-equilibrium_close_trshld'],\n",
+ " line=dict(color=\"brown\", width=2, dash=\"dot\"),\n",
+ " opacity=0.7,\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " fig.add_shape(\n",
+ " type=\"line\",\n",
+ " x0=timeline_df['tstamp'].min(),\n",
+ " x1=timeline_df['tstamp'].max(),\n",
+ " y0=-PT_BT_CONFIG['dis-equilibrium_close_trshld'],\n",
+ " y1=-PT_BT_CONFIG['dis-equilibrium_close_trshld'],\n",
+ " line=dict(color=\"brown\", width=2, dash=\"dot\"),\n",
+ " opacity=0.7,\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " fig.add_shape(\n",
+ " type=\"line\",\n",
+ " x0=timeline_df['tstamp'].min(),\n",
+ " x1=timeline_df['tstamp'].max(),\n",
+ " y0=0,\n",
+ " y1=0,\n",
+ " line=dict(color=\"black\", width=1, dash=\"solid\"),\n",
+ " opacity=0.5,\n",
+ " row=1, col=1\n",
+ " )\n",
+ "\n",
+ " # Add normalized price lines\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=price_data['tstamp'],\n",
+ " y=norm_a,\n",
+ " name=f'{SYMBOL_A} (Normalized)',\n",
+ " line=dict(color='blue', width=2),\n",
+ " opacity=0.8\n",
+ " ),\n",
+ " row=2, col=1\n",
+ " )\n",
+ "\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=price_data['tstamp'],\n",
+ " y=norm_b,\n",
+ " name=f'{SYMBOL_B} (Normalized)',\n",
+ " line=dict(color='orange', width=2),\n",
+ " opacity=0.8,\n",
+ " ),\n",
+ " row=2, col=1\n",
+ " )\n",
+ "\n",
+ " # Add BUY and SELL signals if available\n",
+ " if pair_trades is not None and len(pair_trades) > 0:\n",
+ " # Define signal groups to avoid legend repetition\n",
+ " signal_groups = {}\n",
+ " \n",
+ " # Process all trades and group by signal type (ignore OPEN/CLOSE status)\n",
+ " for _, trade in pair_trades.iterrows():\n",
+ " symbol = trade['symbol']\n",
+ " side = trade['side']\n",
+ " # status = trade['status']\n",
+ " action = trade['action']\n",
+ " \n",
+ " # Create signal group key (without status to combine OPEN/CLOSE)\n",
+ " signal_key = f\"{symbol} {side} {action}\"\n",
+ " \n",
+ " # Find normalized price for this trade\n",
+ " trade_time = trade['time']\n",
+ " if symbol == SYMBOL_A:\n",
+ " closest_idx = price_data['tstamp'].searchsorted(trade_time)\n",
+ " if closest_idx < len(norm_a):\n",
+ " norm_price = norm_a.iloc[closest_idx]\n",
+ " else:\n",
+ " norm_price = norm_a.iloc[-1]\n",
+ " else: # SYMBOL_B\n",
+ " closest_idx = price_data['tstamp'].searchsorted(trade_time)\n",
+ " if closest_idx < len(norm_b):\n",
+ " norm_price = norm_b.iloc[closest_idx]\n",
+ " else:\n",
+ " norm_price = norm_b.iloc[-1]\n",
+ " \n",
+ " # Initialize group if not exists\n",
+ " if signal_key not in signal_groups:\n",
+ " signal_groups[signal_key] = {\n",
+ " 'times': [],\n",
+ " 'prices': [],\n",
+ " 'actual_prices': [],\n",
+ " 'symbol': symbol,\n",
+ " 'side': side,\n",
+ " # 'status': status,\n",
+ " 'action': trade['action']\n",
+ " }\n",
+ " \n",
+ " # Add to group\n",
+ " signal_groups[signal_key]['times'].append(trade_time)\n",
+ " signal_groups[signal_key]['prices'].append(norm_price)\n",
+ " signal_groups[signal_key]['actual_prices'].append(trade['price'])\n",
+ " \n",
+ " # Add each signal group as a single trace\n",
+ " for signal_key, group_data in signal_groups.items():\n",
+ " symbol = group_data['symbol']\n",
+ " side = group_data['side']\n",
+ " # status = group_data['status']\n",
+ " \n",
+ " # Determine marker properties (same for all OPEN/CLOSE of same side)\n",
+ " is_close: bool = (group_data['action'] == \"CLOSE\")\n",
+ " \n",
+ " if 'BUY' in side:\n",
+ " marker_color = 'green'\n",
+ " marker_symbol = 'triangle-up'\n",
+ " marker_size = 14\n",
+ " else: # SELL\n",
+ " marker_color = 'red'\n",
+ " marker_symbol = 'triangle-down'\n",
+ " marker_size = 14\n",
+ " \n",
+ " # Create hover text for each point in the group\n",
+ " hover_texts = []\n",
+ " for i, (time, norm_price, actual_price) in enumerate(zip(group_data['times'], \n",
+ " group_data['prices'], \n",
+ " group_data['actual_prices'])):\n",
+ " # Find the corresponding trade to get the status for hover text\n",
+ " trade_info = pair_trades[(pair_trades['time'] == time) & \n",
+ " (pair_trades['symbol'] == symbol) & \n",
+ " (pair_trades['side'] == side)]\n",
+ " if len(trade_info) > 0:\n",
+ " action = trade_info.iloc[0]['action']\n",
+ " hover_texts.append(f'{signal_key} {action}
' +\n",
+ " f'Time: {time}
' +\n",
+ " f'Normalized Price: {norm_price:.4f}
' +\n",
+ " f'Actual Price: ${actual_price:.2f}')\n",
+ " else:\n",
+ " hover_texts.append(f'{signal_key}
' +\n",
+ " f'Time: {time}
' +\n",
+ " f'Normalized Price: {norm_price:.4f}
' +\n",
+ " f'Actual Price: ${actual_price:.2f}')\n",
+ " \n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=group_data['times'],\n",
+ " y=group_data['prices'],\n",
+ " mode='markers',\n",
+ " name=signal_key,\n",
+ " marker=dict(\n",
+ " color=marker_color,\n",
+ " size=marker_size,\n",
+ " symbol=marker_symbol,\n",
+ " line=dict(width=2, color='black') if is_close else None\n",
+ " ),\n",
+ " showlegend=True,\n",
+ " hovertemplate='%{text}',\n",
+ " text=hover_texts\n",
+ " ),\n",
+ " row=2, col=1\n",
+ " )\n",
+ "\n",
+ " # ----------------------------- \n",
+ " \n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=symbol_a_data['tstamp'],\n",
+ " y=symbol_a_data[colname_a],\n",
+ " name=f'{SYMBOL_A} Price',\n",
+ " line=dict(color='blue', width=2),\n",
+ " opacity=0.8\n",
+ " ),\n",
+ " row=3, col=1\n",
+ " )\n",
+ "\n",
+ " # Filter trades for Symbol_A\n",
+ " symbol_a_trades = pair_trades[pair_trades['symbol'] == SYMBOL_A]\n",
+ " print(f\"\\nSymbol_A trades:\\n{symbol_a_trades}\")\n",
+ " \n",
+ " if len(symbol_a_trades) > 0:\n",
+ " # Separate trades by action and status for different colors\n",
+ " buy_open_trades = symbol_a_trades[(symbol_a_trades['side'].str.contains('BUY', na=False)) & \n",
+ " (symbol_a_trades['action'].str.contains('OPEN', na=False))]\n",
+ " buy_close_trades = symbol_a_trades[(symbol_a_trades['side'].str.contains('BUY', na=False)) & \n",
+ " (symbol_a_trades['action'].str.contains('CLOSE', na=False))]\n",
+ " \n",
+ " sell_open_trades = symbol_a_trades[(symbol_a_trades['side'].str.contains('SELL', na=False)) & \n",
+ " (symbol_a_trades['action'].str.contains('OPEN', na=False))]\n",
+ " sell_close_trades = symbol_a_trades[(symbol_a_trades['side'].str.contains('SELL', na=False)) & \n",
+ " (symbol_a_trades['action'].str.contains('CLOSE', na=False))]\n",
+ " \n",
+ " # Add BUY OPEN signals\n",
+ " if len(buy_open_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=buy_open_trades['time'],\n",
+ " y=buy_open_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_A} BUY OPEN',\n",
+ " marker=dict(color='green', size=12, symbol='triangle-up'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=3, col=1\n",
+ " )\n",
+ " \n",
+ " # Add BUY CLOSE signals\n",
+ " if len(buy_close_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=buy_close_trades['time'],\n",
+ " y=buy_close_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_A} BUY CLOSE',\n",
+ " marker=dict(color='green', size=12, symbol='triangle-up'),\n",
+ " line=dict(width=2, color='black'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=3, col=1\n",
+ " )\n",
+ " \n",
+ " # Add SELL OPEN signals\n",
+ " if len(sell_open_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=sell_open_trades['time'],\n",
+ " y=sell_open_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_A} SELL OPEN',\n",
+ " marker=dict(color='red', size=12, symbol='triangle-down'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=3, col=1\n",
+ " )\n",
+ " \n",
+ " # Add SELL CLOSE signals\n",
+ " if len(sell_close_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=sell_close_trades['time'],\n",
+ " y=sell_close_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_A} SELL CLOSE',\n",
+ " marker=dict(color='red', size=12, symbol='triangle-down'),\n",
+ " line=dict(width=2, color='black'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=3, col=1\n",
+ " )\n",
+ " \n",
+ " # 4. Symbol_B Market Data with Trading Signals\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=symbol_b_data['tstamp'],\n",
+ " y=symbol_b_data[colname_b],\n",
+ " name=f'{SYMBOL_B} Price',\n",
+ " line=dict(color='orange', width=2),\n",
+ " opacity=0.8\n",
+ " ),\n",
+ " row=4, col=1\n",
+ " )\n",
+ " \n",
+ " # Add trading signals for Symbol_B if available\n",
+ " symbol_b_trades = pair_trades[pair_trades['symbol'] == SYMBOL_B]\n",
+ " print(f\"\\nSymbol_B trades:\\n{symbol_b_trades}\")\n",
+ " \n",
+ " if len(symbol_b_trades) > 0:\n",
+ " # Separate trades by action and status for different colors\n",
+ " buy_open_trades = symbol_b_trades[(symbol_b_trades['side'].str.contains('BUY', na=False)) & \n",
+ " (symbol_b_trades['action'].str.startswith('OPEN', na=False))]\n",
+ " buy_close_trades = symbol_b_trades[(symbol_b_trades['side'].str.contains('BUY', na=False)) & \n",
+ " (symbol_b_trades['action'].str.startswith('CLOSE', na=False))]\n",
+ " \n",
+ " sell_open_trades = symbol_b_trades[(symbol_b_trades['side'].str.contains('SELL', na=False)) & \n",
+ " (symbol_b_trades['action'].str.contains('OPEN', na=False))]\n",
+ " sell_close_trades = symbol_b_trades[(symbol_b_trades['side'].str.contains('SELL', na=False)) & \n",
+ " (symbol_b_trades['action'].str.contains('CLOSE', na=False))]\n",
+ " \n",
+ " # Add BUY OPEN signals\n",
+ " if len(buy_open_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=buy_open_trades['time'],\n",
+ " y=buy_open_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_B} BUY OPEN',\n",
+ " marker=dict(color='darkgreen', size=12, symbol='triangle-up'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=4, col=1\n",
+ " )\n",
+ " \n",
+ " # Add BUY CLOSE signals\n",
+ " if len(buy_close_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=buy_close_trades['time'],\n",
+ " y=buy_close_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_B} BUY CLOSE',\n",
+ " marker=dict(color='green', size=12, symbol='triangle-up'),\n",
+ " line=dict(width=2, color='black'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=4, col=1\n",
+ " )\n",
+ " \n",
+ " # Add SELL OPEN signals\n",
+ " if len(sell_open_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=sell_open_trades['time'],\n",
+ " y=sell_open_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_B} SELL OPEN',\n",
+ " marker=dict(color='red', size=12, symbol='triangle-down'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=4, col=1\n",
+ " )\n",
+ " \n",
+ " # Add SELL CLOSE signals\n",
+ " if len(sell_close_trades) > 0:\n",
+ " fig.add_trace(\n",
+ " go.Scatter(\n",
+ " x=sell_close_trades['time'],\n",
+ " y=sell_close_trades['price'],\n",
+ " mode='markers',\n",
+ " name=f'{SYMBOL_B} SELL CLOSE',\n",
+ " marker=dict(color='red', size=12, symbol='triangle-down'),\n",
+ " line=dict(width=2, color='black'),\n",
+ " showlegend=True\n",
+ " ),\n",
+ " row=4, col=1\n",
+ " )\n",
+ " \n",
+ " # Update layout\n",
+ " fig.update_layout(\n",
+ " height=1600,\n",
+ " title_text=f\"Strategy Analysis - {SYMBOL_A} & {SYMBOL_B} ({TRD_DATE})\",\n",
+ " showlegend=True,\n",
+ " template=\"plotly_white\",\n",
+ " plot_bgcolor='lightgray',\n",
+ " )\n",
+ " \n",
+ " # Update y-axis labels\n",
+ " fig.update_yaxes(title_text=\"Scaled Dis-equilibrium\", row=1, col=1)\n",
+ " fig.update_yaxes(title_text=f\"{SYMBOL_A} Price ($)\", row=2, col=1)\n",
+ " fig.update_yaxes(title_text=f\"{SYMBOL_B} Price ($)\", row=3, col=1)\n",
+ " fig.update_yaxes(title_text=\"Normalized Price (Base = 1.0)\", row=4, col=1)\n",
+ " \n",
+ " # Update x-axis labels and ensure consistent time range\n",
+ " time_range = [timeline_df['tstamp'].min(), timeline_df['tstamp'].max()]\n",
+ " fig.update_xaxes(range=time_range, row=1, col=1)\n",
+ " fig.update_xaxes(range=time_range, row=2, col=1)\n",
+ " fig.update_xaxes(range=time_range, row=3, col=1)\n",
+ " fig.update_xaxes(title_text=\"Time\", range=time_range, row=4, col=1)\n",
+ " \n",
+ " # Display using plotly offline mode\n",
+ " # pyo.iplot(fig)\n",
+ " fig.show()\n",
+ " \n",
+ " else:\n",
+ " print(\"No interactive visualization data available - strategy may not have run successfully\")\n",
+ "\n",
+ " print(f\"\\nChart shows:\")\n",
+ " print(f\"- {SYMBOL_A} and {SYMBOL_B} prices normalized to start at 1.0\")\n",
+ " print(f\"- BUY signals shown as green triangles pointing up\")\n",
+ " print(f\"- SELL signals shown as orange triangles pointing down\")\n",
+ " print(f\"- All BUY signals per symbol grouped together, all SELL signals per symbol grouped together\")\n",
+ " print(f\"- Hover over markers to see individual trade details (OPEN/CLOSE status)\")\n",
+ "\n",
+ " if pair_trades is not None and len(pair_trades) > 0:\n",
+ " print(f\"- Total signals displayed: {len(pair_trades)}\")\n",
+ " print(f\"- {SYMBOL_A} signals: {len(pair_trades[pair_trades['symbol'] == SYMBOL_A])}\")\n",
+ " print(f\"- {SYMBOL_B} signals: {len(pair_trades[pair_trades['symbol'] == SYMBOL_B])}\")\n",
+ " else:\n",
+ " print(\"- No trading signals to display\")\n",
+ "\n",
+ "# visualization()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "vscode": {
+ "languageId": "raw"
+ }
+ },
+ "source": [
+ "## Summary\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def summary() -> None:\n",
+ " global PT_RESULTS\n",
+ " \n",
+ " PT_RESULTS.analyze_pair_performance()\n",
+ " \n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Performance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def performance_results() -> None:\n",
+ " global pair_trades\n",
+ " global bt_result\n",
+ " global SYMBOL_A\n",
+ " global SYMBOL_B\n",
+ " global FIT_METHOD_TYPE\n",
+ " global PT_BT_CONFIG\n",
+ "\n",
+ " from pt_trading.results import BacktestResult\n",
+ "\n",
+ " if pair_trades is not None and len(pair_trades) > 0:\n",
+ " # Print detailed results using BacktestResult methods\n",
+ " # bt_result.print_single_day_results()\n",
+ " \n",
+ " # Print trading signal details\n",
+ " print(f\"\\nDetailed Trading Signals:\")\n",
+ " print(f\"{'Time':<20} {'Action':<15} {'Symbol':<10} {'Price':<12} {'Scaled Dis-eq':<15} {'Status':<10}\")\n",
+ " print(\"-\" * 90)\n",
+ " \n",
+ " for _, trade in pair_trades.head(10).iterrows(): # Show first 10 trades\n",
+ " time_str = str(trade['time'])[:19] \n",
+ " action_str = str(trade['action'])[:14]\n",
+ " symbol_str = str(trade['symbol'])[:9]\n",
+ " price_str = f\"${trade['price']:.2f}\"\n",
+ " diseq_str = f\"{trade.get('scaled_disequilibrium', 'N/A'):.3f}\" if 'scaled_disequilibrium' in trade else 'N/A'\n",
+ " status = trade.get('status', 'N/A')\n",
+ " \n",
+ " print(f\"{time_str:<20} {action_str:<15} {symbol_str:<10} {price_str:<12} {diseq_str:<15} {status:<10}\")\n",
+ " \n",
+ " if len(pair_trades) > 10:\n",
+ " print(f\"... and {len(pair_trades)-10} more trading signals\")\n",
+ " \n",
+ " bt_result.collect_single_day_results([pair_trades])\n",
+ "\n",
+ " # bt_result.print_grand_totals()\n",
+ " # bt_result.print_outstanding_positions() \n",
+ " else:\n",
+ " print(f\"\\nNo trading signals generated\")\n",
+ " print(f\"Backtest completed with no trades\")\n",
+ " \n",
+ " # Still print any outstanding information\n",
+ " print(f\"\\nConfiguration Summary:\")\n",
+ " print(f\" Pair: {SYMBOL_A} & {SYMBOL_B}\")\n",
+ " print(f\" Strategy: {FIT_METHOD_TYPE}\")\n",
+ " print(f\" Open threshold: {PT_BT_CONFIG['dis-equilibrium_open_trshld']}\")\n",
+ " print(f\" Close threshold: {PT_BT_CONFIG['dis-equilibrium_close_trshld']}\")\n",
+ " print(f\" Training window: {PT_BT_CONFIG['training_minutes']} minutes\")\n",
+ " \n",
+ " print(\"\\n\" + \"=\"*80)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "\n",
+ "def print_summary():\n",
+ " global pair_trades\n",
+ "\n",
+ " from pt_trading.results import BacktestResult\n",
+ "\n",
+ " if pair_trades is not None and len(pair_trades) > 0:\n",
+ " all_results: Dict[str, Dict[str, Any]] = {}\n",
+ " all_results[f\"{TRADING_DATE}-{pair.name()}\"] = {\n",
+ " \"trades\": bt_result.trades.copy(), \n",
+ " \"outstanding_positions\": bt_result.outstanding_positions.copy()\n",
+ " }\n",
+ "\n",
+ " if all_results:\n",
+ " aggregate_bt_results = BacktestResult(config=PT_BT_CONFIG)\n",
+ " aggregate_bt_results.calculate_returns(all_results)\n",
+ " aggregate_bt_results.print_grand_totals()\n",
+ " aggregate_bt_results.print_outstanding_positions()\n",
+ "\n",
+ "\n",
+ " \n",
+ "# performance_results()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Run"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "setup()\n",
+ "load_config_from_file()\n",
+ "prepare_config()\n",
+ "run_strategy()\n",
+ "visualize_prices()\n",
+ "visualize_trades()\n",
+ "summary() \n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "python3.12-venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/research/notebooks/single_pair_test.ipynb b/research/notebooks/single_pair_test.ipynb
index 1340ba1..aa08284 100644
--- a/research/notebooks/single_pair_test.ipynb
+++ b/research/notebooks/single_pair_test.ipynb
@@ -393,40 +393,40 @@
"
2025-06-02 11:30:00 | \n",
" 0.6670 | \n",
" 154.01 | \n",
- " 0.6673 | \n",
- " 154.12 | \n",
+ " 0.6670 | \n",
+ " 154.01 | \n",
" \n",
" \n",
" | 1 | \n",
" 2025-06-02 11:31:00 | \n",
" 0.6673 | \n",
" 154.12 | \n",
- " 0.6677 | \n",
- " 154.16 | \n",
+ " 0.6673 | \n",
+ " 154.12 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2025-06-02 11:32:00 | \n",
" 0.6677 | \n",
" 154.16 | \n",
- " 0.6679 | \n",
- " 154.22 | \n",
+ " 0.6677 | \n",
+ " 154.16 | \n",
"
\n",
" \n",
" | 3 | \n",
" 2025-06-02 11:33:00 | \n",
" 0.6679 | \n",
" 154.22 | \n",
- " 0.6670 | \n",
- " 154.06 | \n",
+ " 0.6679 | \n",
+ " 154.22 | \n",
"
\n",
" \n",
" | 4 | \n",
" 2025-06-02 11:34:00 | \n",
" 0.6670 | \n",
" 154.06 | \n",
- " 0.6680 | \n",
- " 154.20 | \n",
+ " 0.6670 | \n",
+ " 154.06 | \n",
"
\n",
" \n",
"\n",
@@ -434,11 +434,11 @@
],
"text/plain": [
" tstamp close_ADA-USDT close_SOL-USDT exec_price_ADA-USDT exec_price_SOL-USDT\n",
- "0 2025-06-02 11:30:00 0.6670 154.01 0.6673 154.12\n",
- "1 2025-06-02 11:31:00 0.6673 154.12 0.6677 154.16\n",
- "2 2025-06-02 11:32:00 0.6677 154.16 0.6679 154.22\n",
- "3 2025-06-02 11:33:00 0.6679 154.22 0.6670 154.06\n",
- "4 2025-06-02 11:34:00 0.6670 154.06 0.6680 154.20"
+ "0 2025-06-02 11:30:00 0.6670 154.01 0.6670 154.01\n",
+ "1 2025-06-02 11:31:00 0.6673 154.12 0.6673 154.12\n",
+ "2 2025-06-02 11:32:00 0.6677 154.16 0.6677 154.16\n",
+ "3 2025-06-02 11:33:00 0.6679 154.22 0.6679 154.22\n",
+ "4 2025-06-02 11:34:00 0.6670 154.06 0.6670 154.06"
]
},
"metadata": {},
@@ -474,44 +474,44 @@
" \n",
" \n",
" \n",
- " | 654 | \n",
+ " 504 | \n",
" 2025-06-02 22:25:00 | \n",
" 0.6919 | \n",
" 156.70 | \n",
- " 0.6917 | \n",
- " 156.72 | \n",
+ " 0.6919 | \n",
+ " 156.70 | \n",
"
\n",
" \n",
- " | 655 | \n",
+ " 505 | \n",
" 2025-06-02 22:26:00 | \n",
" 0.6917 | \n",
" 156.72 | \n",
- " 0.6909 | \n",
- " 156.57 | \n",
+ " 0.6917 | \n",
+ " 156.72 | \n",
"
\n",
" \n",
- " | 656 | \n",
+ " 506 | \n",
" 2025-06-02 22:27:00 | \n",
" 0.6909 | \n",
" 156.57 | \n",
- " 0.6908 | \n",
- " 156.65 | \n",
+ " 0.6909 | \n",
+ " 156.57 | \n",
"
\n",
" \n",
- " | 657 | \n",
+ " 507 | \n",
" 2025-06-02 22:28:00 | \n",
" 0.6908 | \n",
" 156.65 | \n",
- " 0.6910 | \n",
- " 156.75 | \n",
+ " 0.6908 | \n",
+ " 156.65 | \n",
"
\n",
" \n",
- " | 658 | \n",
+ " 508 | \n",
" 2025-06-02 22:29:00 | \n",
" 0.6910 | \n",
" 156.75 | \n",
- " 0.6908 | \n",
- " 156.70 | \n",
+ " 0.6910 | \n",
+ " 156.75 | \n",
"
\n",
" \n",
"\n",
@@ -519,11 +519,11 @@
],
"text/plain": [
" tstamp close_ADA-USDT close_SOL-USDT exec_price_ADA-USDT exec_price_SOL-USDT\n",
- "654 2025-06-02 22:25:00 0.6919 156.70 0.6917 156.72\n",
- "655 2025-06-02 22:26:00 0.6917 156.72 0.6909 156.57\n",
- "656 2025-06-02 22:27:00 0.6909 156.57 0.6908 156.65\n",
- "657 2025-06-02 22:28:00 0.6908 156.65 0.6910 156.75\n",
- "658 2025-06-02 22:29:00 0.6910 156.75 0.6908 156.70"
+ "504 2025-06-02 22:25:00 0.6919 156.70 0.6919 156.70\n",
+ "505 2025-06-02 22:26:00 0.6917 156.72 0.6917 156.72\n",
+ "506 2025-06-02 22:27:00 0.6909 156.57 0.6909 156.57\n",
+ "507 2025-06-02 22:28:00 0.6908 156.65 0.6908 156.65\n",
+ "508 2025-06-02 22:29:00 0.6910 156.75 0.6910 156.75"
]
},
"metadata": {},
@@ -1539,40 +1539,40 @@
" 2025-06-02 11:30:00 | \n",
" 0.6670 | \n",
" 154.01 | \n",
- " 0.6673 | \n",
- " 154.12 | \n",
+ " 0.6670 | \n",
+ " 154.01 | \n",
" \n",
" \n",
" | 1 | \n",
" 2025-06-02 11:31:00 | \n",
" 0.6673 | \n",
" 154.12 | \n",
- " 0.6677 | \n",
- " 154.16 | \n",
+ " 0.6673 | \n",
+ " 154.12 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2025-06-02 11:32:00 | \n",
" 0.6677 | \n",
" 154.16 | \n",
- " 0.6679 | \n",
- " 154.22 | \n",
+ " 0.6677 | \n",
+ " 154.16 | \n",
"
\n",
" \n",
" | 3 | \n",
" 2025-06-02 11:33:00 | \n",
" 0.6679 | \n",
" 154.22 | \n",
- " 0.6670 | \n",
- " 154.06 | \n",
+ " 0.6679 | \n",
+ " 154.22 | \n",
"
\n",
" \n",
" | 4 | \n",
" 2025-06-02 11:34:00 | \n",
" 0.6670 | \n",
" 154.06 | \n",
- " 0.6680 | \n",
- " 154.20 | \n",
+ " 0.6670 | \n",
+ " 154.06 | \n",
"
\n",
" \n",
"\n",
@@ -1580,11 +1580,11 @@
],
"text/plain": [
" tstamp close_ADA-USDT close_SOL-USDT exec_price_ADA-USDT exec_price_SOL-USDT\n",
- "0 2025-06-02 11:30:00 0.6670 154.01 0.6673 154.12\n",
- "1 2025-06-02 11:31:00 0.6673 154.12 0.6677 154.16\n",
- "2 2025-06-02 11:32:00 0.6677 154.16 0.6679 154.22\n",
- "3 2025-06-02 11:33:00 0.6679 154.22 0.6670 154.06\n",
- "4 2025-06-02 11:34:00 0.6670 154.06 0.6680 154.20"
+ "0 2025-06-02 11:30:00 0.6670 154.01 0.6670 154.01\n",
+ "1 2025-06-02 11:31:00 0.6673 154.12 0.6673 154.12\n",
+ "2 2025-06-02 11:32:00 0.6677 154.16 0.6677 154.16\n",
+ "3 2025-06-02 11:33:00 0.6679 154.22 0.6679 154.22\n",
+ "4 2025-06-02 11:34:00 0.6670 154.06 0.6670 154.06"
]
},
"metadata": {},
@@ -1620,44 +1620,44 @@
" \n",
" \n",
" \n",
- " | 654 | \n",
+ " 504 | \n",
" 2025-06-02 22:25:00 | \n",
" 0.6919 | \n",
" 156.70 | \n",
- " 0.6917 | \n",
- " 156.72 | \n",
+ " 0.6919 | \n",
+ " 156.70 | \n",
"
\n",
" \n",
- " | 655 | \n",
+ " 505 | \n",
" 2025-06-02 22:26:00 | \n",
" 0.6917 | \n",
" 156.72 | \n",
- " 0.6909 | \n",
- " 156.57 | \n",
+ " 0.6917 | \n",
+ " 156.72 | \n",
"
\n",
" \n",
- " | 656 | \n",
+ " 506 | \n",
" 2025-06-02 22:27:00 | \n",
" 0.6909 | \n",
" 156.57 | \n",
- " 0.6908 | \n",
- " 156.65 | \n",
+ " 0.6909 | \n",
+ " 156.57 | \n",
"
\n",
" \n",
- " | 657 | \n",
+ " 507 | \n",
" 2025-06-02 22:28:00 | \n",
" 0.6908 | \n",
" 156.65 | \n",
- " 0.6910 | \n",
- " 156.75 | \n",
+ " 0.6908 | \n",
+ " 156.65 | \n",
"
\n",
" \n",
- " | 658 | \n",
+ " 508 | \n",
" 2025-06-02 22:29:00 | \n",
" 0.6910 | \n",
" 156.75 | \n",
- " 0.6908 | \n",
- " 156.70 | \n",
+ " 0.6910 | \n",
+ " 156.75 | \n",
"
\n",
" \n",
"\n",
@@ -1665,11 +1665,11 @@
],
"text/plain": [
" tstamp close_ADA-USDT close_SOL-USDT exec_price_ADA-USDT exec_price_SOL-USDT\n",
- "654 2025-06-02 22:25:00 0.6919 156.70 0.6917 156.72\n",
- "655 2025-06-02 22:26:00 0.6917 156.72 0.6909 156.57\n",
- "656 2025-06-02 22:27:00 0.6909 156.57 0.6908 156.65\n",
- "657 2025-06-02 22:28:00 0.6908 156.65 0.6910 156.75\n",
- "658 2025-06-02 22:29:00 0.6910 156.75 0.6908 156.70"
+ "504 2025-06-02 22:25:00 0.6919 156.70 0.6919 156.70\n",
+ "505 2025-06-02 22:26:00 0.6917 156.72 0.6917 156.72\n",
+ "506 2025-06-02 22:27:00 0.6909 156.57 0.6909 156.57\n",
+ "507 2025-06-02 22:28:00 0.6908 156.65 0.6908 156.65\n",
+ "508 2025-06-02 22:29:00 0.6910 156.75 0.6910 156.75"
]
},
"metadata": {},
@@ -1737,69 +1737,86 @@
"OPEN_TRADES: 2025-06-02 13:37:00 open_scaled_disequilibrium=2.1525256289273242\n",
"OPEN TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 13:37:00 ADA-USDT BUY OPEN 0.6754 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 13:37:00 SOL-USDT SELL OPEN 154.3200 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
+ "0 2025-06-02 13:37:00 ADA-USDT BUY OPEN 0.6743 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 13:37:00 SOL-USDT SELL OPEN 154.1400 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
"CLOSE TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 14:37:00 ADA-USDT SELL CLOSE 0.6734 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
- "1 2025-06-02 14:37:00 SOL-USDT BUY CLOSE 153.7000 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
+ "0 2025-06-02 14:37:00 ADA-USDT SELL CLOSE 0.6746 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 14:37:00 SOL-USDT BUY CLOSE 154.0000 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
"OPEN_TRADES: 2025-06-02 15:09:00 open_scaled_disequilibrium=2.5218125398969375\n",
"OPEN TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 15:09:00 ADA-USDT BUY OPEN 0.6691 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 15:09:00 SOL-USDT SELL OPEN 152.1800 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
+ "0 2025-06-02 15:09:00 ADA-USDT BUY OPEN 0.6689 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 15:09:00 SOL-USDT SELL OPEN 152.1200 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
"CLOSE TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 15:41:00 ADA-USDT SELL CLOSE 0.6734 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
- "1 2025-06-02 15:41:00 SOL-USDT BUY CLOSE 153.1000 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
+ "0 2025-06-02 15:41:00 ADA-USDT SELL CLOSE 0.6735 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 15:41:00 SOL-USDT BUY CLOSE 153.0800 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
"OPEN_TRADES: 2025-06-02 16:44:00 open_scaled_disequilibrium=2.364778510607668\n",
"OPEN TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 16:44:00 ADA-USDT BUY OPEN 0.6712 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 16:44:00 SOL-USDT SELL OPEN 152.5100 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
+ "0 2025-06-02 16:44:00 ADA-USDT BUY OPEN 0.6708 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 16:44:00 SOL-USDT SELL OPEN 152.4700 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
"CLOSE TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 17:01:00 ADA-USDT SELL CLOSE 0.6744 -0.45725 0.45725 -0.45725 ADA-USDT & SOL-USDT CLOSE\n",
- "1 2025-06-02 17:01:00 SOL-USDT BUY CLOSE 153.0700 -0.45725 0.45725 -0.45725 ADA-USDT & SOL-USDT CLOSE\n",
+ "0 2025-06-02 17:01:00 ADA-USDT SELL CLOSE 0.6745 -0.45725 0.45725 -0.45725 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 17:01:00 SOL-USDT BUY CLOSE 153.2100 -0.45725 0.45725 -0.45725 ADA-USDT & SOL-USDT CLOSE\n",
"OPEN_TRADES: 2025-06-02 17:06:00 open_scaled_disequilibrium=2.191024540541887\n",
"OPEN TRADES:\n",
- " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 17:06:00 ADA-USDT BUY OPEN 0.674 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 17:06:00 SOL-USDT SELL OPEN 153.030 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 17:06:00 ADA-USDT BUY OPEN 0.6738 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 17:06:00 SOL-USDT SELL OPEN 152.9000 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
"CLOSE TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 17:17:00 ADA-USDT SELL CLOSE 0.6743 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
- "1 2025-06-02 17:17:00 SOL-USDT BUY CLOSE 153.0900 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
+ "0 2025-06-02 17:17:00 ADA-USDT SELL CLOSE 0.6726 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 17:17:00 SOL-USDT BUY CLOSE 152.7800 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
"OPEN_TRADES: 2025-06-02 17:24:00 open_scaled_disequilibrium=2.748538160528875\n",
"OPEN TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 17:24:00 ADA-USDT BUY OPEN 0.6759 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 17:24:00 SOL-USDT SELL OPEN 153.7000 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
+ "0 2025-06-02 17:24:00 ADA-USDT BUY OPEN 0.6755 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 17:24:00 SOL-USDT SELL OPEN 153.5600 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
"CLOSE TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 17:35:00 ADA-USDT SELL CLOSE 0.6715 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
- "1 2025-06-02 17:35:00 SOL-USDT BUY CLOSE 152.9900 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
+ "0 2025-06-02 17:35:00 ADA-USDT SELL CLOSE 0.6712 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 17:35:00 SOL-USDT BUY CLOSE 153.0300 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
"OPEN_TRADES: 2025-06-02 18:02:00 open_scaled_disequilibrium=2.0472288892294728\n",
"OPEN TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 18:02:00 ADA-USDT SELL OPEN 0.6743 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 18:02:00 SOL-USDT BUY OPEN 153.6400 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
+ "0 2025-06-02 18:02:00 ADA-USDT SELL OPEN 0.6741 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 18:02:00 SOL-USDT BUY OPEN 153.5900 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
"CLOSE TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 18:06:00 ADA-USDT BUY CLOSE 0.6747 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
- "1 2025-06-02 18:06:00 SOL-USDT SELL CLOSE 153.8400 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
+ "0 2025-06-02 18:06:00 ADA-USDT BUY CLOSE 0.6746 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 18:06:00 SOL-USDT SELL CLOSE 153.7900 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
"OPEN_TRADES: 2025-06-02 19:35:00 open_scaled_disequilibrium=2.016877535891162\n",
"OPEN TRADES:\n",
" time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 19:35:00 ADA-USDT BUY OPEN 0.6721 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
- "1 2025-06-02 19:35:00 SOL-USDT SELL OPEN 152.1300 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
- "ADA-USDT & SOL-USDT: *** Position is NOT CLOSED. ***\n",
- "CLOSE_POSITION TRADES:\n",
- " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 22:28:00 ADA-USDT SELL CLOSE 0.691 0.0 0.0 0.0 ADA-USDT & SOL-USDT CLOSE_POSITION\n",
- "1 2025-06-02 22:28:00 SOL-USDT BUY CLOSE 156.750 0.0 0.0 0.0 ADA-USDT & SOL-USDT CLOSE_POSITION\n",
- "***ADA-USDT & SOL-USDT*** FINISHED *** Num Trades:28\n",
- "Generated 28 trading signals\n",
+ "0 2025-06-02 19:35:00 ADA-USDT BUY OPEN 0.6719 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 19:35:00 SOL-USDT SELL OPEN 151.9900 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
+ "CLOSE TRADES:\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 21:04:00 ADA-USDT SELL CLOSE 0.6845 -0.316305 0.316305 -0.316305 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 21:04:00 SOL-USDT BUY CLOSE 154.7200 -0.316305 0.316305 -0.316305 ADA-USDT & SOL-USDT CLOSE\n",
+ "OPEN_TRADES: 2025-06-02 21:33:00 open_scaled_disequilibrium=2.1162146947771068\n",
+ "OPEN TRADES:\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 21:33:00 ADA-USDT SELL OPEN 0.6819 2.116215 2.116215 2.116215 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 21:33:00 SOL-USDT BUY OPEN 154.5100 2.116215 2.116215 2.116215 ADA-USDT & SOL-USDT OPEN\n",
+ "CLOSE TRADES:\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 21:40:00 ADA-USDT BUY CLOSE 0.6833 -0.195611 0.195611 -0.195611 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 21:40:00 SOL-USDT SELL CLOSE 154.9200 -0.195611 0.195611 -0.195611 ADA-USDT & SOL-USDT CLOSE\n",
+ "OPEN_TRADES: 2025-06-02 21:58:00 open_scaled_disequilibrium=2.0841568077931436\n",
+ "OPEN TRADES:\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 21:58:00 ADA-USDT BUY OPEN 0.6842 -2.084157 2.084157 -2.084157 ADA-USDT & SOL-USDT OPEN\n",
+ "1 2025-06-02 21:58:00 SOL-USDT SELL OPEN 155.2900 -2.084157 2.084157 -2.084157 ADA-USDT & SOL-USDT OPEN\n",
+ "CLOSE TRADES:\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 22:06:00 ADA-USDT SELL CLOSE 0.6887 -0.396354 0.396354 -0.396354 ADA-USDT & SOL-USDT CLOSE\n",
+ "1 2025-06-02 22:06:00 SOL-USDT BUY CLOSE 155.8300 -0.396354 0.396354 -0.396354 ADA-USDT & SOL-USDT CLOSE\n",
+ "***ADA-USDT & SOL-USDT*** FINISHED *** Num Trades:36\n",
+ "Generated 36 trading signals\n",
"\n",
"Strategy execution completed!\n",
"\n",
@@ -1832,38 +1849,46 @@
"Timeline range: 2025-06-02 11:30:00 to 2025-06-02 22:29:00\n",
"\n",
"Symbol_A trades:\n",
- " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "0 2025-06-02 13:37:00 ADA-USDT BUY OPEN 0.6754 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
- "2 2025-06-02 14:37:00 ADA-USDT SELL CLOSE 0.6734 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
- "4 2025-06-02 15:09:00 ADA-USDT BUY OPEN 0.6691 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
- "6 2025-06-02 15:41:00 ADA-USDT SELL CLOSE 0.6734 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
- "8 2025-06-02 16:44:00 ADA-USDT BUY OPEN 0.6712 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
- "10 2025-06-02 17:01:00 ADA-USDT SELL CLOSE 0.6744 -0.457250 0.457250 -0.457250 ADA-USDT & SOL-USDT CLOSE\n",
- "12 2025-06-02 17:06:00 ADA-USDT BUY OPEN 0.6740 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
- "14 2025-06-02 17:17:00 ADA-USDT SELL CLOSE 0.6743 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
- "16 2025-06-02 17:24:00 ADA-USDT BUY OPEN 0.6759 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
- "18 2025-06-02 17:35:00 ADA-USDT SELL CLOSE 0.6715 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
- "20 2025-06-02 18:02:00 ADA-USDT SELL OPEN 0.6743 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
- "22 2025-06-02 18:06:00 ADA-USDT BUY CLOSE 0.6747 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
- "24 2025-06-02 19:35:00 ADA-USDT BUY OPEN 0.6721 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
- "26 2025-06-02 22:28:00 ADA-USDT SELL CLOSE 0.6910 0.000000 0.000000 0.000000 ADA-USDT & SOL-USDT CLOSE_POSITION\n",
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "0 2025-06-02 13:37:00 ADA-USDT BUY OPEN 0.6743 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
+ "2 2025-06-02 14:37:00 ADA-USDT SELL CLOSE 0.6746 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
+ "4 2025-06-02 15:09:00 ADA-USDT BUY OPEN 0.6689 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
+ "6 2025-06-02 15:41:00 ADA-USDT SELL CLOSE 0.6735 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
+ "8 2025-06-02 16:44:00 ADA-USDT BUY OPEN 0.6708 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
+ "10 2025-06-02 17:01:00 ADA-USDT SELL CLOSE 0.6745 -0.457250 0.457250 -0.457250 ADA-USDT & SOL-USDT CLOSE\n",
+ "12 2025-06-02 17:06:00 ADA-USDT BUY OPEN 0.6738 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
+ "14 2025-06-02 17:17:00 ADA-USDT SELL CLOSE 0.6726 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
+ "16 2025-06-02 17:24:00 ADA-USDT BUY OPEN 0.6755 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
+ "18 2025-06-02 17:35:00 ADA-USDT SELL CLOSE 0.6712 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
+ "20 2025-06-02 18:02:00 ADA-USDT SELL OPEN 0.6741 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
+ "22 2025-06-02 18:06:00 ADA-USDT BUY CLOSE 0.6746 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
+ "24 2025-06-02 19:35:00 ADA-USDT BUY OPEN 0.6719 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
+ "26 2025-06-02 21:04:00 ADA-USDT SELL CLOSE 0.6845 -0.316305 0.316305 -0.316305 ADA-USDT & SOL-USDT CLOSE\n",
+ "28 2025-06-02 21:33:00 ADA-USDT SELL OPEN 0.6819 2.116215 2.116215 2.116215 ADA-USDT & SOL-USDT OPEN\n",
+ "30 2025-06-02 21:40:00 ADA-USDT BUY CLOSE 0.6833 -0.195611 0.195611 -0.195611 ADA-USDT & SOL-USDT CLOSE\n",
+ "32 2025-06-02 21:58:00 ADA-USDT BUY OPEN 0.6842 -2.084157 2.084157 -2.084157 ADA-USDT & SOL-USDT OPEN\n",
+ "34 2025-06-02 22:06:00 ADA-USDT SELL CLOSE 0.6887 -0.396354 0.396354 -0.396354 ADA-USDT & SOL-USDT CLOSE\n",
"\n",
"Symbol_B trades:\n",
- " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
- "1 2025-06-02 13:37:00 SOL-USDT SELL OPEN 154.32 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
- "3 2025-06-02 14:37:00 SOL-USDT BUY CLOSE 153.70 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
- "5 2025-06-02 15:09:00 SOL-USDT SELL OPEN 152.18 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
- "7 2025-06-02 15:41:00 SOL-USDT BUY CLOSE 153.10 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
- "9 2025-06-02 16:44:00 SOL-USDT SELL OPEN 152.51 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
- "11 2025-06-02 17:01:00 SOL-USDT BUY CLOSE 153.07 -0.457250 0.457250 -0.457250 ADA-USDT & SOL-USDT CLOSE\n",
- "13 2025-06-02 17:06:00 SOL-USDT SELL OPEN 153.03 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
- "15 2025-06-02 17:17:00 SOL-USDT BUY CLOSE 153.09 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
- "17 2025-06-02 17:24:00 SOL-USDT SELL OPEN 153.70 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
- "19 2025-06-02 17:35:00 SOL-USDT BUY CLOSE 152.99 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
- "21 2025-06-02 18:02:00 SOL-USDT BUY OPEN 153.64 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
- "23 2025-06-02 18:06:00 SOL-USDT SELL CLOSE 153.84 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
- "25 2025-06-02 19:35:00 SOL-USDT SELL OPEN 152.13 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
- "27 2025-06-02 22:28:00 SOL-USDT BUY CLOSE 156.75 0.000000 0.000000 0.000000 ADA-USDT & SOL-USDT CLOSE_POSITION\n"
+ " time symbol side action price disequilibrium scaled_disequilibrium signed_scaled_disequilibrium pair status\n",
+ "1 2025-06-02 13:37:00 SOL-USDT SELL OPEN 154.14 -2.152526 2.152526 -2.152526 ADA-USDT & SOL-USDT OPEN\n",
+ "3 2025-06-02 14:37:00 SOL-USDT BUY CLOSE 154.00 -0.280199 0.280199 -0.280199 ADA-USDT & SOL-USDT CLOSE\n",
+ "5 2025-06-02 15:09:00 SOL-USDT SELL OPEN 152.12 -2.521813 2.521813 -2.521813 ADA-USDT & SOL-USDT OPEN\n",
+ "7 2025-06-02 15:41:00 SOL-USDT BUY CLOSE 153.08 0.014633 0.014633 0.014633 ADA-USDT & SOL-USDT CLOSE\n",
+ "9 2025-06-02 16:44:00 SOL-USDT SELL OPEN 152.47 -2.364779 2.364779 -2.364779 ADA-USDT & SOL-USDT OPEN\n",
+ "11 2025-06-02 17:01:00 SOL-USDT BUY CLOSE 153.21 -0.457250 0.457250 -0.457250 ADA-USDT & SOL-USDT CLOSE\n",
+ "13 2025-06-02 17:06:00 SOL-USDT SELL OPEN 152.90 -2.191025 2.191025 -2.191025 ADA-USDT & SOL-USDT OPEN\n",
+ "15 2025-06-02 17:17:00 SOL-USDT BUY CLOSE 152.78 -0.152501 0.152501 -0.152501 ADA-USDT & SOL-USDT CLOSE\n",
+ "17 2025-06-02 17:24:00 SOL-USDT SELL OPEN 153.56 -2.748538 2.748538 -2.748538 ADA-USDT & SOL-USDT OPEN\n",
+ "19 2025-06-02 17:35:00 SOL-USDT BUY CLOSE 153.03 -0.413061 0.413061 -0.413061 ADA-USDT & SOL-USDT CLOSE\n",
+ "21 2025-06-02 18:02:00 SOL-USDT BUY OPEN 153.59 2.047229 2.047229 2.047229 ADA-USDT & SOL-USDT OPEN\n",
+ "23 2025-06-02 18:06:00 SOL-USDT SELL CLOSE 153.79 -0.089168 0.089168 -0.089168 ADA-USDT & SOL-USDT CLOSE\n",
+ "25 2025-06-02 19:35:00 SOL-USDT SELL OPEN 151.99 -2.016878 2.016878 -2.016878 ADA-USDT & SOL-USDT OPEN\n",
+ "27 2025-06-02 21:04:00 SOL-USDT BUY CLOSE 154.72 -0.316305 0.316305 -0.316305 ADA-USDT & SOL-USDT CLOSE\n",
+ "29 2025-06-02 21:33:00 SOL-USDT BUY OPEN 154.51 2.116215 2.116215 2.116215 ADA-USDT & SOL-USDT OPEN\n",
+ "31 2025-06-02 21:40:00 SOL-USDT SELL CLOSE 154.92 -0.195611 0.195611 -0.195611 ADA-USDT & SOL-USDT CLOSE\n",
+ "33 2025-06-02 21:58:00 SOL-USDT SELL OPEN 155.29 -2.084157 2.084157 -2.084157 ADA-USDT & SOL-USDT OPEN\n",
+ "35 2025-06-02 22:06:00 SOL-USDT BUY CLOSE 155.83 -0.396354 0.396354 -0.396354 ADA-USDT & SOL-USDT CLOSE\n"
]
},
{
@@ -2544,7 +2569,7 @@
],
"xaxis": "x",
"y": {
- "bdata": "AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAA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AAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fw==",
+ "bdata": "AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/BVMBjW/09z9zQRGpTWX6Pw4xzj0Orvk/MtiiQtiB+z+FgrWEDCz9Pw7Q8bGjc/w/PQ2aAf+n/z+GW2BbXzgBQHlAaKw4Hv0/SQ8D81fi/j/nQ3dMW/X9Px2+QaY89vs/aCl1rqPX/D87yoGl2tL6P45IQE6kO/k/Gw5bE3oY+D/mOoYUjyT6P+/jx5x+HPU/v3veDaC09z9O6p4RDcb1P7AOYfcHY/Q/FEDtnK0s9T+lKv7pgNzyP0I03sf0zfE/8XrYx9a+6D8hR+4KMrDxP7jFBBqBV+0/VQnQ2dah8z83tB9lM4n2P+Hx0oO9yPY/eo2yXOOl8z9HhFUkIRf3Pzex2R88S/g/EoXzSVTP/T+YpZfHetr/PzFS3vWWgf8/J4FqFPbLAEBJ3nlbOYIBQEBpWlydtgFApVhD5M4jA0A5ulqxGNcBQJQ43po7egJAV8AgzUx0/T+kY2JbuQb6P7T3N+Ogf/o/ZNE7iiyQ/z+fyvfH/FgCQBlr7I9SywFA3Y5lx5oNAkDmANDGEAUGQDzmK+8WZQZAI3S8Fao/B0CEdWOkyusFQEEqFIRrwgVAgQitVySlBUAchKXSgcEDQCIm/mtPHwJA5/v6XjlDAkB6jxa7IP7/P5seoDX1fP0/i3fQUh54/T8YC2HHN3n2P6pghZ4f6/c/c0B5LG9m6D/J80nOAnjlP+rbiLQsguk/LS4U6w075z/tTIghye7RP5im29eNLd8/iRcDawW+4D+3HpUeDnTEP7VAO42a3sw/mS8pSN6rwj9kuxvLdybTP5EFVr9GY98/uKXpxMT42z89aZv0Z2HmPyA+WD0fDOY/FPNVj66Z8T82Wq7oIW3vP35vQy47NfE/Vn9K9CUk8j/QfMj362PsPw9TnV3Eo+o/zdCwFVGC2D+/qwzrOj3pP0egiAAxbO8/fug93evG7j9WQ2hOjKzrPzMOmw2RiO0/I+zNjWxi5D80c56x3aPhPy1THnBaVec/Hybpct7S3z+Y/JBTIhPXP+iKuvbKqPQ/dFuf/zXb+T8rP7Ziw7H+PxYAjA2sLARAJ+ZUzpMcCUBImnDnWxsHQDZmwOk6WgJAXabxsU9oAUBW4FY6y+39PxdryYSsuPs/12xP7AQB9j+GK4JSDL/2P+vCG+8jIfQ/8Yl93ibw+T/OIswfEyP9PxtPpSyHD/w/KTstOLZ/BEA4CjU0c2sFQMsnzBOaOQZAq8swx9H6B0B4b3ssocIEQHy0Xhq5DQlAzUgbOpwOB0Bq83+oSZYEQBeQLmuRuwVAHeIwLPsiB0D7ZI6+zL4GQAaixX4o+vg/hf6wLTje/j/KOlUbmWsAQHLTDR2zBPw/uATLujJF9j/P618gfKP2PyVdrQZw4uw/mSHqqkxI5z9xm/fT9PeNP6byz/FGAdQ/C1vwLHfY5D8TLAxij0TvPy7ZLx00b+I/sGKIWqoB8j9M7TqLGwzQP8kGos2fB9M/hK7iO+ka2T+2NNJiQeXuPxQTd/9uZNA/3byNxIJXrD8Iki2Hq4fVP0EBjTCymlE/aRx+z7VU2j+w79xITkLZP1k0U5zQhtY/wrKku5v8kD/lI+TIIxuyP9yCErE/ZYE/VYkgN+JO5z93mU6K3ArZPzT5PulqbNw/l+MyFJ7Z2T9R5rtJmbzeP7foE2F0vuo/Q/a24nY66T8LSiSwPxvaP1Y6ZBBVseU/U31DvB/21j/c+rGOScjrPxGIAWZ1c+s/P0aQAZkk4T8C9Er0sNvjP5oUDamnFPc/hW2jpq2G+j+l+7qkqv31P70BZ6/V9PY/OmAT8FcD9D9iLZnyWxPdP7r9NLHpkM8/up+masDU0j8jSLRV0EpiPwza73ybMZs/YVbpZP0Lxj9jJ7iCAWzYP29a4DCH7Oc/qHG57zQ9vz/sYIYDJEGuP3kXI6G2moQ/s9Ur82Orwz9rOdHTvgZjP2iE08u2vsI/VVyM6TFM0z8j550TRmK2P0SzK4KaMdc/qA4qpdMe5T9fXQMfflLoP9arayVuq/E/z5vrKGxy+T9lljDXzEjzP0F4jEqhmPk/6bOnER5B/T+Jv+r+EOsCQJVO4zuk6whABSa1ZpGYCEDtSq7M9U4QQGANCTYHFw9AgifssmsKEUCp/KxbDswOQLzF806S8QtAYgPn6qXYCkCHTq5FofYFQIDjJcY8zQNAl3tTyh/KB0BAXXf35xwDQBeq5/sbzQRACwIgUAGhA0DYKA8lAj/5P0KygQMRJvE/JJIGAJRD3T+thr80mcD0P5s6MjZTiu0/aG8DxAu69z8v0E6t/qD2P/vi0t83hwFAbxsgDflcAkCBL+d3qKwCQDBlPYWc0Po/vKp6SY3H/T8ZtAdUAhjhP43MBzuPyvg/1z/ag0tN9T/cLlZZHRDuPzJma7ZdW/Y/EfOAnyf28z860WUuJYXDP8yt07Dp99Y/Dp2ILiFd5z8YbtWVeO7yPxV2LBpJmPs/OYFUHHJx8D/8RJjKuKT3P3M8OpMB/QVAmvGy2nyP+z9WExKx5X/2P8SfwAMDqvo/FnrbtlRn+z8YhZs7PTr3P1WO3coVIvQ/DPPWlE/c+j/nn3pG6ZP5P/6W7QLwsfI/p0YxD7X14T/axuM4mW/aP+P/Eo+OMMQ/dtJSGo4lwj+dqVsucIXVPx3a4VDgfdY/uNOE8Vg14D+VG+6+JQG9P51hZ49VINQ/8uX5a0TOuD+A0KLtV1DgP5/6xnfeSec/eiWWQien2z+YjgGBQZ7tP3WFjUbxjfQ/I38ZsMfG6z9ynbEeXy75P1l4HkcvNPQ/5dgk0hQj8z+FbdiFWO3wPykhzwJoSvc/hLszsduu9j/qsnXtaZrxP/Axtrx7b+g/2zXqEpZH8j/PEjwYxDnyP3RfMeQtWPI/w3CF4f3k9z8AVjWKuWAAQEi90tCJgfY/nzAazOi44T+lYZhkomPjP40uR6O+07Y/HdubnYPk3D+mGUWJuXPZP+NUFyi/geU//203TiNv4D+4WKuE/iXvP8GQlIabjtw/HZjeQF996D/97JfHkUDlP+hmFtLp2e0/kQoQ6ONW5T80cn6nOPDvP4PQ75UVEvA/eVD8KVs04T8iI3ZJf+7gPxzwa4NsLuo/pzwZ6tCG3D8wCTN+cbDPP7Y8mrw1C9Q/CMzw8cOruj+pKeiJ0CzpP8gwl8JlINQ/BP88P3iWxT+BiXyfouvQP9U7nQvjRuE/t4wwxnHh4j/aHOU+XQTsPyt+TwnQqe8/f+bHQlb95T8etrS91inSP6AYpYhmMdU/GlMKiRAajz9YZ5oIYvrTP79uc2QBpcw/vDuSi8P21j+HrxA1JbbYPxOLTF2sQNM/sWtF1yLV0D+cUdZIelbdP+GuH8Knz8I/YVPgv0gE0j+nnwNwFS/hP3NomQntItQ/6D3JAYx3wj8LvjVD0v3VP+t7K1iSP90/pGVktwzLzj+5xoEr5X/dP1rtUEyp4+k//lvc4xMv1z+SNL2ie+vkP10w3LJfiu4/OZXP1f5G6D/01EP/dE3mP93+f7Sn1ec/3oap72uk8T9lnj2bi5D2PyUR43WwufI/yMPzAdi18j+DrJDo9Df1PwlII8mTMPI/FeUTLEEr7T8GmbFpMAzYP8ll5TLBw+U/67s3II7L8D8N01hdvwHmPy/tVysPfc0/sayJBiW21D9q4Pdz6s3UP2+FFAGni+E/ehZYdDOi1D/3FQIIRWvUP6iTpl20qdY/mNiF9k9i3D/E0+4pBK3gPzUqyrPgL9c/GgIqJ5go1D9TXBqhJ0rLP9AkCmx6uNg/pisNqd8z3j+4uvOumT3FP1yb46GT270/sMNqXrjTrD8pcA7D6ePGP2HuyxMuVOc/xbD+Ijj17j/PQALl1tzoP0IrYgrPYfg/jHz51bn89z9RhIWwkCIAQJgzAOieEP0/AJqpjHF9+j9LUYMhimX5Pw1H0ml04/g/1qxDMU8SAUDSsOCVmHYBQLsC8FaFoQJACKnOHr6SA0AGliUUaG4AQNKQC2OjlQFAFwLm2ToQAEDpnmttiTsAQI88sPAmJgFAxgH0AiSt+z8ckTbf7kL7P+t/NS3PEvw/ulXPcZ6Y/T+zImkorzD3P5/H2U5zpfs/H0WYvLfT+z9uXREKwPr4PwSXzFE5z/M/ULTRznEC9z8t9dZdRGH0P1MLoIn/CfM/46INfJsC8j+9DOyiZ/zyP/d18C5M/fE/x+X+Hqbx6j/NAHppx6DsPx2542HrwfI/2eu+3YoP8z/lcQnuhxvxP6Lt/FW46fE/U4RN36ym9j9eMMMi4C/5P5UXTUG7ifo/NelTEWNn+j/jTYd7a9z2P5FJoFaQCPQ/bkSGqhgj8j+h6dFeWejtP2f44IytQOk//ohLfouI5z9CebPdWo7pP7VNlwsuzOs/syFcPEmW4z/rAkl685DvP3i5zz0lI/A/xehx3/R98D9+XHZcVDvwP3ztbJDJ+fM/equhmQUa9j8I8OI9Zx34PyzHEX3Eh/s/q8F8pzgz/j/YIB+sWfQAQLS1e7h4yv8/M5vxQ6W4/z+hgGutwaIAQJGlIEvoaABAdpJ2p1C8AUDpBALh8hYCQJS4U508/QNADqiosrmaA0BDAOqgnDgDQCceIfh04QNAXQbgWKkRBUBZdQs1CVMFQBeLBuk7pgRAgoXwQIvZAEBs34d60fL+P32svKSqpv8/5eO6uQWC/z/8cV5ebrr7P5sxwaJTdP4/lWfIyYud/z+iRzfsAG//P2BTgOBX1ABAiJs0nsnr+j9IHQAGS8/6P3kH2QX9ZPo/FgC5hk+n/z9nv5+HMHH9Px3MCx8NI/4/rDerZ9u//j/RgQu/1d/1P4/NHn75Fu8/KOSlaVc+1D+lWRFoCdDdP4Ju64VVIa8/Zhr0YHt+1T+9/FpGU0PVPyB5SD9jhdY/LwDAbfBiwD/yM7F2mKnhP9QDTXufI/k/vE+PU8xd+T/BXhDlTuH8Pxg7aHjbsfg/ZKk6jDcz9j+iPtEBa+f6P7vqfxXz0v0/LSodqPkw/T/F6XgFNKH4PzmzlbcaL/U/mTPyw4q3+D8QQRF9TIjuP7z0wEPF+uo/RM3ce7sO8j9XsYtaCvfwPybezzV1Svs/a6PZyTdi/T/MeHubH0D/P1JaPoR7F/4/aHeF5JKo/D+s+k6lRPD5P/EOS/gB7gBA3UXVC+onAEC8yBgVpJX4P/f1MVEIp/E/hb5Wzo5U7D+iQSXplNbjP128c8lj3ew/JLFobcsJyT8GGxtZ5IqjP1BcGzE8BdQ/2NHKwwSz1T/j92sqXQzEPzb/P5XW47M/ykT9pUuF6T/4008LAiHwP5RyHzWeltY/YXeSA0GQ1z/1kUnfEma8Px7HJ1a+xeQ/ZEFsaeVd4z9lEqGPqVPzP6T8yVcnZ/Q/AMw4+PIt7j8qXf3yHpn2P72Oa0rIyP0/kqiJZ1qsAEC00uH4MCoGQPRZC/SiSAVAZKFAauRDA0AP/aG7r1ICQE42NBOJ1ANAz2bI/hHF4z8uaCaGH1rkPyJW5o/eXdk/+Ayoh3W/3T8QuHUCb/fgPznnc4A+V9k/jj3ZX0RLwj8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fw==",
"dtype": "f8"
},
"yaxis": "y"
@@ -3220,7 +3245,7 @@
],
"xaxis": "x",
"y": {
- "bdata": "AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAA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AAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fw==",
+ "bdata": "AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAA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",
"dtype": "f8"
},
"yaxis": "y"
@@ -4588,12 +4613,13 @@
"name": "ADA-USDT BUY OPEN",
"showlegend": true,
"text": [
- "ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 13:37:00
Normalized Price: 1.0109
Actual Price: $0.68",
+ "ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 13:37:00
Normalized Price: 1.0109
Actual Price: $0.67",
"ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 15:09:00
Normalized Price: 1.0028
Actual Price: $0.67",
"ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 16:44:00
Normalized Price: 1.0057
Actual Price: $0.67",
"ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 17:06:00
Normalized Price: 1.0102
Actual Price: $0.67",
"ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 17:24:00
Normalized Price: 1.0127
Actual Price: $0.68",
- "ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 19:35:00
Normalized Price: 1.0073
Actual Price: $0.67"
+ "ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 19:35:00
Normalized Price: 1.0073
Actual Price: $0.67",
+ "ADA-USDT BUY OPEN OPEN
Time: 2025-06-02 21:58:00
Normalized Price: 1.0258
Actual Price: $0.68"
],
"type": "scatter",
"x": [
@@ -4602,7 +4628,8 @@
"2025-06-02T16:44:00",
"2025-06-02T17:06:00",
"2025-06-02T17:24:00",
- "2025-06-02T19:35:00"
+ "2025-06-02T19:35:00",
+ "2025-06-02T21:58:00"
],
"xaxis": "x2",
"y": [
@@ -4611,7 +4638,8 @@
1.0056971514242878,
1.0101949025487256,
1.012743628185907,
- 1.0073463268365817
+ 1.0073463268365817,
+ 1.0257871064467765
],
"yaxis": "y2"
},
@@ -4626,12 +4654,13 @@
"name": "SOL-USDT SELL OPEN",
"showlegend": true,
"text": [
- "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 13:37:00
Normalized Price: 1.0008
Actual Price: $154.32",
- "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 15:09:00
Normalized Price: 0.9877
Actual Price: $152.18",
- "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 16:44:00
Normalized Price: 0.9900
Actual Price: $152.51",
- "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 17:06:00
Normalized Price: 0.9928
Actual Price: $153.03",
- "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 17:24:00
Normalized Price: 0.9971
Actual Price: $153.70",
- "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 19:35:00
Normalized Price: 0.9869
Actual Price: $152.13"
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 13:37:00
Normalized Price: 1.0008
Actual Price: $154.14",
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 15:09:00
Normalized Price: 0.9877
Actual Price: $152.12",
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 16:44:00
Normalized Price: 0.9900
Actual Price: $152.47",
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 17:06:00
Normalized Price: 0.9928
Actual Price: $152.90",
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 17:24:00
Normalized Price: 0.9971
Actual Price: $153.56",
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 19:35:00
Normalized Price: 0.9869
Actual Price: $151.99",
+ "SOL-USDT SELL OPEN OPEN
Time: 2025-06-02 21:58:00
Normalized Price: 1.0083
Actual Price: $155.29"
],
"type": "scatter",
"x": [
@@ -4640,7 +4669,8 @@
"2025-06-02T16:44:00",
"2025-06-02T17:06:00",
"2025-06-02T17:24:00",
- "2025-06-02T19:35:00"
+ "2025-06-02T19:35:00",
+ "2025-06-02T21:58:00"
],
"xaxis": "x2",
"y": [
@@ -4649,7 +4679,8 @@
0.9900006493084865,
0.9927926758002728,
0.9970781118109214,
- 0.9868839685734694
+ 0.9868839685734694,
+ 1.0083111486267125
],
"yaxis": "y2"
},
@@ -4673,7 +4704,8 @@
"ADA-USDT SELL CLOSE CLOSE
Time: 2025-06-02 17:01:00
Normalized Price: 1.0112
Actual Price: $0.67",
"ADA-USDT SELL CLOSE CLOSE
Time: 2025-06-02 17:17:00
Normalized Price: 1.0084
Actual Price: $0.67",
"ADA-USDT SELL CLOSE CLOSE
Time: 2025-06-02 17:35:00
Normalized Price: 1.0063
Actual Price: $0.67",
- "ADA-USDT SELL CLOSE CLOSE
Time: 2025-06-02 22:28:00
Normalized Price: 1.0357
Actual Price: $0.69"
+ "ADA-USDT SELL CLOSE CLOSE
Time: 2025-06-02 21:04:00
Normalized Price: 1.0262
Actual Price: $0.68",
+ "ADA-USDT SELL CLOSE CLOSE
Time: 2025-06-02 22:06:00
Normalized Price: 1.0325
Actual Price: $0.69"
],
"type": "scatter",
"x": [
@@ -4682,7 +4714,8 @@
"2025-06-02T17:01:00",
"2025-06-02T17:17:00",
"2025-06-02T17:35:00",
- "2025-06-02T22:28:00"
+ "2025-06-02T21:04:00",
+ "2025-06-02T22:06:00"
],
"xaxis": "x2",
"y": [
@@ -4691,7 +4724,8 @@
1.0112443778110944,
1.0083958020989505,
1.0062968515742128,
- 1.0356821589205396
+ 1.0262368815592204,
+ 1.0325337331334332
],
"yaxis": "y2"
},
@@ -4710,12 +4744,13 @@
"name": "SOL-USDT BUY CLOSE",
"showlegend": true,
"text": [
- "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 14:37:00
Normalized Price: 0.9999
Actual Price: $153.70",
- "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 15:41:00
Normalized Price: 0.9940
Actual Price: $153.10",
- "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 17:01:00
Normalized Price: 0.9948
Actual Price: $153.07",
- "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 17:17:00
Normalized Price: 0.9920
Actual Price: $153.09",
- "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 17:35:00
Normalized Price: 0.9936
Actual Price: $152.99",
- "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 22:28:00
Normalized Price: 1.0171
Actual Price: $156.75"
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 14:37:00
Normalized Price: 0.9999
Actual Price: $154.00",
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 15:41:00
Normalized Price: 0.9940
Actual Price: $153.08",
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 17:01:00
Normalized Price: 0.9948
Actual Price: $153.21",
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 17:17:00
Normalized Price: 0.9920
Actual Price: $152.78",
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 17:35:00
Normalized Price: 0.9936
Actual Price: $153.03",
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 21:04:00
Normalized Price: 1.0046
Actual Price: $154.72",
+ "SOL-USDT BUY CLOSE CLOSE
Time: 2025-06-02 22:06:00
Normalized Price: 1.0118
Actual Price: $155.83"
],
"type": "scatter",
"x": [
@@ -4724,7 +4759,8 @@
"2025-06-02T17:01:00",
"2025-06-02T17:17:00",
"2025-06-02T17:35:00",
- "2025-06-02T22:28:00"
+ "2025-06-02T21:04:00",
+ "2025-06-02T22:06:00"
],
"xaxis": "x2",
"y": [
@@ -4733,7 +4769,8 @@
0.9948055321083048,
0.9920135056165185,
0.9936367768326733,
- 1.0171417440425947
+ 1.0046100902538797,
+ 1.011817414453607
],
"yaxis": "y2"
},
@@ -4748,15 +4785,18 @@
"name": "ADA-USDT SELL OPEN",
"showlegend": true,
"text": [
- "ADA-USDT SELL OPEN OPEN
Time: 2025-06-02 18:02:00
Normalized Price: 1.0106
Actual Price: $0.67"
+ "ADA-USDT SELL OPEN OPEN
Time: 2025-06-02 18:02:00
Normalized Price: 1.0106
Actual Price: $0.67",
+ "ADA-USDT SELL OPEN OPEN
Time: 2025-06-02 21:33:00
Normalized Price: 1.0223
Actual Price: $0.68"
],
"type": "scatter",
"x": [
- "2025-06-02T18:02:00"
+ "2025-06-02T18:02:00",
+ "2025-06-02T21:33:00"
],
"xaxis": "x2",
"y": [
- 1.0106446776611695
+ 1.0106446776611695,
+ 1.0223388305847074
],
"yaxis": "y2"
},
@@ -4771,15 +4811,18 @@
"name": "SOL-USDT BUY OPEN",
"showlegend": true,
"text": [
- "SOL-USDT BUY OPEN OPEN
Time: 2025-06-02 18:02:00
Normalized Price: 0.9973
Actual Price: $153.64"
+ "SOL-USDT BUY OPEN OPEN
Time: 2025-06-02 18:02:00
Normalized Price: 0.9973
Actual Price: $153.59",
+ "SOL-USDT BUY OPEN OPEN
Time: 2025-06-02 21:33:00
Normalized Price: 1.0032
Actual Price: $154.51"
],
"type": "scatter",
"x": [
- "2025-06-02T18:02:00"
+ "2025-06-02T18:02:00",
+ "2025-06-02T21:33:00"
],
"xaxis": "x2",
"y": [
- 0.99727290435686
+ 0.99727290435686,
+ 1.0032465424323096
],
"yaxis": "y2"
},
@@ -4798,15 +4841,18 @@
"name": "ADA-USDT BUY CLOSE",
"showlegend": true,
"text": [
- "ADA-USDT BUY CLOSE CLOSE
Time: 2025-06-02 18:06:00
Normalized Price: 1.0114
Actual Price: $0.67"
+ "ADA-USDT BUY CLOSE CLOSE
Time: 2025-06-02 18:06:00
Normalized Price: 1.0114
Actual Price: $0.67",
+ "ADA-USDT BUY CLOSE CLOSE
Time: 2025-06-02 21:40:00
Normalized Price: 1.0244
Actual Price: $0.68"
],
"type": "scatter",
"x": [
- "2025-06-02T18:06:00"
+ "2025-06-02T18:06:00",
+ "2025-06-02T21:40:00"
],
"xaxis": "x2",
"y": [
- 1.0113943028485757
+ 1.0113943028485757,
+ 1.0244377811094452
],
"yaxis": "y2"
},
@@ -4825,15 +4871,18 @@
"name": "SOL-USDT SELL CLOSE",
"showlegend": true,
"text": [
- "SOL-USDT SELL CLOSE CLOSE
Time: 2025-06-02 18:06:00
Normalized Price: 0.9986
Actual Price: $153.84"
+ "SOL-USDT SELL CLOSE CLOSE
Time: 2025-06-02 18:06:00
Normalized Price: 0.9986
Actual Price: $153.79",
+ "SOL-USDT SELL CLOSE CLOSE
Time: 2025-06-02 21:40:00
Normalized Price: 1.0059
Actual Price: $154.92"
],
"type": "scatter",
"x": [
- "2025-06-02T18:06:00"
+ "2025-06-02T18:06:00",
+ "2025-06-02T21:40:00"
],
"xaxis": "x2",
"y": [
- 0.9985715213297838
+ 0.9985715213297838,
+ 1.0059087072268034
],
"yaxis": "y2"
},
@@ -5529,11 +5578,12 @@
"2025-06-02T16:44:00.000000000",
"2025-06-02T17:06:00.000000000",
"2025-06-02T17:24:00.000000000",
- "2025-06-02T19:35:00.000000000"
+ "2025-06-02T19:35:00.000000000",
+ "2025-06-02T21:58:00.000000000"
],
"xaxis": "x3",
"y": {
- "bdata": "Iv32deCc5T9+HThnRGnlPwpoImx4euU/xSCwcmiR5T+MuWsJ+aDlP/2H9NvXgeU/",
+ "bdata": "ayv2l92T5T+6awn5oGflP4EExY8xd+U/AG+BBMWP5T8EVg4tsp3lPznWxW00gOU/24r9Zffk5T8=",
"dtype": "f8"
},
"yaxis": "y3"
@@ -5553,11 +5603,12 @@
"showlegend": true,
"type": "scatter",
"x": [
- "2025-06-02T18:06:00.000000000"
+ "2025-06-02T18:06:00.000000000",
+ "2025-06-02T21:40:00.000000000"
],
"xaxis": "x3",
"y": {
- "bdata": "845TdCSX5T8=",
+ "bdata": "ETY8vVKW5T/oaiv2l93lPw==",
"dtype": "f8"
},
"yaxis": "y3"
@@ -5573,11 +5624,12 @@
"showlegend": true,
"type": "scatter",
"x": [
- "2025-06-02T18:02:00.000000000"
+ "2025-06-02T18:02:00.000000000",
+ "2025-06-02T21:33:00.000000000"
],
"xaxis": "x3",
"y": {
- "bdata": "ayv2l92T5T8=",
+ "bdata": "p3nHKTqS5T+KjuTyH9LlPw==",
"dtype": "f8"
},
"yaxis": "y3"
@@ -5602,11 +5654,12 @@
"2025-06-02T17:01:00.000000000",
"2025-06-02T17:17:00.000000000",
"2025-06-02T17:35:00.000000000",
- "2025-06-02T22:28:00.000000000"
+ "2025-06-02T21:04:00.000000000",
+ "2025-06-02T22:06:00.000000000"
],
"xaxis": "x3",
"y": {
- "bdata": "eAskKH6M5T94CyQofozlP02EDU+vlOU/ayv2l92T5T+wcmiR7XzlP+kmMQisHOY/",
+ "bdata": "ETY8vVKW5T9aZDvfT43lPy/dJAaBleU/Z0Rpb/CF5T8KaCJseHrlP4GVQ4ts5+U/mSoYldQJ5j8=",
"dtype": "f8"
},
"yaxis": "y3"
@@ -6298,11 +6351,12 @@
"showlegend": true,
"type": "scatter",
"x": [
- "2025-06-02T18:02:00.000000000"
+ "2025-06-02T18:02:00.000000000",
+ "2025-06-02T21:33:00.000000000"
],
"xaxis": "x4",
"y": {
- "bdata": "FK5H4Xo0Y0A=",
+ "bdata": "exSuR+EyY0C4HoXrUVBjQA==",
"dtype": "f8"
},
"yaxis": "y4"
@@ -6327,11 +6381,12 @@
"2025-06-02T17:01:00.000000000",
"2025-06-02T17:17:00.000000000",
"2025-06-02T17:35:00.000000000",
- "2025-06-02T22:28:00.000000000"
+ "2025-06-02T21:04:00.000000000",
+ "2025-06-02T22:06:00.000000000"
],
"xaxis": "x4",
"y": {
- "bdata": "ZmZmZmY2Y0AzMzMzMyNjQArXo3A9ImNAexSuR+EiY0BI4XoUrh9jQAAAAAAAmGNA",
+ "bdata": "AAAAAABAY0DD9ShcjyJjQB+F61G4JmNAKVyPwvUYY0ApXI/C9SBjQNejcD0KV2NAw/UoXI96Y0A=",
"dtype": "f8"
},
"yaxis": "y4"
@@ -6352,11 +6407,12 @@
"2025-06-02T16:44:00.000000000",
"2025-06-02T17:06:00.000000000",
"2025-06-02T17:24:00.000000000",
- "2025-06-02T19:35:00.000000000"
+ "2025-06-02T19:35:00.000000000",
+ "2025-06-02T21:58:00.000000000"
],
"xaxis": "x4",
"y": {
- "bdata": "CtejcD1KY0D2KFyPwgVjQLgehetREGNAKVyPwvUgY0BmZmZmZjZjQFyPwvUoBGNA",
+ "bdata": "FK5H4XpEY0CkcD0K1wNjQNejcD0KD2NAzczMzMwcY0BSuB6F6zFjQEjhehSu/2JA4XoUrkdpY0A=",
"dtype": "f8"
},
"yaxis": "y4"
@@ -6376,11 +6432,12 @@
"showlegend": true,
"type": "scatter",
"x": [
- "2025-06-02T18:06:00.000000000"
+ "2025-06-02T18:06:00.000000000",
+ "2025-06-02T21:40:00.000000000"
],
"xaxis": "x4",
"y": {
- "bdata": "exSuR+E6Y0A=",
+ "bdata": "4XoUrkc5Y0A9CtejcF1jQA==",
"dtype": "f8"
},
"yaxis": "y4"
@@ -7391,9 +7448,9 @@
},
"text/html": [
"