outstanding positions bug fix

This commit is contained in:
Oleg Sheynin 2025-07-15 00:10:46 +00:00
parent 94ffb32f50
commit 80cf1b60ef
5 changed files with 166 additions and 99 deletions

View File

@ -2,7 +2,7 @@
"security_type": "EQUITY", "security_type": "EQUITY",
"data_directory": "./data/equity", "data_directory": "./data/equity",
"datafiles": [ "datafiles": [
"20250605.mktdata.ohlcv.db", "20250606.mktdata.ohlcv.db",
], ],
"db_table_name": "md_1min_bars", "db_table_name": "md_1min_bars",
"exchange_id": "ALPACA", "exchange_id": "ALPACA",

View File

@ -276,25 +276,27 @@ class SlidingFit(PairsTradingFitMethod):
if len(pair.training_df_) < training_minutes: if len(pair.training_df_) < training_minutes:
print( print(
f"{pair}: {self.curr_training_start_idx_} Not enough training data. Completing the job." f"{pair}: current offset={self.curr_training_start_idx_}"
) f" * Training data length={len(pair.training_df_)} < {training_minutes}"
if pair.user_data_["state"] == PairState.OPEN: " * Not enough training data. Completing the job."
print(
f"{pair}: {self.curr_training_start_idx_} Position is not closed."
)
# outstanding positions
# last_row_index = self.curr_training_start_idx_ + training_minutes
if pair.predicted_df_ is not None:
bt_result.handle_outstanding_position(
pair=pair,
pair_result_df=pair.predicted_df_,
last_row_index=0,
open_side_a=pair.user_data_["open_side_a"],
open_side_b=pair.user_data_["open_side_b"],
open_px_a=pair.user_data_["open_px_a"],
open_px_b=pair.user_data_["open_px_b"],
open_tstamp=pair.user_data_["open_tstamp"],
) )
# if pair.user_data_["state"] == PairState.OPEN:
# print(
# f"{pair}: {self.curr_training_start_idx_} Position is not closed."
# )
# # outstanding positions
# # last_row_index = self.curr_training_start_idx_ + training_minutes
# if pair.predicted_df_ is not None:
# bt_result.handle_outstanding_position(
# pair=pair,
# pair_result_df=pair.predicted_df_,
# last_row_index=0,
# open_side_a=pair.user_data_["open_side_a"],
# open_side_b=pair.user_data_["open_side_b"],
# open_px_a=pair.user_data_["open_px_a"],
# open_px_b=pair.user_data_["open_px_b"],
# open_tstamp=pair.user_data_["open_tstamp"],
# )
break break
try: try:
@ -367,6 +369,25 @@ class SlidingFit(PairsTradingFitMethod):
pair.add_trades(close_trades) pair.add_trades(close_trades)
pair.user_data_["state"] = PairState.CLOSED pair.user_data_["state"] = PairState.CLOSED
# Outstanding positions
if pair.user_data_["state"] == PairState.OPEN:
print(
f"{pair}: *** Position is NOT CLOSED. ***"
)
# outstanding positions
# last_row_index = self.curr_training_start_idx_ + training_minutes
if pair.predicted_df_ is not None:
bt_result.handle_outstanding_position(
pair=pair,
pair_result_df=pair.predicted_df_,
last_row_index=0,
open_side_a=pair.user_data_["open_side_a"],
open_side_b=pair.user_data_["open_side_b"],
open_px_a=pair.user_data_["open_px_a"],
open_px_b=pair.user_data_["open_px_b"],
open_tstamp=pair.user_data_["open_tstamp"],
)
def _get_open_trades( def _get_open_trades(
self, pair: TradingPair, row: pd.Series, open_threshold: float self, pair: TradingPair, row: pd.Series, open_threshold: float
) -> Optional[pd.DataFrame]: ) -> Optional[pd.DataFrame]:
@ -386,15 +407,15 @@ class SlidingFit(PairsTradingFitMethod):
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 # Ensure scalars for handle_outstanding_position
if isinstance(open_px_a, pd.Series): # if isinstance(open_px_a, pd.Series):
open_px_a = open_px_a.iloc[0] # open_px_a = open_px_a.iloc[0]
if isinstance(open_px_b, pd.Series): # if isinstance(open_px_b, pd.Series):
open_px_b = open_px_b.iloc[0] # open_px_b = open_px_b.iloc[0]
if isinstance(open_tstamp, pd.Series): # if isinstance(open_tstamp, pd.Series):
open_tstamp = open_tstamp.iloc[0] # open_tstamp = open_tstamp.iloc[0]
open_px_a = float(open_px_a) # open_px_a = float(open_px_a)
open_px_b = float(open_px_b) # open_px_b = float(open_px_b)
open_tstamp = pd.Timestamp(open_tstamp) # open_tstamp = pd.Timestamp(open_tstamp)
if open_scaled_disequilibrium < open_threshold: if open_scaled_disequilibrium < open_threshold:
return None return None

View File

@ -526,6 +526,8 @@ class BacktestResult:
day_return = 0 day_return = 0
print(f"\n--- {filename} ---") print(f"\n--- {filename} ---")
self.outstanding_positions = data["outstanding_positions"]
# Process each pair # Process each pair
for pair, symbols in data["trades"].items(): for pair, symbols in data["trades"].items():
pair_return = 0 pair_return = 0

File diff suppressed because one or more lines are too long

View File

@ -226,7 +226,10 @@ def main() -> None:
# Store results with file name as key # Store results with file name as key
filename = os.path.basename(datafile) filename = os.path.basename(datafile)
all_results[filename] = {"trades": bt_results.trades.copy()} all_results[filename] = {
"trades": bt_results.trades.copy(),
"outstanding_positions": bt_results.outstanding_positions.copy(),
}
# Store results in database # Store results in database
if args.result_db.upper() != "NONE": if args.result_db.upper() != "NONE":