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

226 lines
No EOL
7.2 KiB
Python

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