new strategies

This commit is contained in:
2025-10-25 21:51:25 +02:00
parent 76a858a7df
commit 541a71d2a6
6 changed files with 291 additions and 52 deletions

View File

@ -9,10 +9,13 @@ import schedule
import sqlite3
import pandas as pd
from datetime import datetime, timezone
import importlib
from logging_utils import setup_logging
# --- Using the new high-performance WebSocket utility for live prices ---
from live_market_utils import start_live_feed
# --- Import the base class for type hinting (optional but good practice) ---
from strategies.base_strategy import BaseStrategy
# --- Configuration ---
WATCHED_COINS = ["BTC", "ETH", "SOL", "BNB", "HYPE", "ASTER", "ZEC", "PUMP", "SUI"]
@ -108,21 +111,70 @@ def market_cap_fetcher_scheduler():
def run_strategy(strategy_name: str, config: dict):
"""Target function to run a strategy, redirecting its output to a log file."""
log_file = os.path.join(LOGS_DIR, f"strategy_{strategy_name}.log")
script_name = config['script']
command = [sys.executable, script_name, "--name", strategy_name, "--log-level", "normal"]
"""
This function BECOMES the strategy runner. It is executed as a separate
process by multiprocessing.
"""
# These imports only happen in the new, lightweight process
import importlib
import os
import sys
import time
import logging
from logging_utils import setup_logging
from strategies.base_strategy import BaseStrategy
# --- Setup logging to file for this specific process ---
log_file_path = os.path.join(LOGS_DIR, f"strategy_{strategy_name}.log")
try:
# Redirect stdout and stderr of this process to its log file
sys.stdout = open(log_file_path, 'a')
sys.stderr = sys.stdout
except Exception as e:
print(f"Failed to open log file for {strategy_name}: {e}")
# Setup logging *within this process*
setup_logging('normal', f"Strategy-{strategy_name}")
# --- Main resilient loop (was previously in main_app) ---
while True:
try:
with open(log_file, 'a') as f:
f.write(f"\n--- Starting strategy '{strategy_name}' at {datetime.now()} ---\n")
subprocess.run(command, check=True, stdout=f, stderr=subprocess.STDOUT)
except (subprocess.CalledProcessError, Exception) as e:
with open(log_file, 'a') as f:
f.write(f"\n--- PROCESS ERROR at {datetime.now()} ---\n")
f.write(f"Strategy '{strategy_name}' failed: {e}. Restarting...\n")
logging.info(f"--- Starting strategy '{strategy_name}' ---")
# 1. Load the strategy class
if 'class' not in config:
logging.error(f"Strategy config for '{strategy_name}' is missing the 'class' key. Exiting.")
return
module_path, class_name = config['class'].rsplit('.', 1)
module = importlib.import_module(module_path)
StrategyClass = getattr(module, class_name)
strategy = StrategyClass(strategy_name, config['parameters']) # Log level is now handled here
# 2. Run the strategy's logic loop
logging.info(f"Starting main logic loop for {strategy.coin} on {strategy.timeframe}.")
while True:
df = strategy.load_data()
if df.empty:
logging.warning("No data loaded. Waiting 1 minute...")
time.sleep(60)
continue
strategy.calculate_signals_and_state(df.copy())
strategy._save_status()
logging.info(f"Current Signal: {strategy.current_signal}")
time.sleep(60) # Simple 1-minute wait
except KeyboardInterrupt:
logging.info("Strategy process stopping.")
return # Exit the outer loop on Ctrl+C
except Exception as e:
logging.error(f"Strategy '{strategy_name}' failed: {e}", exc_info=True)
logging.info("Restarting strategy in 10 seconds...")
time.sleep(10)
def run_trade_executor():
"""Target function to run the trade_executor.py script in a resilient loop."""
log_file = os.path.join(LOGS_DIR, "trade_executor.log")
@ -207,10 +259,22 @@ class MainApp:
left_table_lines.append(f"{'#':<2} | {'Coin':^6} | {'Live Price':>10} | {'Market Cap':>15} |")
left_table_lines.append("-" * left_table_width)
for i, coin in enumerate(self.watched_coins, 1):
price = self.prices.get(coin, "Loading...")
price_str = self.prices.get(coin, "Loading...")
# Format the price string
try:
price_float = float(price_str)
if price_float < 1:
price_str = f"{price_float:>10.6f}"
elif price_float < 100:
price_str = f"{price_float:>10.4f}"
else:
price_str = f"{price_float:>10.2f}"
except (ValueError, TypeError):
price_str = f"{'Loading...':>10}"
market_cap = self.market_caps.get(coin)
formatted_mc = format_market_cap(market_cap)
left_table_lines.append(f"{i:<2} | {coin:^6} | {price:>10} | {formatted_mc:>15} |")
left_table_lines.append(f"{i:<2} | {coin:^6} | {price_str} | {formatted_mc:>15} |")
left_table_lines.append("-" * left_table_width)
right_table_lines = ["--- Strategy Status ---"]
@ -234,7 +298,7 @@ class MainApp:
timeframe = config_params.get('timeframe', 'N/A')
size = config_params.get('size', 'N/A')
other_params = {k: v for k, v in config_params.items() if k not in ['coin', 'timeframe', 'size']}
other_params = {k: v for k, v in config.get('parameters', {}).items() if k not in ['coin', 'timeframe', 'size']}
params_str = ", ".join([f"{k}={v}" for k, v in other_params.items()])
right_table_lines.append(f"{i:^2} | {name:<25} | {coin:^6} | {signal:^8} | {price_display:>12} | {last_change_display:>17} | {timeframe:^5} | {size:>8} | {params_str:<45} |")
right_table_lines.append("-" * right_table_width)
@ -338,8 +402,9 @@ if __name__ == "__main__":
for name, config in strategy_configs.items():
if config.get("enabled", False):
if not os.path.exists(config['script']):
logging.error(f"Strategy script '{config['script']}' for '{name}' not found. Skipping.")
# --- FIX: Check for the 'class' key, not the 'script' key ---
if 'class' not in config:
logging.error(f"Strategy '{name}' is missing 'class' key. Skipping.")
continue
proc = multiprocessing.Process(target=run_strategy, args=(name, config), daemon=True)
processes[f"Strategy: {name}"] = proc