1
Fork 0
crypto_bot_training/Session_05/bots/Market_Maker.py
2025-06-26 15:46:49 +02:00

341 lines
No EOL
11 KiB
Python

'''
Market Maker Strategy Overview:
Market Making Logic:
- Places buy orders near recent lows, sell orders near recent highs
- Uses dynamic range based on recent high-low spread
- Only trades within configured percentage of recent range extremes
Risk Management:
- ATR-based volatility filtering (no trading if volatility too high)
- Emergency position size limits with automatic closure
- Time-based position limits (auto-close after time limit)
- Stop losses with trailing functionality
Entry Conditions:
- BUY: When bid drops below (low + range_percentage)
- SELL: When ask rises above (high - range_percentage)
- Range calculated from recent N-period high/low
- Filtered out during high volatility periods
Exit Conditions:
- Profit target: 0.4% gain from entry
- Stop loss: 0.1% loss from entry
- Time limit: 2 hours maximum hold time
- Emergency size limit: $1100 maximum risk
Technical Filters:
- Uses 5-minute timeframe with 180-period lookback (15 hours)
- ATR volatility filter prevents trading in choppy markets
- Recent high/low trend analysis prevents bad entries
WARNING: This strategy is complex and has not been fully backtested.
Use only for educational purposes without proper testing.
WARNING: Do not run without thorough backtesting and understanding!
'''
import ccxt
import pandas as pd
import time
from datetime import datetime, timedelta
import schedule
import warnings
import os
from dotenv import load_dotenv
warnings.filterwarnings("ignore")
load_dotenv()
api_key = os.getenv('BINANCE_API_KEY')
api_secret = os.getenv('BINANCE_SECRET_KEY')
exchange = ccxt.binance({
'apiKey': api_key,
'secret': api_secret,
'enableRateLimit': True,
'options': {
'defaultType': 'future',
}
})
# Configuration
size = 4200
symbol = 'DYDXUSDT'
perc_from_lh = 0.35
close_seconds = 60 * 47 # 47 minutes
trade_pause_mins = 15
max_lh = 1250
timeframe = '5m'
num_bars = 180
max_risk = 1100
sl_perc = 0.1
exit_perc = 0.004
max_tr = 550
quartile = 0.33
time_limit = 120 # minutes
sleep_time = 30
params = {'timeInForce': 'GTC'}
def get_bid_ask(symbol=symbol):
orderbook = exchange.fetch_order_book(symbol)
bid = orderbook['bids'][0][0]
ask = orderbook['asks'][0][0]
bid_vol = orderbook['bids'][0][1]
ask_vol = orderbook['asks'][0][1]
return ask, bid, ask_vol, bid_vol
def get_open_positions(symbol=symbol):
positions = exchange.fetch_positions([symbol])
for pos in positions:
if pos['symbol'] == symbol and float(pos['contracts']) != 0:
return {
'side': pos['side'],
'size': float(pos['contracts']),
'entry_price': float(pos['entryPrice']),
'is_long': pos['side'] == 'long',
'has_position': True
}
return {
'side': None,
'size': 0,
'entry_price': 0,
'is_long': None,
'has_position': False
}
def size_kill(symbol=symbol):
position = get_open_positions(symbol)
if position['has_position']:
position_cost = abs(position['size'] * position['entry_price'])
if position_cost > max_risk:
print(f'EMERGENCY: Position size ${position_cost} exceeds max risk ${max_risk}')
kill_switch(symbol)
print('Emergency closure complete. Sleeping 72 hours...')
time.sleep(260000)
def kill_switch(symbol=symbol):
print('KILL SWITCH ACTIVATED')
while True:
position = get_open_positions(symbol)
if not position['has_position']:
break
exchange.cancel_all_orders(symbol)
ask, bid, _, _ = get_bid_ask(symbol)
if position['is_long']:
exchange.create_limit_sell_order(symbol, position['size'], ask, params)
print(f'SELL to close: {position["size"]} at {ask}')
else:
exchange.create_limit_buy_order(symbol, position['size'], bid, params)
print(f'BUY to close: {position["size"]} at {bid}')
time.sleep(30)
def get_order_status(symbol=symbol):
open_orders = exchange.fetch_open_orders(symbol)
has_stop_loss = any(order['type'] == 'stop_market' for order in open_orders)
has_close_order = any(order['type'] == 'limit' for order in open_orders)
has_entry_order = len(open_orders) > 0 and not get_open_positions(symbol)['has_position']
return {
'has_both': has_stop_loss and has_close_order,
'needs_stop_loss': not has_stop_loss,
'needs_close_order': not has_close_order,
'has_entry_pending': has_entry_order
}
def calculate_atr(df, period=7):
df['prev_close'] = df['close'].shift(1)
df['high_low'] = abs(df['high'] - df['low'])
df['high_prev_close'] = abs(df['high'] - df['prev_close'])
df['low_prev_close'] = abs(df['low'] - df['prev_close'])
df['tr'] = df[['high_low', 'high_prev_close', 'low_prev_close']].max(axis=1)
df['atr'] = df['tr'].rolling(period).mean()
return df
def get_pnl(symbol=symbol):
position = get_open_positions(symbol)
if not position['has_position']:
return "No position", 0, 0
ask, bid, _, _ = get_bid_ask(symbol)
current_price = bid
entry_price = position['entry_price']
if position['is_long']:
price_diff = current_price - entry_price
else:
price_diff = entry_price - current_price
try:
pnl_percent = (price_diff / entry_price) * 100
except:
pnl_percent = 0
pnl_text = f'PnL: {pnl_percent:.2f}%'
print(pnl_text)
return pnl_text, ask, bid
def create_stop_order(symbol, reference_price, direction):
position = get_open_positions(symbol)
position_size = position['size'] if position['has_position'] else size
if direction == 'SELL': # Stop for long position
stop_price = reference_price * 1.001
exchange.create_order(
symbol, 'stop_market', 'sell', position_size, None,
params={'stopPrice': stop_price}
)
print(f'Stop loss created: SELL at {stop_price}')
elif direction == 'BUY': # Stop for short position
stop_price = reference_price * 0.999
exchange.create_order(
symbol, 'stop_market', 'buy', position_size, None,
params={'stopPrice': stop_price}
)
print(f'Stop loss created: BUY at {stop_price}')
def bot():
print('\n---- MARKET MAKER ACTIVE ----\n')
# Check PnL and get current prices
pnl_info = get_pnl(symbol)
ask = pnl_info[1]
bid = pnl_info[2]
# Emergency size check
size_kill()
# Get market data
bars = exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=num_bars)
df = pd.DataFrame(bars[:-1], columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
# Calculate technical indicators
df = calculate_atr(df)
# Get range data
low = df['low'].min()
high = df['high'].max()
range_size = high - low
avg_price = (high + low) / 2
print(f'Range: {low:.2f} - {high:.2f} | Size: {range_size:.2f} | Avg: {avg_price:.2f}')
# Check if range is too large (high volatility)
if range_size > max_lh:
print('RANGE TOO LARGE - No trading')
kill_switch()
return
# Check recent trend (no new highs/lows in last 17 bars)
recent_lows = df['low'].tail(17).tolist()
no_trading = any(low >= recent_low for recent_low in recent_lows)
if no_trading:
print('Recent trend unfavorable - No trading')
return
# Get position and order status
position = get_open_positions(symbol)
order_status = get_order_status(symbol)
# Calculate entry levels
open_range = range_size * perc_from_lh
sell_to_open_limit = high - open_range
buy_to_open_limit = low + open_range
print(f'Entry levels - Buy below: {buy_to_open_limit:.2f}, Sell above: {sell_to_open_limit:.2f}')
# Calculate exit price for existing position
if position['has_position']:
if position['is_long']:
exit_price = position['entry_price'] * (1 + exit_perc)
else:
exit_price = position['entry_price'] * (1 - exit_perc)
# Check time limit for existing positions
current_time = int(time.time())
# Main trading logic
if not position['has_position'] and not order_status['has_entry_pending']:
# Look for entry opportunities
if ask > sell_to_open_limit:
print('SELLING to open - Price above sell level')
exchange.cancel_all_orders(symbol)
# Create sell order
sell_price = ask * 1.0009
exchange.create_limit_sell_order(symbol, size, sell_price, params)
print(f'SELL order placed at {sell_price}')
# Create stop loss
create_stop_order(symbol, high, 'SELL')
time.sleep(300) # 5 minute pause
elif bid < buy_to_open_limit:
print('BUYING to open - Price below buy level')
exchange.cancel_all_orders(symbol)
# Create buy order
buy_price = bid * 0.9991
exchange.create_limit_buy_order(symbol, size, buy_price, params)
print(f'BUY order placed at {buy_price}')
# Create stop loss
create_stop_order(symbol, low, 'BUY')
time.sleep(300) # 5 minute pause
else:
print('Price in middle of range - No entry')
elif position['has_position']:
# Manage existing position
if order_status['needs_close_order']:
# Create close order at profit target
if position['is_long']:
exchange.create_limit_sell_order(symbol, position['size'], exit_price, params)
print(f'Close order: SELL at {exit_price}')
else:
exchange.create_limit_buy_order(symbol, position['size'], exit_price, params)
print(f'Close order: BUY at {exit_price}')
if order_status['needs_stop_loss']:
# Create missing stop loss
if position['is_long']:
create_stop_order(symbol, low, 'BUY')
else:
create_stop_order(symbol, high, 'SELL')
else:
print('All orders in place - Monitoring...')
time.sleep(12)
print('=' * 40)
schedule.every(25).seconds.do(bot)
while True:
try:
schedule.run_pending()
time.sleep(15)
except Exception as e:
print(f'Bot error: {e}')
print('Sleeping 75 seconds...')
time.sleep(75)