refactor: Update Sunny Bands scanner to match ATR EMA pattern and focus on bullish signals
This commit is contained in:
parent
15304106ac
commit
c610bc7d4a
@ -10,6 +10,44 @@ from utils.data_utils import get_stock_data, validate_signal_date, print_signal,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def check_entry_signal(df: pd.DataFrame) -> list:
|
||||||
|
"""
|
||||||
|
Check for entry signals based on Sunny Bands strategy throughout the date range
|
||||||
|
|
||||||
|
Args:
|
||||||
|
df (pd.DataFrame): DataFrame with price data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: List of tuples (signal, date, signal_data) for each signal found
|
||||||
|
"""
|
||||||
|
if len(df) < 2: # Need at least 2 bars for comparison
|
||||||
|
return []
|
||||||
|
|
||||||
|
sunny = SunnyBands()
|
||||||
|
results = sunny.calculate(df)
|
||||||
|
|
||||||
|
if len(results) < 2:
|
||||||
|
return []
|
||||||
|
|
||||||
|
signals = []
|
||||||
|
|
||||||
|
# Start from index 1 to compare with previous
|
||||||
|
for i in range(1, len(df)):
|
||||||
|
current = df.iloc[i]
|
||||||
|
current_bands = results.iloc[i]
|
||||||
|
|
||||||
|
# Check for bullish signal
|
||||||
|
if current_bands['bullish_signal']:
|
||||||
|
signal_data = {
|
||||||
|
'price': current['close'],
|
||||||
|
'upper_band': current_bands['upper_band'],
|
||||||
|
'lower_band': current_bands['lower_band'],
|
||||||
|
'dma': current_bands['dma']
|
||||||
|
}
|
||||||
|
signals.append((True, current['date'], signal_data))
|
||||||
|
|
||||||
|
return signals
|
||||||
|
|
||||||
def get_valid_tickers(min_price: float, max_price: float, min_volume: int, interval: str) -> list:
|
def get_valid_tickers(min_price: float, max_price: float, min_volume: int, interval: str) -> list:
|
||||||
"""Get tickers that meet the price and volume criteria"""
|
"""Get tickers that meet the price and volume criteria"""
|
||||||
client = create_client()
|
client = create_client()
|
||||||
@ -235,58 +273,37 @@ def run_sunny_scanner(min_price: float, max_price: float, min_volume: int, portf
|
|||||||
if df.empty or len(df) < 50: # Need at least 50 bars for the indicator
|
if df.empty or len(df) < 50: # Need at least 50 bars for the indicator
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Calculate SunnyBands
|
# Check for signals throughout the date range
|
||||||
results = sunny.calculate(df)
|
signals = check_entry_signal(df)
|
||||||
|
for signal, signal_date, signal_data in signals:
|
||||||
# Check for signals
|
|
||||||
if results['bullish_signal'].iloc[-1]:
|
|
||||||
target_price = results['upper_band'].iloc[-1]
|
|
||||||
|
|
||||||
if calculator:
|
if calculator:
|
||||||
try:
|
try:
|
||||||
position = calculator.calculate_position_size(
|
position = calculator.calculate_position_size(
|
||||||
entry_price=current_price,
|
entry_price=signal_data['price'],
|
||||||
target_price=target_price
|
target_price=signal_data['upper_band']
|
||||||
)
|
)
|
||||||
if position['shares'] > 0:
|
if position['shares'] > 0:
|
||||||
# Update signal data with proper stop loss calculation
|
entry_data = {
|
||||||
# Get signal date from latest data point
|
|
||||||
signal_date = df.iloc[-1]['date']
|
|
||||||
signal_data = {
|
|
||||||
'ticker': ticker,
|
'ticker': ticker,
|
||||||
'entry_price': current_price,
|
'entry_price': signal_data['price'],
|
||||||
'target_price': target_price,
|
'target_price': signal_data['upper_band'],
|
||||||
'signal_date': signal_date,
|
'signal_date': signal_date,
|
||||||
'volume': current_volume,
|
'volume': current_volume,
|
||||||
'last_update': datetime.fromtimestamp(last_update/1000000000),
|
'last_update': datetime.fromtimestamp(last_update/1000000000),
|
||||||
'shares': position['shares'],
|
'shares': position['shares'],
|
||||||
'position_size': position['position_value'],
|
'position_size': position['position_value'],
|
||||||
'stop_loss': current_price * 0.93, # 7% stop loss
|
'stop_loss': signal_data['price'] * 0.93, # 7% stop loss
|
||||||
'risk_amount': position['potential_loss'],
|
'risk_amount': position['potential_loss'],
|
||||||
'profit_amount': position['potential_profit'],
|
'profit_amount': position['potential_profit'],
|
||||||
'risk_reward_ratio': position['risk_reward_ratio']
|
'risk_reward_ratio': position['risk_reward_ratio']
|
||||||
}
|
}
|
||||||
bullish_signals.append(signal_data)
|
bullish_signals.append(entry_data)
|
||||||
# Update print output format
|
print_signal(entry_data, "🟢")
|
||||||
dollar_risk = position['potential_loss'] * -1
|
|
||||||
signal_date = validate_signal_date(df.iloc[-1]['date']) # Get and validate the date
|
|
||||||
signal_data['signal_date'] = signal_date # Add to signal data
|
|
||||||
print_signal(signal_data, "🟢")
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(f"Skipping {ticker} position: {str(e)}")
|
print(f"Skipping {ticker} position: {str(e)}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif results['bearish_signal'].iloc[-1]:
|
|
||||||
signal_date = df.iloc[-1]['date']
|
|
||||||
bearish_signals.append({
|
|
||||||
'ticker': ticker,
|
|
||||||
'price': current_price,
|
|
||||||
'volume': current_volume,
|
|
||||||
'signal_date': signal_date,
|
|
||||||
'last_update': datetime.fromtimestamp(last_update/1000000000)
|
|
||||||
})
|
|
||||||
print(f"\n🔴 {ticker} @ ${current_price:.2f} on {signal_date.strftime('%Y-%m-%d %H:%M')}")
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error processing {ticker}: {str(e)}")
|
print(f"Error processing {ticker}: {str(e)}")
|
||||||
continue
|
continue
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user