191 lines
No EOL
6.6 KiB
Python
191 lines
No EOL
6.6 KiB
Python
'''
|
|
Supply & Demand Zone Trading Strategy Overview:
|
|
|
|
Zone Identification:
|
|
- Calculates supply zones (resistance areas where selling pressure exists)
|
|
- Calculates demand zones (support areas where buying pressure exists)
|
|
- Uses historical price action analysis to identify key levels
|
|
- Zones represent areas where institutional orders likely cluster
|
|
|
|
Entry Strategy:
|
|
- BUY: Places orders at demand zone levels (support areas)
|
|
- SELL: Places orders at supply zone levels (resistance areas)
|
|
- Chooses the zone closest to current price for higher probability fills
|
|
- Uses average of multiple zone levels for more reliable entries
|
|
|
|
Position Management:
|
|
- Supports partial position building (adds to positions under target size)
|
|
- Maximum 1 full position at a time with partial fills allowed
|
|
- Automatic position sizing adjustments based on existing exposure
|
|
- Leverage: 3x (adjustable)
|
|
|
|
Risk Management:
|
|
- Profit target: 5% gain
|
|
- Stop loss: 10% loss
|
|
- Continuous PnL monitoring for existing positions
|
|
- Order cancellation and replacement system
|
|
|
|
Technical Setup:
|
|
- Symbol: WIF (configurable)
|
|
- Timeframe: 15 minutes for zone calculation
|
|
- SMA confirmation: 20-period moving average
|
|
- Lookback: 1 day for zone identification
|
|
- Platform: Hyper Liquid (on-chain execution)
|
|
|
|
Zone Logic:
|
|
- Supply zones: Areas where price previously dropped (selling pressure)
|
|
- Demand zones: Areas where price previously bounced (buying pressure)
|
|
- Strategy assumes these levels will act as support/resistance again
|
|
|
|
WARNING: Do not run without thorough backtesting and understanding!
|
|
'''
|
|
|
|
import Functions.funcs as func
|
|
import eth_account
|
|
import time
|
|
import pandas as pd
|
|
import schedule
|
|
import os
|
|
from dotenv import load_dotenv
|
|
|
|
load_dotenv()
|
|
|
|
# Configuration
|
|
symbol = 'WIF'
|
|
timeframe = '15m'
|
|
sma_window = 20
|
|
lookback_days = 1
|
|
size = 1
|
|
target = 5
|
|
max_loss = -10
|
|
leverage = 3
|
|
max_positions = 1
|
|
|
|
def get_account():
|
|
"""Initialize trading account from private key"""
|
|
secret = os.getenv('PRIVATE_KEY')
|
|
return eth_account.Account.from_key(secret)
|
|
|
|
def setup_account():
|
|
"""Setup account with leverage"""
|
|
account = get_account()
|
|
func.adjust_leverage_size_signal(symbol, leverage, account)
|
|
return account
|
|
|
|
def get_position_info(symbol, account):
|
|
"""Get current position information and calculate adjusted size"""
|
|
try:
|
|
positions, in_position, position_size, pos_symbol, entry_price, pnl_percent, is_long = func.get_position(symbol, account)
|
|
|
|
print(f'Position Status - In position: {in_position} | Size: {position_size} | PnL: {pnl_percent}%')
|
|
|
|
# Calculate adjusted position size for partial fills
|
|
if 0 < position_size < size:
|
|
adjusted_size = size - position_size
|
|
print(f'Partial position detected - Current: {position_size} | Needed: {adjusted_size}')
|
|
return False, adjusted_size, positions # Treat as not in position for adding
|
|
else:
|
|
return in_position, size, positions
|
|
|
|
except Exception as e:
|
|
print(f'Error getting position info: {e}')
|
|
return False, size, []
|
|
|
|
def get_supply_demand_zones(symbol):
|
|
"""Calculate supply and demand zones and determine best entry"""
|
|
try:
|
|
# Get supply and demand zones
|
|
sd_df = func.supply_demand_zones_hl(symbol, timeframe, lookback_days)
|
|
print('Supply & Demand Zones:')
|
|
print(sd_df)
|
|
|
|
# Convert to numeric
|
|
sd_df[f'{timeframe}_dz'] = pd.to_numeric(sd_df[f'{timeframe}_dz'], errors='coerce')
|
|
sd_df[f'{timeframe}_sz'] = pd.to_numeric(sd_df[f'{timeframe}_sz'], errors='coerce')
|
|
|
|
# Calculate average zone levels
|
|
demand_zone_avg = float(sd_df[f'{timeframe}_dz'].mean())
|
|
supply_zone_avg = float(sd_df[f'{timeframe}_sz'].mean())
|
|
|
|
# Get current price and SMA confirmation
|
|
current_price = func.ask_bid(symbol)[0]
|
|
latest_sma = func.get_latest_sma(symbol, timeframe, sma_window, 2)
|
|
|
|
print(f'Market Data - Price: {current_price:.4f} | SMA: {latest_sma:.4f}')
|
|
print(f'Zones - Demand: {demand_zone_avg:.4f} | Supply: {supply_zone_avg:.4f}')
|
|
|
|
# Calculate distance to each zone
|
|
distance_to_demand = abs(current_price - demand_zone_avg)
|
|
distance_to_supply = abs(current_price - supply_zone_avg)
|
|
|
|
print(f'Distances - To Demand: {distance_to_demand:.4f} | To Supply: {distance_to_supply:.4f}')
|
|
|
|
# Choose closest zone for entry
|
|
if distance_to_demand < distance_to_supply:
|
|
return 'BUY', demand_zone_avg, 'demand'
|
|
else:
|
|
return 'SELL', supply_zone_avg, 'supply'
|
|
|
|
except Exception as e:
|
|
print(f'Error calculating supply/demand zones: {e}')
|
|
return None, None, None
|
|
|
|
def place_zone_trade(signal, entry_price, zone_type, position_size, account):
|
|
"""Place trade order at supply or demand zone"""
|
|
try:
|
|
func.cancel_all_orders(account)
|
|
print('Canceled all existing orders')
|
|
|
|
if signal == 'BUY':
|
|
func.limit_order(symbol, True, position_size, entry_price, False, account)
|
|
print(f'LONG order placed at {zone_type} zone: {position_size} at {entry_price:.4f}')
|
|
|
|
elif signal == 'SELL':
|
|
func.limit_order(symbol, False, position_size, entry_price, False, account)
|
|
print(f'SHORT order placed at {zone_type} zone: {position_size} at {entry_price:.4f}')
|
|
|
|
except Exception as e:
|
|
print(f'Error placing zone trade: {e}')
|
|
|
|
def bot():
|
|
try:
|
|
print(f'\n---- Supply & Demand Zone Strategy for {symbol} ----')
|
|
|
|
# Setup account
|
|
account = get_account()
|
|
|
|
# Get position information
|
|
in_position, position_size, positions = get_position_info(symbol, account)
|
|
|
|
# Check PnL for existing positions
|
|
if in_position:
|
|
print('Managing existing position')
|
|
func.pnl_close(symbol, target, max_loss, account)
|
|
return
|
|
|
|
# Look for new trade opportunities
|
|
print('Analyzing supply & demand zones...')
|
|
signal, entry_price, zone_type = get_supply_demand_zones(symbol)
|
|
|
|
if signal and entry_price:
|
|
place_zone_trade(signal, entry_price, zone_type, position_size, account)
|
|
else:
|
|
print('No valid zone signals found')
|
|
|
|
print('=' * 60)
|
|
|
|
except Exception as e:
|
|
print(f'Bot error: {e}')
|
|
|
|
# Initial setup
|
|
account = setup_account()
|
|
|
|
schedule.every(30).seconds.do(bot)
|
|
|
|
while True:
|
|
try:
|
|
schedule.run_pending()
|
|
time.sleep(10)
|
|
except Exception as e:
|
|
print(f'Schedule error: {e} - Sleeping 30 seconds')
|
|
time.sleep(30) |