Compare commits
No commits in common. "35a1cd748e53ad5c939c796a80d89bef57ec53d5" and "b24285802a7adf1851c2c23b6181c93e55430526" have entirely different histories.
35a1cd748e
...
b24285802a
@ -7,6 +7,16 @@
|
|||||||
"db_table_name": "md_1min_bars",
|
"db_table_name": "md_1min_bars",
|
||||||
"exchange_id": "BNBSPOT",
|
"exchange_id": "BNBSPOT",
|
||||||
"instrument_id_pfx": "PAIR-",
|
"instrument_id_pfx": "PAIR-",
|
||||||
|
# "instruments": [
|
||||||
|
# "BTC-USDT",
|
||||||
|
# "BCH-USDT",
|
||||||
|
# "ETH-USDT",
|
||||||
|
# "LTC-USDT",
|
||||||
|
# "XRP-USDT",
|
||||||
|
# "ADA-USDT",
|
||||||
|
# "SOL-USDT",
|
||||||
|
# "DOT-USDT"
|
||||||
|
# ],
|
||||||
"trading_hours": {
|
"trading_hours": {
|
||||||
"begin_session": "00:00:00",
|
"begin_session": "00:00:00",
|
||||||
"end_session": "23:59:00",
|
"end_session": "23:59:00",
|
||||||
@ -19,5 +29,5 @@
|
|||||||
"dis-equilibrium_close_trshld": 0.5,
|
"dis-equilibrium_close_trshld": 0.5,
|
||||||
"training_minutes": 120,
|
"training_minutes": 120,
|
||||||
"funding_per_pair": 2000.0,
|
"funding_per_pair": 2000.0,
|
||||||
"fit_method_class": "pt_trading.fit_methods.SlidingFit"
|
"fit_method_class": "pt_trading.fit_methods.StaticFit"
|
||||||
}
|
}
|
||||||
@ -3,6 +3,7 @@ from enum import Enum
|
|||||||
from typing import Dict, Optional, cast
|
from typing import Dict, Optional, cast
|
||||||
|
|
||||||
import pandas as pd # type: ignore[import]
|
import pandas as pd # type: ignore[import]
|
||||||
|
|
||||||
from pt_trading.results import BacktestResult
|
from pt_trading.results import BacktestResult
|
||||||
from pt_trading.trading_pair import TradingPair
|
from pt_trading.trading_pair import TradingPair
|
||||||
|
|
||||||
@ -63,17 +64,6 @@ class StaticFit(PairsTradingFitMethod):
|
|||||||
colname_a, colname_b = pair.colnames()
|
colname_a, colname_b = pair.colnames()
|
||||||
|
|
||||||
predicted_df = pair.predicted_df_
|
predicted_df = pair.predicted_df_
|
||||||
if predicted_df is None:
|
|
||||||
# Return empty DataFrame with correct columns and dtypes
|
|
||||||
return pd.DataFrame(columns=self.TRADES_COLUMNS).astype({
|
|
||||||
"time": "datetime64[ns]",
|
|
||||||
"action": "string",
|
|
||||||
"symbol": "string",
|
|
||||||
"price": "float64",
|
|
||||||
"disequilibrium": "float64",
|
|
||||||
"scaled_disequilibrium": "float64",
|
|
||||||
"pair": "object"
|
|
||||||
})
|
|
||||||
|
|
||||||
open_threshold = config["dis-equilibrium_open_trshld"]
|
open_threshold = config["dis-equilibrium_open_trshld"]
|
||||||
close_threshold = config["dis-equilibrium_close_trshld"]
|
close_threshold = config["dis-equilibrium_close_trshld"]
|
||||||
@ -106,11 +96,11 @@ class StaticFit(PairsTradingFitMethod):
|
|||||||
break
|
break
|
||||||
|
|
||||||
open_row = predicted_df.loc[open_row_index]
|
open_row = predicted_df.loc[open_row_index]
|
||||||
open_px_a = predicted_df.at[open_row_index, f"{colname_a}"]
|
open_tstamp = open_row["tstamp"]
|
||||||
open_px_b = predicted_df.at[open_row_index, f"{colname_b}"]
|
|
||||||
open_tstamp = predicted_df.at[open_row_index, "tstamp"]
|
|
||||||
open_disequilibrium = open_row["disequilibrium"]
|
open_disequilibrium = open_row["disequilibrium"]
|
||||||
open_scaled_disequilibrium = open_row["scaled_disequilibrium"]
|
open_scaled_disequilibrium = open_row["scaled_disequilibrium"]
|
||||||
|
open_px_a = open_row[f"{colname_a}"]
|
||||||
|
open_px_b = open_row[f"{colname_b}"]
|
||||||
|
|
||||||
abs_beta = abs(beta[1])
|
abs_beta = abs(beta[1])
|
||||||
pred_px_b = predicted_df.loc[open_row_index][f"{colname_b}_pred"]
|
pred_px_b = predicted_df.loc[open_row_index][f"{colname_b}_pred"]
|
||||||
@ -139,9 +129,9 @@ class StaticFit(PairsTradingFitMethod):
|
|||||||
last_row_index=last_row_index,
|
last_row_index=last_row_index,
|
||||||
open_side_a=open_side_a,
|
open_side_a=open_side_a,
|
||||||
open_side_b=open_side_b,
|
open_side_b=open_side_b,
|
||||||
open_px_a=float(open_px_a),
|
open_px_a=open_px_a,
|
||||||
open_px_b=float(open_px_b),
|
open_px_b=open_px_b,
|
||||||
open_tstamp=pd.Timestamp(open_tstamp),
|
open_tstamp=open_tstamp,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Return only open trades (no close trades)
|
# Return only open trades (no close trades)
|
||||||
@ -215,21 +205,11 @@ class StaticFit(PairsTradingFitMethod):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add tuples to data frame with explicit dtypes to avoid concatenation warnings
|
# Add tuples to data frame
|
||||||
df = pd.DataFrame(
|
return pd.DataFrame(
|
||||||
trd_signal_tuples,
|
trd_signal_tuples,
|
||||||
columns=self.TRADES_COLUMNS,
|
columns=self.TRADES_COLUMNS, # type: ignore
|
||||||
)
|
)
|
||||||
# Ensure consistent dtypes
|
|
||||||
return df.astype({
|
|
||||||
"time": "datetime64[ns]",
|
|
||||||
"action": "string",
|
|
||||||
"symbol": "string",
|
|
||||||
"price": "float64",
|
|
||||||
"disequilibrium": "float64",
|
|
||||||
"scaled_disequilibrium": "float64",
|
|
||||||
"pair": "object"
|
|
||||||
})
|
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
pass
|
pass
|
||||||
@ -252,16 +232,7 @@ class SlidingFit(PairsTradingFitMethod):
|
|||||||
print(f"***{pair}*** STARTING....")
|
print(f"***{pair}*** STARTING....")
|
||||||
|
|
||||||
pair.user_data_["state"] = PairState.INITIAL
|
pair.user_data_["state"] = PairState.INITIAL
|
||||||
# Initialize trades DataFrame with proper dtypes to avoid concatenation warnings
|
pair.user_data_["trades"] = pd.DataFrame(columns=self.TRADES_COLUMNS)
|
||||||
pair.user_data_["trades"] = pd.DataFrame(columns=self.TRADES_COLUMNS).astype({
|
|
||||||
"time": "datetime64[ns]",
|
|
||||||
"action": "string",
|
|
||||||
"symbol": "string",
|
|
||||||
"price": "float64",
|
|
||||||
"disequilibrium": "float64",
|
|
||||||
"scaled_disequilibrium": "float64",
|
|
||||||
"pair": "object"
|
|
||||||
})
|
|
||||||
pair.user_data_["is_cointegrated"] = False
|
pair.user_data_["is_cointegrated"] = False
|
||||||
|
|
||||||
training_minutes = config["training_minutes"]
|
training_minutes = config["training_minutes"]
|
||||||
@ -284,7 +255,7 @@ class SlidingFit(PairsTradingFitMethod):
|
|||||||
)
|
)
|
||||||
# outstanding positions
|
# outstanding positions
|
||||||
# last_row_index = self.curr_training_start_idx_ + training_minutes
|
# last_row_index = self.curr_training_start_idx_ + training_minutes
|
||||||
if pair.predicted_df_ is not None:
|
|
||||||
bt_result.handle_outstanding_position(
|
bt_result.handle_outstanding_position(
|
||||||
pair=pair,
|
pair=pair,
|
||||||
pair_result_df=pair.predicted_df_,
|
pair_result_df=pair.predicted_df_,
|
||||||
@ -340,10 +311,7 @@ class SlidingFit(PairsTradingFitMethod):
|
|||||||
def _create_trading_signals(
|
def _create_trading_signals(
|
||||||
self, pair: TradingPair, config: Dict, bt_result: BacktestResult
|
self, pair: TradingPair, config: Dict, bt_result: BacktestResult
|
||||||
) -> None:
|
) -> None:
|
||||||
if pair.predicted_df_ is None:
|
assert pair.predicted_df_ is not None
|
||||||
print(f"{pair.market_data_.iloc[0]['tstamp']} {pair}: No predicted data")
|
|
||||||
return
|
|
||||||
|
|
||||||
open_threshold = config["dis-equilibrium_open_trshld"]
|
open_threshold = config["dis-equilibrium_open_trshld"]
|
||||||
close_threshold = config["dis-equilibrium_close_trshld"]
|
close_threshold = config["dis-equilibrium_close_trshld"]
|
||||||
for curr_predicted_row_idx in range(len(pair.predicted_df_)):
|
for curr_predicted_row_idx in range(len(pair.predicted_df_)):
|
||||||
@ -385,16 +353,6 @@ class SlidingFit(PairsTradingFitMethod):
|
|||||||
open_scaled_disequilibrium = open_row["scaled_disequilibrium"]
|
open_scaled_disequilibrium = open_row["scaled_disequilibrium"]
|
||||||
open_px_a = open_row[f"{colname_a}"]
|
open_px_a = open_row[f"{colname_a}"]
|
||||||
open_px_b = open_row[f"{colname_b}"]
|
open_px_b = open_row[f"{colname_b}"]
|
||||||
# Ensure scalars for handle_outstanding_position
|
|
||||||
if isinstance(open_px_a, pd.Series):
|
|
||||||
open_px_a = open_px_a.iloc[0]
|
|
||||||
if isinstance(open_px_b, pd.Series):
|
|
||||||
open_px_b = open_px_b.iloc[0]
|
|
||||||
if isinstance(open_tstamp, pd.Series):
|
|
||||||
open_tstamp = open_tstamp.iloc[0]
|
|
||||||
open_px_a = float(open_px_a)
|
|
||||||
open_px_b = float(open_px_b)
|
|
||||||
open_tstamp = pd.Timestamp(open_tstamp)
|
|
||||||
|
|
||||||
if open_scaled_disequilibrium < open_threshold:
|
if open_scaled_disequilibrium < open_threshold:
|
||||||
return None
|
return None
|
||||||
@ -444,21 +402,10 @@ class SlidingFit(PairsTradingFitMethod):
|
|||||||
pair,
|
pair,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
# Create DataFrame with explicit dtypes to avoid concatenation warnings
|
return pd.DataFrame(
|
||||||
df = pd.DataFrame(
|
|
||||||
trd_signal_tuples,
|
trd_signal_tuples,
|
||||||
columns=self.TRADES_COLUMNS,
|
columns=self.TRADES_COLUMNS, # type: ignore
|
||||||
)
|
)
|
||||||
# Ensure consistent dtypes
|
|
||||||
return df.astype({
|
|
||||||
"time": "datetime64[ns]",
|
|
||||||
"action": "string",
|
|
||||||
"symbol": "string",
|
|
||||||
"price": "float64",
|
|
||||||
"disequilibrium": "float64",
|
|
||||||
"scaled_disequilibrium": "float64",
|
|
||||||
"pair": "object"
|
|
||||||
})
|
|
||||||
|
|
||||||
def _get_close_trades(
|
def _get_close_trades(
|
||||||
self, pair: TradingPair, row: pd.Series, close_threshold: float
|
self, pair: TradingPair, row: pd.Series, close_threshold: float
|
||||||
@ -502,21 +449,11 @@ class SlidingFit(PairsTradingFitMethod):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add tuples to data frame with explicit dtypes to avoid concatenation warnings
|
# Add tuples to data frame
|
||||||
df = pd.DataFrame(
|
return pd.DataFrame(
|
||||||
trd_signal_tuples,
|
trd_signal_tuples,
|
||||||
columns=self.TRADES_COLUMNS,
|
columns=self.TRADES_COLUMNS, # type: ignore
|
||||||
)
|
)
|
||||||
# Ensure consistent dtypes
|
|
||||||
return df.astype({
|
|
||||||
"time": "datetime64[ns]",
|
|
||||||
"action": "string",
|
|
||||||
"symbol": "string",
|
|
||||||
"price": "float64",
|
|
||||||
"disequilibrium": "float64",
|
|
||||||
"scaled_disequilibrium": "float64",
|
|
||||||
"pair": "object"
|
|
||||||
})
|
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
self.curr_training_start_idx_ = 0
|
self.curr_training_start_idx_ = 0
|
||||||
|
|||||||
@ -41,12 +41,6 @@ def create_result_database(db_path: str) -> None:
|
|||||||
Create the SQLite database and required tables if they don't exist.
|
Create the SQLite database and required tables if they don't exist.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Create directory if it doesn't exist
|
|
||||||
db_dir = os.path.dirname(db_path)
|
|
||||||
if db_dir and not os.path.exists(db_dir):
|
|
||||||
os.makedirs(db_dir, exist_ok=True)
|
|
||||||
print(f"Created directory: {db_dir}")
|
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path)
|
conn = sqlite3.connect(db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
|||||||
@ -179,39 +179,10 @@ class TradingPair:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def add_trades(self, trades: pd.DataFrame) -> None:
|
def add_trades(self, trades: pd.DataFrame) -> None:
|
||||||
if self.user_data_["trades"] is None or len(self.user_data_["trades"]) == 0:
|
if self.user_data_["trades"] is None:
|
||||||
# If trades is empty or None, just assign the new trades directly
|
self.user_data_["trades"] = pd.DataFrame(trades)
|
||||||
self.user_data_["trades"] = trades.copy()
|
|
||||||
else:
|
else:
|
||||||
# Ensure both DataFrames have the same columns and dtypes before concatenation
|
self.user_data_["trades"] = pd.concat([self.user_data_["trades"], pd.DataFrame(trades)], ignore_index=True)
|
||||||
existing_trades = self.user_data_["trades"]
|
|
||||||
|
|
||||||
# If existing trades is empty, just assign the new trades
|
|
||||||
if len(existing_trades) == 0:
|
|
||||||
self.user_data_["trades"] = trades.copy()
|
|
||||||
else:
|
|
||||||
# Ensure both DataFrames have the same columns
|
|
||||||
if set(existing_trades.columns) != set(trades.columns):
|
|
||||||
# Add missing columns to trades with appropriate default values
|
|
||||||
for col in existing_trades.columns:
|
|
||||||
if col not in trades.columns:
|
|
||||||
if col == "time":
|
|
||||||
trades[col] = pd.Timestamp.now()
|
|
||||||
elif col in ["action", "symbol"]:
|
|
||||||
trades[col] = ""
|
|
||||||
elif col in ["price", "disequilibrium", "scaled_disequilibrium"]:
|
|
||||||
trades[col] = 0.0
|
|
||||||
elif col == "pair":
|
|
||||||
trades[col] = None
|
|
||||||
else:
|
|
||||||
trades[col] = None
|
|
||||||
|
|
||||||
# Concatenate with explicit dtypes to avoid warnings
|
|
||||||
self.user_data_["trades"] = pd.concat(
|
|
||||||
[existing_trades, trades],
|
|
||||||
ignore_index=True,
|
|
||||||
copy=False
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_trades(self) -> pd.DataFrame:
|
def get_trades(self) -> pd.DataFrame:
|
||||||
return self.user_data_["trades"] if "trades" in self.user_data_ else pd.DataFrame()
|
return self.user_data_["trades"] if "trades" in self.user_data_ else pd.DataFrame()
|
||||||
|
|||||||
@ -24,14 +24,11 @@ hjson>=3.0.2
|
|||||||
html5lib>=1.1
|
html5lib>=1.1
|
||||||
httplib2>=0.20.2
|
httplib2>=0.20.2
|
||||||
idna>=3.3
|
idna>=3.3
|
||||||
ipython>=8.18.1
|
|
||||||
ipywidgets>=8.1.1
|
|
||||||
ifaddr>=0.1.7
|
ifaddr>=0.1.7
|
||||||
IMDbPY>=2021.4.18
|
IMDbPY>=2021.4.18
|
||||||
ipykernel>=6.29.5
|
ipykernel>=6.29.5
|
||||||
jeepney>=0.7.1
|
jeepney>=0.7.1
|
||||||
jsonschema>=3.2.0
|
jsonschema>=3.2.0
|
||||||
jupyter>=1.0.0
|
|
||||||
keyring>=23.5.0
|
keyring>=23.5.0
|
||||||
launchpadlib>=1.10.16
|
launchpadlib>=1.10.16
|
||||||
lazr.restfulclient>=0.14.4
|
lazr.restfulclient>=0.14.4
|
||||||
@ -45,18 +42,15 @@ more-itertools>=8.10.0
|
|||||||
multidict>=6.0.4
|
multidict>=6.0.4
|
||||||
mypy>=0.942
|
mypy>=0.942
|
||||||
mypy-extensions>=0.4.3
|
mypy-extensions>=0.4.3
|
||||||
nbformat>=5.10.2
|
|
||||||
netaddr>=0.8.0
|
netaddr>=0.8.0
|
||||||
######### netifaces>=0.11.0
|
######### netifaces>=0.11.0
|
||||||
numpy>=1.26.4,<2.3.0
|
numpy>=1.26.4,<2.3.0
|
||||||
oauthlib>=3.2.0
|
oauthlib>=3.2.0
|
||||||
packaging>=23.1
|
packaging>=23.1
|
||||||
pandas>=2.2.3
|
|
||||||
pathspec>=0.11.1
|
pathspec>=0.11.1
|
||||||
pexpect>=4.8.0
|
pexpect>=4.8.0
|
||||||
Pillow>=9.0.1
|
Pillow>=9.0.1
|
||||||
platformdirs>=3.2.0
|
platformdirs>=3.2.0
|
||||||
plotly>=5.19.0
|
|
||||||
protobuf>=3.12.4
|
protobuf>=3.12.4
|
||||||
psutil>=5.9.0
|
psutil>=5.9.0
|
||||||
ptyprocess>=0.7.0
|
ptyprocess>=0.7.0
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user