import ccxt import pandas as pd import time import os from dotenv import load_dotenv 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', } }) symbol = 'APEUSDT' pause_time = 60 vol_repeat = 11 vol_time = 5 pos_size = 100 params = {'timeInForce': 'GTC'} target = 35 max_loss = -55 vol_decimal = 0.4 timeframe = '4h' limit = 100 sma = 20 def ask_bid(symbol=symbol): orderbook = exchange.fetch_order_book(symbol) bid = orderbook['bids'][0][0] ask = orderbook['asks'][0][0] print(f'Ask price for {symbol}: {ask}') return ask, bid def df_sma(symbol=symbol, timeframe=timeframe, limit=limit, sma=sma): print('Starting technical indicators...') bars = exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit) df = pd.DataFrame(bars, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df[f'sma{sma}_{timeframe}'] = df['close'].rolling(sma).mean() _, bid = ask_bid(symbol) df.loc[df[f'sma{sma}_{timeframe}'] > bid, 'sig'] = 'SELL' df.loc[df[f'sma{sma}_{timeframe}'] < bid, 'sig'] = 'BUY' df['support'] = df[:-2]['close'].min() df['resistance'] = df[:-2]['close'].max() df['prev_close'] = df['close'].shift(1) df['bullish_confirmation'] = df['close'] > df['prev_close'] return df def open_positions(symbol=symbol): positions = exchange.fetch_positions([symbol]) for pos in positions: if pos['symbol'] == symbol and float(pos['contracts']) != 0: side = pos['side'] size = pos['contracts'] is_long = side == 'long' print(f'Open position: {side} {size} contracts') return positions, True, size, is_long, 0, {} return [], False, 0, None, 0, {} def kill_switch(symbol=symbol): print(f'Starting kill switch for {symbol}') while True: _, has_position, position_size, is_long, _, _ = open_positions(symbol) if not has_position: break print(f'Closing position: {position_size} contracts, long: {is_long}') exchange.cancel_all_orders(symbol) ask, bid = ask_bid(symbol) position_size = float(position_size) if is_long: exchange.create_limit_sell_order(symbol, position_size, ask, params) print(f'SELL to close: {position_size} {symbol} at {ask}') else: exchange.create_limit_buy_order(symbol, position_size, bid, params) print(f'BUY to close: {position_size} {symbol} at {bid}') print('Waiting 30 seconds for fill...') time.sleep(30) def sleep_on_close(symbol=symbol, pause_time=pause_time): closed_orders = exchange.fetch_closed_orders(symbol) for order in reversed(closed_orders): if order['status'] == 'closed': order_time = int(order['timestamp'] / 1000) current_time = int(exchange.fetch_order_book(symbol)['timestamp'] / 1000) time_since_trade = (current_time - order_time) / 60 print(f'Last trade was {time_since_trade:.1f} minutes ago') if time_since_trade < pause_time - 1: print(f'Sleeping 60 seconds (recent trade)') time.sleep(60) else: print('No sleep needed') break print(f'Sleep check complete for {symbol}') def ob(symbol=symbol, vol_repeat=vol_repeat, vol_time=vol_time): print(f'Analyzing order book volume for {symbol}...') volume_data = [] for i in range(vol_repeat): orderbook = exchange.fetch_order_book(symbol) bid_volume = sum([bid[1] for bid in orderbook['bids']]) ask_volume = sum([ask[1] for ask in orderbook['asks']]) volume_data.append({'bid_vol': bid_volume, 'ask_vol': ask_volume}) if i < vol_repeat - 1: time.sleep(vol_time) print(f'Sample {i+1}: Bid Vol: {bid_volume}, Ask Vol: {ask_volume}') df = pd.DataFrame(volume_data) total_bid_vol = df['bid_vol'].sum() total_ask_vol = df['ask_vol'].sum() minutes = (vol_time * vol_repeat) / 60 print(f'Total volume over {minutes:.1f} minutes:') print(f'Bid: {total_bid_vol}, Ask: {total_ask_vol}') if total_bid_vol > total_ask_vol: control_ratio = total_ask_vol / total_bid_vol print(f'Bulls in control: {control_ratio:.3f}') else: control_ratio = total_bid_vol / total_ask_vol print(f'Bears in control: {control_ratio:.3f}') _, has_position, _, is_long, _, _ = open_positions(symbol) if has_position: volume_under_threshold = control_ratio < vol_decimal position_type = 'long' if is_long else 'short' print(f'In {position_type} position. Volume under threshold: {volume_under_threshold}') return volume_under_threshold else: print('Not in position') return None def pnl_close(symbol=symbol, target=target, max_loss=max_loss): print(f'Checking PnL for {symbol}...') positions = exchange.fetch_positions([symbol]) position = None for pos in positions: if pos['symbol'] == symbol and float(pos['contracts']) != 0: position = pos break if position is None: print('No position open') return False, False, 0, None side = position['side'] size = position['contracts'] entry_price = float(position['entryPrice']) leverage = float(position['leverage']) is_long = side == 'long' _, current_price = ask_bid(symbol) if is_long: price_diff = current_price - entry_price else: price_diff = entry_price - current_price try: pnl_percent = ((price_diff / entry_price) * leverage) * 100 except: pnl_percent = 0 print(f'PnL: {pnl_percent:.2f}% (Entry: {entry_price}, Current: {current_price})') if pnl_percent > target: print(f'Target hit! Checking volume before closing...') volume_under_threshold = ob(symbol) if volume_under_threshold: print(f'Volume too low, waiting 30s...') time.sleep(30) else: print(f'Closing profitable position!') kill_switch(symbol) return True, True, size, is_long elif pnl_percent <= max_loss: print(f'Max loss hit! Closing position immediately.') kill_switch(symbol) return True, True, size, is_long elif pnl_percent > 0: print(f'In profit but target not reached') else: print(f'In loss but within acceptable range') # Stop loss check using 15m SMA if True: # Position exists df_15m = df_sma(symbol, '15m', 100, 20) sma_15m = df_15m.iloc[-1][f'sma{sma}_15m'] stop_loss_level = sma_15m * 1.008 print(f'SMA stop loss level: {stop_loss_level}') print(f'PnL check complete for {symbol}') return False, True, size, is_long