Home PDF Splitter Phantom Mouse Get File Names Proxy Web Requests Google Traffic Gmail Price Alerts Trading Bot What's My Public IP HEX-ASCII Converter Stableford Calculator CV Golf Ball Tracer QR Code Generator About Me

Python

Trading Bot - Simple and Advanced!

With the start of the new bull cycle, I got inspired to try my hand at making a basic BTC/BUSD trading bot. It uses the python-binance wrapper and pulls data from Binance, then analyses this data to make decisions on when to place trades.

The key items in the code are:

  1. API Key and Secret Key - Replace 'your_api_key' and 'your_api_secret' with your Binance API credentials. You should never share these keys with anyone!

  2. Trading Pair - symbol = 'BTCUSDT' means the bot will trade Bitcoin against USDT. You can change this to any other trading pair (like ETHUSDT for Ethereum).

  3. Buy/Sell Logic - The bot buys if the price has increased by more than price_change_threshold (set to 0.1% in this case) since the last transaction. It then sells when the price decreases by more than the price_change_threshold.

  4. Order Placement - place_buy_order() and place_sell_order() place market orders. You can modify these to place limit orders instead.

  5. Price Monitoring - The bot fetches the current price every 10 seconds using get_price(). Adjust the time.sleep(10) for more frequent or less frequent checking.
You will also need to set up the API key in Binance. This isn't hard to do and you'll find an abundance of guides on how to achieve this on the internet, e.g here: Create Binance API Link - Youtube
To modify for paper trading, replace the place_buy_order() and place_sell_order() with simple print statements during testing, e.g.

print(f"Simulating buy order for {quantity} {symbol}")

The code can be found below:

from binance.client import Client import time # Your API Key and Secret from Binance (DO NOT SHARE) api_key = 'your_api_key' api_secret = 'your_api_secret' # Initialize Binance client client = Client(api_key, api_secret) # Define the trading pair and other parameters symbol = 'BTCBUSD' # Bitcoin vs BUSD quantity = 0.001 # Amount of BTC to buy/sell price_change_threshold = 0.001 # Change in price (%) that triggers a buy or sell # Function to get the current price of a cryptocurrency def get_price(symbol): ticker = client.get_symbol_ticker(symbol=symbol) return float(ticker['price']) # Function to place a market buy order def place_buy_order(symbol, quantity): try: order = client.order_market_buy( symbol=symbol, quantity=quantity) print(f"Buy order placed for {quantity} {symbol}") except Exception as e: print(f"An error occurred: {e}") # Function to place a market sell order def place_sell_order(symbol, quantity): try: order = client.order_market_sell( symbol=symbol, quantity=quantity) print(f"Sell order placed for {quantity} {symbol}") except Exception as e: print(f"An error occurred: {e}") # Main trading logic def trading_bot(): initial_price = get_price(symbol) # Get initial price at the start print(f"Starting bot... Initial price: {initial_price}") while True: current_price = get_price(symbol) # Fetch current price price_change = (current_price - initial_price) / initial_price # If price increased by more than the threshold, buy if price_change >= price_change_threshold: print(f"Price increased by {price_change*100:.2f}% - Buying!") place_buy_order(symbol, quantity) initial_price = current_price # Update the initial price after buying # If price decreased by more than the threshold, sell elif price_change <= -price_change_threshold: print(f"Price decreased by {price_change*100:.2f}% - Selling!") place_sell_order(symbol, quantity) initial_price = current_price # Update the initial price after selling # Wait for a few seconds before checking again time.sleep(10) # Start the bot trading_bot()



I tried my hand at a more advanced version of the bot below, with some mixed results. The #Flags section shows some of the analysis the code can do, to check for different conditions in the charts. Trades can then be made based on one or many of these conditions being true. It will likely take a considerable amount of playing with these values to get the bot trading on set ups that you think are high probability.
It uses slightly more complicated analysis of the data to create some common indicators, e.g. the Exponential Moving Average (EMA) and Stochastic. This is the code:

