new strategies
This commit is contained in:
97
main_app.py
97
main_app.py
@ -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
|
||||
|
||||
Reference in New Issue
Block a user