Created
June 11, 2024 21:15
-
-
Save Br4ndonP0nce/53b089d946750ac529452fab063d8ebb to your computer and use it in GitHub Desktop.
TradingBot Binance runs asynchronously a websocket to read latest data price for the pair BTCUSDT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import asyncio | |
import math | |
from binance import AsyncClient, BinanceSocketManager | |
from dotenv import load_dotenv | |
from datetime import datetime | |
import time | |
# Load environment variables from .env file | |
load_dotenv() | |
# Fetch API key and secret from environment variables | |
api_key = os.getenv('BINANCE_API_KEY') | |
api_secret = os.getenv('BINANCE_API_SECRET') | |
# Ensure API key and secret are set | |
if not api_key or api_secret is None: | |
raise ValueError("Please set the BINANCE_API_KEY and BINANCE_API_SECRET environment variables in the .env file.") | |
# Global variables to hold the latest market price and balances | |
latest_price = None | |
usdt_balance = 0.0 | |
btc_balance = 0.0 | |
min_qty = 0.0 | |
min_notional = 0.0 | |
step_size = 0.0 | |
entry_price = 0.0 | |
entry_quantity = 0.0 | |
initial_btc_balance = 0.0 | |
initial_usdt_balance = 0.0 | |
last_update = None | |
async def handle_socket_message(msg): | |
global latest_price | |
if msg['e'] == 'error': | |
print(f"Error: {msg}") | |
else: | |
latest_price = float(msg['p']) | |
print(f"Updated latest price: {latest_price:.2f} USD") # Debugging statement | |
async def get_account_info(client): | |
global usdt_balance, btc_balance, initial_btc_balance, initial_usdt_balance | |
account_info = await client.get_account() | |
balances = account_info['balances'] | |
for balance in balances: | |
if balance['asset'] == 'USDT': | |
usdt_balance = float(balance['free']) | |
if initial_usdt_balance == 0.0: | |
initial_usdt_balance = usdt_balance | |
if balance['asset'] == 'BTC': | |
btc_balance = float(balance['free']) | |
if initial_btc_balance == 0.0: | |
initial_btc_balance = btc_balance | |
async def place_order(client, symbol, side, order_type, quantity, price=None): | |
if order_type == 'MARKET': | |
order = await client.order_market( | |
symbol=symbol, | |
side=side, | |
quantity=quantity | |
) | |
elif order_type == 'LIMIT': | |
order = await client.order_limit( | |
symbol=symbol, | |
side=side, | |
timeInForce='GTC', | |
quantity=quantity, | |
price=price | |
) | |
return order | |
async def check_open_orders(client, symbol): | |
orders = await client.get_open_orders(symbol=symbol) | |
if orders: | |
print(f"Open Orders for {symbol}:") | |
for order in orders: | |
print(f" Order ID: {order['orderId']}, Status: {order['status']}, Price: {order['price']}, Quantity: {order['origQty']}") | |
else: | |
print(f"No open orders for {symbol}.") | |
async def check_completed_orders(client, symbol): | |
orders = await client.get_all_orders(symbol=symbol) | |
filled_orders = [order for order in orders if order['status'] == 'FILLED'] | |
if filled_orders: | |
print(f"Order History for {symbol}:") | |
for order in filled_orders: | |
order_time = datetime.fromtimestamp(order['time'] / 1000).strftime('%Y-%m-%d %H:%M:%S') | |
print(f" Order ID: {order['orderId']}, Side: {order['side']}, Price: {order['price']}, Quantity: {order['origQty']}, Time: {order_time}") | |
else: | |
print(f"No completed orders for {symbol}.") | |
def is_socket_active(): | |
global last_update | |
if last_update is None: | |
return False | |
current_time = time.time() | |
# Check if the last update was within the last 30 seconds | |
return (current_time - last_update) < 30 | |
async def start_socket(client, symbol): | |
global latest_price | |
bsm = BinanceSocketManager(client) | |
ts = bsm.trade_socket(symbol) | |
async with ts as tscm: | |
while True: | |
res = await tscm.recv() | |
await handle_socket_message(res) | |
async def get_min_trade_info(client, symbol): | |
global min_qty, min_notional, step_size | |
info = await client.get_symbol_info(symbol) | |
for filter in info['filters']: | |
if filter['filterType'] == 'LOT_SIZE': | |
min_qty = float(filter['minQty']) | |
step_size = float(filter['stepSize']) | |
if filter['filterType'] == 'MIN_NOTIONAL': | |
min_notional = float(filter['minNotional']) | |
print(f"min_qty: {min_qty}, min_notional: {min_notional}, step_size: {step_size}") | |
def adjust_to_step_size(quantity, step_size): | |
return math.floor(quantity / step_size) * step_size | |
def round_step_size(quantity, step_size): | |
precision = int(round(-math.log(step_size, 10), 0)) | |
return round(quantity, precision) | |
async def scalping_strategy(client, symbol, usd_amount, profit_threshold, loss_threshold): | |
global latest_price, usdt_balance, btc_balance, min_qty, min_notional, step_size, entry_price, entry_quantity | |
# Define the size of buy orders in USD | |
buy_amount_usd = usd_amount | |
while True: | |
if latest_price is None: | |
print("Waiting for price update...") | |
await asyncio.sleep(1) | |
continue | |
# Only calculate the current worth and PNL if we have an entry | |
if entry_quantity > 0: | |
current_worth = entry_quantity * latest_price | |
pnl = current_worth - buy_amount_usd | |
else: | |
current_worth = 0 | |
pnl = 0 | |
# Print current status | |
print(f"Live BTC Price: {latest_price:.2f} USD") | |
print(f"USDT Balance: {usdt_balance:.2f}") | |
print(f"BTC Balance: {btc_balance:.6f}") | |
print(f"Entry Quantity: {entry_quantity:.6f} BTC") | |
print(f"Entry Price: {entry_price:.2f} USD") | |
print(f"Current Worth: {current_worth:.2f} USD") | |
print(f"PNL: {pnl:.2f} USD") | |
# Check if we have enough USDT to place a buy order | |
if usdt_balance >= buy_amount_usd and entry_quantity == 0: | |
buy_quantity = buy_amount_usd / latest_price | |
buy_quantity = adjust_to_step_size(buy_quantity, step_size) | |
buy_quantity = round_step_size(buy_quantity, step_size) | |
# Ensure buy quantity meets the minimum lot size and notional value | |
if buy_quantity >= min_qty and (buy_quantity * latest_price) >= min_notional: | |
# Place a buy order | |
order = await place_order(client, symbol, 'BUY', 'MARKET', buy_quantity) | |
print("Buy Order Result:") | |
for key, value in order.items(): | |
print(f" {key}: {value}") | |
# Store the entry price and quantity | |
entry_price = latest_price | |
entry_quantity = buy_quantity | |
print("Entry price:", entry_price, "\nEntry quantity:", entry_quantity) | |
# Check for open orders after placing the buy order | |
# await check_open_orders(client, symbol) | |
# Check for completed orders after placing the buy order | |
#await check_completed_orders(client, symbol) | |
# Calculate the target sell price and stop loss price based on the entry amount in USD | |
target_sell_value = buy_amount_usd * (1 + profit_threshold / 100) | |
stop_loss_value = buy_amount_usd * (1 - loss_threshold / 100) | |
print("Target sell:", target_sell_value, "\nStop loss:", stop_loss_value) | |
while entry_quantity > 0: | |
if latest_price is None: | |
await asyncio.sleep(1) | |
continue | |
if not is_socket_active(): | |
print("Socket inactive! No updates received recently.") | |
# Add logic to handle socket inactivity (e.g., restart the socket) | |
# For simplicity, we just print a message here | |
await asyncio.sleep(5) # Wait before rechecking | |
continue | |
else: | |
print("wu socket good") | |
current_worth = entry_quantity * latest_price | |
pnl = current_worth - buy_amount_usd | |
# Debugging output for monitoring phase | |
print(f"Monitoring: latest_price={latest_price}, target_sell_value={target_sell_value}, stop_loss_value={stop_loss_value}, current_worth={current_worth}") | |
# Check if the current worth has reached the target sell value or stop loss value | |
if current_worth >= target_sell_value or current_worth <= stop_loss_value: | |
print("Placing sell order") | |
# Place a sell order | |
sell_quantity = entry_quantity | |
sell_quantity = adjust_to_step_size(sell_quantity, step_size) | |
sell_quantity = round_step_size(sell_quantity, step_size) | |
order = await place_order(client, symbol, 'SELL', 'MARKET', sell_quantity) | |
print("Sell Order Result:") | |
for key, value in order.items(): | |
print(f" {key}: {value}") | |
# Reset entry price and quantity | |
entry_price = 0 | |
entry_quantity = 0 | |
# Update balances after selling | |
await get_account_info(client) | |
# Check for open orders after placing the sell order | |
await check_open_orders(client, symbol) | |
# Check for completed orders after placing the sell order | |
await check_completed_orders(client, symbol) | |
break | |
# Update balances periodically even if no trades are made | |
await get_account_info(client) | |
await asyncio.sleep(1) # Adjust the update interval as needed | |
async def main(): | |
global usdt_balance, btc_balance | |
# Initialize the client with the Testnet parameter | |
client = await AsyncClient.create(api_key, api_secret, testnet=True) | |
# Get initial account information | |
await get_account_info(client) | |
# Get minimum trade information for the symbol | |
await get_min_trade_info(client,"BTCUSDT") | |
# Get minimum trade information for the symbol | |
await get_min_trade_info(client, 'BTCUSDT') | |
# Start the WebSocket connection in a background task | |
asyncio.create_task(start_socket(client, 'BTCUSDT')) | |
# Define strategy parameters | |
usd_amount = 10 # Buy order size in USD | |
profit_threshold = 1 # Profit threshold in percentage | |
loss_threshold = 20 # Loss threshold in percentage | |
# Start the scalping strategy | |
await scalping_strategy(client, 'BTCUSDT', usd_amount, profit_threshold, loss_threshold) | |
await client.close_connection() | |
if __name__ == "__main__": | |
loop = asyncio.get_event_loop() | |
loop.run_until_complete(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment