gpt fix
This commit is contained in:
parent
316ce608b6
commit
6be64ebe03
@ -1,34 +1,35 @@
|
|||||||
|
from screener.user_input import get_interval_choice
|
||||||
import os
|
import os
|
||||||
import pandas as pd
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
import pandas as pd
|
||||||
from db.db_connection import create_client
|
from db.db_connection import create_client
|
||||||
from indicators.three_atr_ema import ThreeATREMAIndicator
|
|
||||||
from trading.position_calculator import PositionCalculator
|
from trading.position_calculator import PositionCalculator
|
||||||
from screener.t_sunnyband import get_stock_data
|
from screener.t_sunnyband import get_stock_data
|
||||||
|
from indicators.three_atr_ema import ThreeATREMAIndicator
|
||||||
|
|
||||||
def run_atr_ema_target_scanner(min_price: float, max_price: float, min_volume: int, portfolio_size: float = None):
|
def run_atr_ema_target_scanner(min_price: float, max_price: float, min_volume: int, portfolio_size: float = None):
|
||||||
print(f"\n🔍 Scanning for stocks ${min_price:.2f}-${max_price:.2f} with min volume {min_volume:,}")
|
print(f"\n🔍 Scanning for stocks ${min_price:.2f}-${max_price:.2f} with min volume {min_volume:,}")
|
||||||
|
|
||||||
# Set time range
|
interval = get_interval_choice()
|
||||||
end_date = datetime.now()
|
end_date = datetime.now()
|
||||||
start_date = end_date - timedelta(days=90) # Expanded from 30 to 90 days
|
start_date = end_date - timedelta(days=1) # Last trading day
|
||||||
market_days = pd.bdate_range(start=start_date.date(), end=end_date.date())
|
start_ts = int(start_date.timestamp() * 1e9) # Convert to nanoseconds
|
||||||
if len(market_days) < 50:
|
end_ts = int(end_date.timestamp() * 1e9)
|
||||||
start_date = end_date - timedelta(days=50*1.5) # Ensure 50 trading days coverage
|
|
||||||
start_ts = int(start_date.timestamp() * 1000000000)
|
|
||||||
end_ts = int(end_date.timestamp() * 1000000000)
|
|
||||||
|
|
||||||
client = create_client()
|
client = create_client()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Fetch stock prices within the defined range
|
|
||||||
query = f"""
|
query = f"""
|
||||||
WITH latest_data AS (
|
WITH latest_data AS (
|
||||||
SELECT
|
SELECT
|
||||||
ticker,
|
ticker,
|
||||||
argMax(close, window_start) AS last_close,
|
|
||||||
sum(volume) AS total_volume,
|
sum(volume) AS total_volume,
|
||||||
max(window_start) AS last_update
|
argMax(open, window_start) AS last_open,
|
||||||
|
argMax(close, window_start) AS last_close,
|
||||||
|
argMax(high, window_start) AS last_high,
|
||||||
|
argMax(low, window_start) AS last_low,
|
||||||
|
max(window_start) AS last_update,
|
||||||
|
sum(transactions) AS transaction_count
|
||||||
FROM stock_db.stock_prices
|
FROM stock_db.stock_prices
|
||||||
WHERE window_start BETWEEN {start_ts} AND {end_ts}
|
WHERE window_start BETWEEN {start_ts} AND {end_ts}
|
||||||
GROUP BY ticker
|
GROUP BY ticker
|
||||||
@ -37,93 +38,73 @@ def run_atr_ema_target_scanner(min_price: float, max_price: float, min_volume: i
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
ticker,
|
ticker,
|
||||||
last_close,
|
|
||||||
total_volume,
|
total_volume,
|
||||||
last_update
|
last_open,
|
||||||
|
last_close,
|
||||||
|
last_high,
|
||||||
|
last_low,
|
||||||
|
last_update,
|
||||||
|
transaction_count
|
||||||
FROM latest_data
|
FROM latest_data
|
||||||
ORDER BY ticker
|
ORDER BY ticker
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = client.query(query)
|
result = client.query(query)
|
||||||
stocks = [(row[0], row[1], row[2], row[3]) for row in result.result_rows]
|
stocks = result.result_rows
|
||||||
|
|
||||||
if not stocks:
|
if not stocks:
|
||||||
print("❌ No stocks found matching criteria.")
|
print("❌ No stocks found matching criteria.")
|
||||||
return
|
return
|
||||||
|
|
||||||
print("\n🔍 Verifying data availability...")
|
print(f"\n✅ Found {len(stocks)} stocks matching criteria")
|
||||||
valid_query = f"""
|
|
||||||
SELECT ticker
|
# **Correct column order as per ClickHouse output**
|
||||||
FROM (
|
columns = ["ticker", "volume", "open", "close", "high", "low", "window_start", "transactions"]
|
||||||
SELECT ticker, count() as cnt
|
df_stocks = pd.DataFrame(stocks, columns=columns)
|
||||||
FROM (
|
|
||||||
SELECT
|
# **Convert timestamps from nanoseconds to readable datetime**
|
||||||
ticker,
|
df_stocks["window_start"] = pd.to_datetime(df_stocks["window_start"], unit="ns")
|
||||||
toDate(window_start) as date
|
|
||||||
FROM stock_db.stock_prices
|
# Debugging: Check if columns exist
|
||||||
WHERE window_start BETWEEN {start_ts} AND {end_ts}
|
print("\n📊 Data Sample from ClickHouse Query:")
|
||||||
GROUP BY ticker, date
|
print(df_stocks.head())
|
||||||
)
|
|
||||||
GROUP BY ticker
|
|
||||||
HAVING count() >= 50
|
|
||||||
|
|
||||||
UNION ALL
|
|
||||||
|
|
||||||
SELECT ticker, count() as cnt
|
|
||||||
FROM stock_db.stock_prices_daily
|
|
||||||
WHERE date BETWEEN '{start_date.date()}' AND '{end_date.date()}'
|
|
||||||
GROUP BY ticker
|
|
||||||
HAVING cnt >= 50
|
|
||||||
)
|
|
||||||
GROUP BY ticker
|
|
||||||
HAVING sum(cnt) >= 50
|
|
||||||
"""
|
|
||||||
valid_result = client.query(valid_query)
|
|
||||||
valid_symbols = {row[0] for row in valid_result.result_rows}
|
|
||||||
qualified_stocks = [s for s in stocks if s[0] in valid_symbols]
|
|
||||||
|
|
||||||
# Enhanced validation check
|
|
||||||
for ticker in list(qualified_stocks):
|
|
||||||
test_df = get_stock_data(ticker[0], start_date, end_date, "1d")
|
|
||||||
if test_df.empty or len(test_df) < 50:
|
|
||||||
print(f"🚫 Removing {ticker[0]} - insufficient initial data")
|
|
||||||
qualified_stocks.remove(ticker)
|
|
||||||
|
|
||||||
print(f"\n✅ Found {len(qualified_stocks)} stocks with sufficient historical data")
|
|
||||||
|
|
||||||
indicator = ThreeATREMAIndicator()
|
indicator = ThreeATREMAIndicator()
|
||||||
calculator = PositionCalculator(portfolio_size, risk_percentage=1.0, stop_loss_percentage=7.0) if portfolio_size else None
|
calculator = PositionCalculator(portfolio_size, risk_percentage=1.0, stop_loss_percentage=7.0) if portfolio_size else None
|
||||||
bullish_signals = []
|
bullish_signals = []
|
||||||
|
|
||||||
for ticker, current_price, current_volume, last_update in stocks:
|
for _, row in df_stocks.iterrows():
|
||||||
|
ticker = row["ticker"]
|
||||||
|
current_price = row["close"]
|
||||||
|
current_volume = row["volume"]
|
||||||
|
last_update = row["window_start"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Validate interval and fetch data
|
df = get_stock_data(ticker, start_date, end_date, interval)
|
||||||
VALID_INTERVALS = ["1d", "5m", "15m", "30m", "1h", "4h", "1w"]
|
|
||||||
|
# **Check if DataFrame has expected columns**
|
||||||
try:
|
if df.empty:
|
||||||
df = get_stock_data(ticker, start_date, end_date, "1d")
|
print(f"⚠️ No data found for {ticker}. Skipping.")
|
||||||
if df.empty or len(df) < 50:
|
|
||||||
df = get_stock_data(ticker, start_date - timedelta(days=30), end_date, "1d") # Try wider range
|
|
||||||
if df.empty or len(df) < 50:
|
|
||||||
print(f"⚠️ {ticker}: No valid data in extended timeframe")
|
|
||||||
continue
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Data fetch failed for {ticker}: {str(e)[:100]}")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
results = indicator.calculate(df).dropna().tail(30) # Use only most recent valid data
|
missing_cols = [col for col in ["close", "open", "high", "low", "volume"] if col not in df.columns]
|
||||||
|
if missing_cols:
|
||||||
|
print(f"⚠️ {ticker} data is missing columns: {missing_cols}. Skipping.")
|
||||||
|
print(df.head()) # Debugging output
|
||||||
|
continue
|
||||||
|
|
||||||
|
results = indicator.calculate(df)
|
||||||
last_row = results.iloc[-1]
|
last_row = results.iloc[-1]
|
||||||
prev_row = results.iloc[-2]
|
prev_row = results.iloc[-2]
|
||||||
|
|
||||||
# Check if entry condition is met
|
|
||||||
bullish_entry = (
|
bullish_entry = (
|
||||||
last_row['close'] < last_row['ema'] and
|
last_row["close"] < last_row["ema"] and
|
||||||
prev_row['close'] <= prev_row['lower_band'] and
|
prev_row["close"] <= prev_row["lower_band"] and
|
||||||
last_row['close'] > prev_row['close']
|
last_row["close"] > prev_row["close"]
|
||||||
)
|
)
|
||||||
|
|
||||||
if bullish_entry:
|
if bullish_entry:
|
||||||
entry_price = last_row['close']
|
entry_price = last_row["close"]
|
||||||
target_1 = entry_price * 1.10 # 10% profit
|
target_1 = entry_price * 1.10 # 10% profit
|
||||||
target_2 = entry_price * 1.20 # 20% profit
|
target_2 = entry_price * 1.20 # 20% profit
|
||||||
|
|
||||||
@ -131,25 +112,25 @@ def run_atr_ema_target_scanner(min_price: float, max_price: float, min_volume: i
|
|||||||
trail_stop = None
|
trail_stop = None
|
||||||
trail_active = False
|
trail_active = False
|
||||||
|
|
||||||
if last_row['close'] >= last_row['upper_band']:
|
if last_row["close"] >= last_row["upper_band"]:
|
||||||
trail_active = True
|
trail_active = True
|
||||||
highest_price = max(results['high'].iloc[-5:]) # Last 5 days
|
highest_price = max(results["high"].iloc[-5:]) # Last 5 days
|
||||||
trail_stop = highest_price * 0.98 # 2% below high
|
trail_stop = highest_price * 0.98 # 2% below high
|
||||||
|
|
||||||
# Position sizing
|
# Position sizing
|
||||||
position = calculator.calculate_position_size(entry_price, target_2) if calculator else None
|
position = calculator.calculate_position_size(entry_price, target_2) if calculator else None
|
||||||
position_size = position['position_value'] if position else None
|
position_size = position["position_value"] if position else None
|
||||||
|
|
||||||
# Save signal
|
# Save signal
|
||||||
signal_data = {
|
signal_data = {
|
||||||
'ticker': ticker,
|
"ticker": ticker,
|
||||||
'entry_price': entry_price,
|
"entry_price": entry_price,
|
||||||
'target_1': target_1,
|
"target_1": target_1,
|
||||||
'target_2': target_2,
|
"target_2": target_2,
|
||||||
'volume': current_volume,
|
"volume": current_volume,
|
||||||
'last_update': datetime.fromtimestamp(last_update / 1000000000),
|
"last_update": last_update,
|
||||||
'trail_stop': trail_stop,
|
"trail_stop": trail_stop,
|
||||||
'position_size': position_size
|
"position_size": position_size
|
||||||
}
|
}
|
||||||
bullish_signals.append(signal_data)
|
bullish_signals.append(signal_data)
|
||||||
|
|
||||||
@ -165,13 +146,13 @@ def run_atr_ema_target_scanner(min_price: float, max_price: float, min_volume: i
|
|||||||
|
|
||||||
# Save results
|
# Save results
|
||||||
if bullish_signals:
|
if bullish_signals:
|
||||||
output_dir = 'reports'
|
output_dir = "reports"
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
output_file = f'{output_dir}/atr_ema_targets_{datetime.now().strftime("%Y%m%d_%H%M")}.csv'
|
output_file = f"{output_dir}/atr_ema_targets_{datetime.now().strftime('%Y%m%d_%H%M')}.csv"
|
||||||
pd.DataFrame(bullish_signals).to_csv(output_file, index=False)
|
pd.DataFrame(bullish_signals).to_csv(output_file, index=False)
|
||||||
print(f"\n📁 Saved bullish signals to {output_file}")
|
print(f"\n📁 Saved bullish signals to {output_file}")
|
||||||
else:
|
else:
|
||||||
print("❌ No bullish signals found.")
|
print("❌ No bullish signals found.")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Error during scan: {e}")
|
print(f"❌ Error during scan: {e}")
|
||||||
Loading…
Reference in New Issue
Block a user