from dataclasses import dataclass from time import sleep from binance.client import Client from binance.enums import * from matplotlib import pyplot as plt import pandas as pd import matplotlib.pyplot as plt from datetime import datetime PRINT_OUTPUT_FLAG = 1 TEST_MODE_FLAG_LONG = 0 #dont make long trade, only print output TEST_MODE_FLAG_SCALP = 1 #dont make scalp trade #Keys API_KEY = "Enter your API Key here" SECRET_KEY = "Enter your secret key here" SYMBOL = 'BTCBUSD' #Balance Variables busdBalance = 0 btcBalance = 0 #Flags oversoldFlag = 0 threeRedCandleFlag = 0 stochasticRisingFlag = 0 stochasticRisingLongerFlag = 0 marketUptrendFlag = 0 fourOrMoreRedCandleFlag = 0 highVolumeFlag = 0 haveOpenOrder = 0 singleHighVolCandleFlag = 0 lastCandleRedFlag = 0 volumeOver180Flag = 0 averageVolumeHigh = 0 stochasticShowingUptrendRange = 0 limitTradeTimer = 0 #gives a limit order 1 minute to complete or else it gets cancelled client = Client(API_KEY, SECRET_KEY) def getBTCData(): #get 10 day EMA for BTC #Moving average - 10 day. Results show the following: #Open time (Unix), Open Price, High Price, Low Price, #Close Price, Volume, Close time (Unix), Quote Asset Volume, #Number of Trades, Taker buy base asset volume, Taker buy quote asset volume, Ignore #Check if there is an open order and reset if there is. Bot should only have 1 open trade at a time orders = client.get_open_orders(symbol=SYMBOL) if len(orders) > 0: print('{} Open Orders - Restarting'.format(len(orders))) sleep(4) return #Get the data from Binance bars = client.get_historical_klines(SYMBOL, '15m', '4 days ago UTC') for line in bars: del line[6:] #print(bars) dataframe = pd.DataFrame(bars, columns=['date', 'open', 'high', 'low', 'close', 'volume']) #calculate Stochastic %K dataframe['nhigh14'] = dataframe['high'].rolling(14).max() dataframe['nlow14'] = dataframe['low'].rolling(14).min() dataframe['K%'] = (pd.to_numeric(dataframe['close'], downcast="float") - dataframe['nlow14'])*100/(dataframe['nhigh14'] - dataframe['nlow14']) #print(dataframe['K%']) #EMA - havent got this to work yet, but it's a better indicate than SMA #symbolEMA = dataframe['close'].to_frame() #removes everything but close column dataframe['EWMA'] = dataframe['close'].ewm(span=383).mean() #save data to output file, can comment this out if PRINT_OUTPUT_FLAG == 1: with open('output.txt', 'w') as f: f.write( dataframe.to_string() ) #plot graph, can comment this out #plotPriceGraph(dataframe) print('Close Price: {} | Stochastic: {} | EMA: {} '.format(float(dataframe.iloc[-2, 4]), round(dataframe.iloc[-1, 8],2), round(float(dataframe.iloc[-2, 9]),2))) #check the last stochastic value if round(dataframe.iloc[-1, 8],2) < 20: #stochastic shows oversold oversoldFlag = 1 print('Stochastic Oversold - {}'.format(round(dataframe.iloc[-1, 8],2))) else: oversoldFlag = 0 #check if stochastic is rising if round(dataframe.iloc[-1, 8],2) > round(dataframe.iloc[-2, 8],2): stochasticRisingFlag = 1 print('Stochastic on the up') else: stochasticRisingFlag = 0 if (round(dataframe.iloc[-1, 8],2) > round(dataframe.iloc[-2, 8],2)) and (round(dataframe.iloc[-2, 8],2) > round(dataframe.iloc[-3, 8],2)): stochasticRisingLongerFlag = 1 print('Stochastic Rising Longer') else: stochasticRisingLongerFlag = 0 #check if market is in uptrend, i.e. price is above 10 day MA (EMA) if float(dataframe.iloc[-2, 4]) > float(dataframe.iloc[-2, 9]): marketUptrendFlag = 1 print('Market is trending up')# - Last close:{} | EMA:{}'.format(float(dataframe.iloc[-2, 4]), round(float(dataframe.iloc[-2, 9]),2))) else: marketUptrendFlag = 0 #check if average volume of last 4 trades is high averageVolume = (float(dataframe.iloc[-2, 5]) + float(dataframe.iloc[-3, 5]) + float(dataframe.iloc[-4, 5]) + float(dataframe.iloc[-5, 5])) / 4 #average volume of last 4 trades is over a certain amount if (averageVolume > 600): averageVolumeHigh = 1 print('High Average Volume - {}'.format(round(averageVolume,2))) else: averageVolumeHigh = 0 #check if last candle is large (more than 2 times the average of the past 4 candles) if float(dataframe.iloc[-1, 5]) > (averageVolume*4): singleHighVolCandleFlag = 1 #print('Single High Volume Candle') else: singleHighVolCandleFlag = 0 #check if last(current) candle is red if dataframe.iloc[-1, 4] < dataframe.iloc[-1, 1]: lastCandleRedFlag = 1 #print('Last Candle is Red') else: lastCandleRedFlag = 0 if dataframe.iloc[-1, 8] > 21 and dataframe.iloc[-1, 8] < 85: stochasticShowingUptrendRange = 1 print('Stochastic between 21 and 85') else: stochasticShowingUptrendRange = 0 print('{}/4 conditions met'.format(stochasticRisingFlag + stochasticShowingUptrendRange + marketUptrendFlag + averageVolumeHigh)) #check flags if should proceed to buy/sell function if stochasticRisingFlag and stochasticShowingUptrendRange and marketUptrendFlag and averageVolumeHigh: print('Enter Long Trade') if TEST_MODE_FLAG_LONG == 0: longBuy() return #print('Skipping Long Trade') #if stochasticRisingFlag and stochasticShowingUptrendRange and marketUptrendFlag and averageVolumeHigh: # print('Enter Scalp Trade') # if TEST_MODE_FLAG_SCALP == 0: # scalpBuy() # return def longBuy(): #get BTC price trades = client.get_recent_trades(symbol=SYMBOL, limit=1) btcprice = float(trades[0]['price']) #print(btcprice) #Get BUSD Balance in wallet checkBUSDBalance() if busdBalance < 300: print('You need more BUSD!') return #Create a buy limit order buyBTCQty = round((busdBalance/4)/btcprice,5) print('Buying BTC for {}'.format(btcprice)) createBuyLimitOrder(buyBTCQty, btcprice)#btc price #see how many open orders I have sleep(0.25) global limitTradeTimer orders = client.get_open_orders(symbol=SYMBOL) print('{} orders'.format(len(orders))) #if there are any open orders, wait until this order is filled, before we create an OCO sell limit order if len(orders) > 0: tradeID = orders[0]['orderId'] haveOpenOrder = 1 limitTradeTimer = 0 while haveOpenOrder > 0: orders = client.get_open_orders(symbol=SYMBOL) print('{} orders'.format(len(orders))) if len(orders) == 0: haveOpenOrder = 0 #set open order flag to 0 and move on to OCO sell limit order break limitTradeTimer = limitTradeTimer + 0.5 print('{} seconds have passed'.format(limitTradeTimer)) if limitTradeTimer > 60: print('Buy Order Timed Out') client.cancel_order(symbol=SYMBOL, orderId=tradeID) return sleep(0.5) limitTradeTimer = 0 #reset timer for next timer variable #Get BTC balance checkBTCBalance() if btcBalance == 0: print('You''ve got no BTC!') return profitPrice = round(btcprice * 1.01025 ,2) sellStopPrice = round(btcprice * 0.9925 ,2) sellLimitPrice = sellStopPrice - 5 roundedBTCBalance = round(btcBalance - 0.00001,5) #in case is rounded up, sometimes this puts the total in my wallet above the real amount and throws an error print ('creating OCO limit order - BTC Bought: {} | BTC Price: {} | Profit Price: {} | Sell Stop Price: {} | Sell Limit Price: {}'.format(roundedBTCBalance, btcprice, profitPrice, sellStopPrice, sellLimitPrice)) createSellOCOLimitOrder(roundedBTCBalance, profitPrice, sellStopPrice, sellLimitPrice) sleep(30) #sleep, let the trade play out def scalpBuy(): #Get BUSD Balance in wallet checkBUSDBalance() if busdBalance < 300: print('You need more BUSD!') return #get BTC price trades = client.get_recent_trades(symbol=SYMBOL, limit=1) btcprice = float(trades[0]['price']) #print(btcprice) #Create a buy limit order buyBTCQty = round((busdBalance/4)/(btcprice - 1),5) print('Buying {} BTC for {}'.format(buyBTCQty,btcprice - 1)) createBuyLimitOrder(buyBTCQty, btcprice - 1)#btc price #see how many open orders I have sleep(0.2) global limitTradeTimer orders = client.get_open_orders(symbol=SYMBOL) print('{} orders'.format(len(orders))) #if there are any open orders, wait until this order is filled, before we create an OCO sell limit order if len(orders) > 0: tradeID = orders[0]['orderId'] haveOpenOrder = 1 limitTradeTimer = 0 while haveOpenOrder > 0: orders = client.get_open_orders(symbol=SYMBOL) print('{} orders'.format(len(orders))) if len(orders) == 0: haveOpenOrder = 0 #set open order flag to 0 and move on to OCO sell limit order break limitTradeTimer = limitTradeTimer + 0.5 print('{} seconds have passed'.format(limitTradeTimer)) if limitTradeTimer >= 5: print('Buy Order Timed Out') client.cancel_order(symbol=SYMBOL, orderId=tradeID) checkBTCBalance() if round(btcBalance,5) <= 0: return sleep(0.5) limitTradeTimer = 0 #reset timer for next timer variable #Get BTC balance checkBTCBalance() if btcBalance == 0: print('You''ve got no BTC!') return profitPrice = round(btcprice + 15 ,2) sellStopPrice = round(btcprice - 10 ,2) sellLimitPrice = sellStopPrice - 1 roundedBTCBalance = round(btcBalance - 0.00001,5) #subtract 0.00001 in case is rounded up, sometimes this puts the total in my wallet above the real amount and throws an error if roundedBTCBalance <= 0: return print ('creating OCO limit order - BTC Bought: {} | BTC Price: {} | Profit Price: {} | Sell Stop Price: {} | Sell Limit Price: {}'.format(roundedBTCBalance, btcprice, profitPrice, sellStopPrice, sellLimitPrice)) createSellOCOLimitOrder(roundedBTCBalance, profitPrice, sellStopPrice, sellLimitPrice) sleep(10) def plotPriceGraph(dataframe): dataframe = dataframe.astype(float) #dataframe[['close', '5sma', '15sma']].plot() #dataframe[['K%']].plot() plt.xlabel('Date', fontsize=18) plt.ylabel('K%', fontsize=18) #plt.scatter(dataframe.index, dataframe['Buy'], color='purple', label ='Buy', marker='^', alpha = 1)#buy signal #plt.scatter(dataframe.index, dataframe['Sell'], color='red', label ='Sell', marker='v', alpha = 1)#sell signal plt.show() def checkBUSDBalance(): global busdBalance info =client.get_account() balance = info['balances'] for b in balance: if (float(b['free']) > 0) and (b['asset'] == 'BUSD'): busdBalance = float(b['free']) #print(busdBalance) def checkBTCBalance(): global btcBalance info =client.get_account() balance = info['balances'] for b in balance: if (float(b['free']) > 0) and (b['asset'] == 'BTC'): btcBalance = float(b['free']) #print('BTC balance is {}'.format(balance)) return def createBuyLimitOrder(buyQTY, buyPrice): order = client.order_limit_buy( symbol=SYMBOL, quantity= buyQTY, price=buyPrice) print('Buying Order Placed') def createSellOCOLimitOrder(sellQTY, sellPrice, sellStopPrice, sellLimitPrice): order = client.order_oco_sell( symbol=SYMBOL, stopLimitTimeInForce='FOK', quantity=sellQTY, price=sellPrice, stopPrice=sellStopPrice, stopLimitPrice=sellLimitPrice, ) print('OCO Order Placed') #catch exception where code failed for some reason def checkAndSell(): global btcBalance checkBTCBalance() #print(btcBalance) if round(btcBalance, 5) > 0.00002: trades = client.get_recent_trades(symbol=SYMBOL, limit=1) btcprice = float(trades[0]['price']) profitPrice = round(btcprice + 15 ,2) sellStopPrice = round(btcprice - 10 ,2) sellLimitPrice = sellStopPrice - 1 roundedBTCBalance = round(btcBalance - 0.00001, 5) #subtract 0.00001 in case is rounded up, sometimes this puts the total in my wallet above the real amount and throws an error print ('creating panic OCO limit order - BTC to sell: {} | BTC Price: {} | Profit Price: {} | Sell Stop Price: {} | Sell Limit Price: {}'.format(roundedBTCBalance, btcprice, profitPrice, sellStopPrice, sellLimitPrice)) createSellOCOLimitOrder(roundedBTCBalance, profitPrice, sellStopPrice, sellLimitPrice) sleep(1) def main(): getBTCData() if __name__ == "__main__": print('start') while(True): print('\n[{}] recheck'.format(datetime.now())) try: main() except: sleep(5) checkAndSell() checkAndSell() sleep(4)