versión en español disponible aquí
En el mundo del comercio de criptomonedas, el uso de software de comercio automatizado puede ayudar a los comerciantes a identificar oportunidades potenciales de compra y venta en tiempo real y tomar posiciones sin la necesidad de estar frente a una computadora. En esta publicación, analizaremos el código para construir un bot de trading simple usando un par de promedios móviles. El bot utilizará la API de Binance para obtener datos de mercado en tiempo real y ejecutar operaciones basadas en estrategias predefinidas.
El objetivo real de la publicación no es crear un bot competitivo, sino crear un programa simple y fácil de entender que podamos escalar en el futuro, haciéndolo más complejo y eficiente.
Descargo de responsabilidad
La información proporcionada en esta publicación tiene fines educativos únicamente y no debe interpretarse como un consejo de inversión. El comercio automatizado conlleva un alto riesgo en el que se puede perder el capital invertido. Es importante hacer su propia investigación antes de tomar cualquier decisión de inversión.
Requisitos
- Un dispositivo con python 3 (Windows, Linux, Mac, Termux, etc.)
- Un editor de código (VScode, Atom, PyCharm, Vim, Emacs, etc.)
- Una cuenta de Binance verificada.
- Conocimiento básico de python (no es estrictamente necesario, pero te ayudará a comprender mejor el código).
Crear una API binance
Para crear una clave API de Binance, siga estos pasos:
|
Configuración del entorno
Para empezar, asegúrate de que tienes Python instalado en tu máquina junto con las librerías necesarias:
datetime
, time
, pytz
, pandas
, numpy
y python-binance
. Puedes instalar estas librerías usando pip, el instalador de paquetes de Python.
pip install pandas numpy python-binance pytz
Importar librerías
Comencemos nuestro script importando las librerías necesarias para el bot de trading:
import datetime as dt
import time
import pytz
import pandas as pd
import numpy as np
from binance.client import Client
API Key y Secret
Para acceder a la API de Binance, debes proporcionar la clave y el secreto de la API que creaste anteriormente en el sitio web de Binance. Una vez que los tengas, reemplaza las palabras
'YOUR API KEY'
y 'YOUR API SECRET'
con sus credenciales reales de la API:
API_KEY = 'YOUR_API_KEY'
API_SECRET = 'YOUR_API _SECRET'
Definición de variables y parámetros
A continuación, definimos varias variables y parámetros que se utilizarán en todo el código. Estos incluyen el símbolo de la criptomoneda, símbolo de referencia (por ejemplo, USDT), la cantidad de criptomoneda para el comercio, y el período de obtención de datos de velas:
crypto = 'HIVE'
ref = 'USDT'
symbol = crypto + ref
amount = 15
# Eligible periods for candlesticks 1m, 3m, 5m, 15m, 1h, etc.
period = '15m'
# Moving Average Periods
ema_f = 15
ema_s = 50
Funciones auxiliares
Anexamos varias funciones de ayuda que realizan tareas específicas:
get_balance(balances, asset)
: Esta función obtiene el saldo de un activo específico en el balance de la cuenta.get_max_float_qty(step_size)
: Calcula la cantidad máxima de decimales con que se puede operar el activo.get_quantity(price, amount, min_qty, max_qty, max_float_qty)
: Esta función calcula la cantidad a tradear en función del precio, la inversion deseada y las restricciones de cantidad mínima/máxima del asset.crossover(ma_fast, ma_slow)
: Esta función comprueba si se ha producido un cruce entre las medias móviles rápida y lenta.
def get_balance(balances, asset):
for bal in balances:
if bal.get('asset') == asset:
return float(bal['free'])
def get_max_float_qty(step_size):
max_float_qty = 0
a = 10
while step_size * a < 1:
a = a*10**max_float_qty
max_float_qty += 1
return max_float_qty
def get_quantity(price, amount, min_qty, max_qty, max_float_qty):
quantity = amount / price
if (quantity < min_qty or quantity > max_qty):
return False
quantity = np.round(quantity, max_float_qty)
return quantity
def get_quantity(price, amount, min_qty, max_qty, max_float_qty):
quantity = amount / price
if (quantity < min_qty or quantity > max_qty):
return False
quantity = np.round(quantity, max_float_qty)
return quantity
Sincronización
La función
synchronize()
es responsable de sincronizar las acciones del bot con la hora actual UTC. Obtiene los últimos datos de velas y calcula el siguiente tiempo de sincronización añadiendo el "step" especificado (en minutos) a la última marca de tiempo. La función entonces espera hasta que el tiempo actual exceda el tiempo de sincronización, asegurando que el bot opera de acuerdo a los intervalos de tiempo deseados.
def synchronize():
candles = client.get_klines(symbol=symbol,interval=period,limit=1)
timer = pd.to_datetime(float(candles[0][0]) * 1000000)
start = timer + dt.timedelta(minutes=step)
print('Synchronizing .....')
while dt.datetime.now(dt.timezone.utc) < pytz.UTC.localize(start):
time.sleep(1)
time.sleep(2)
print('Bot synchronized')
Análisis de datos
La función
parser()
se define para obtener y analizar datos de velas de la API de Binance. Utiliza el método client.get_klines()
para recuperar los datos históricos del mercado para el símbolo y el intervalo de tiempo especificados. Los datos se convierten en un DataFrame de pandas para su posterior análisis. Las columnas innecesarias se eliminan, y las restantes se convierten a sus tipos de datos apropiados. La columna "hora" se convierte a un formato de fecha y hora, y los valores EMA se calculan utilizando la función ewm()
de pandas. Finalmente, se añade una columna 'operation' al DataFrame y se inicializa con valores NaN. La función devuelve el DataFrame analizado.
def parser(limit=ema_s+1):
candles = client.get_klines(symbol=symbol,interval=period,limit=limit)
df = pd.DataFrame(candles)
df = df.drop([6, 7, 8, 9, 10, 11], axis=1)
df.columns = ['time', 'open', 'high', 'low', 'close', 'volume']
df[['time', 'open', 'high', 'low', 'close', 'volume']] = df[['time', 'open', 'high', 'low', 'close', 'volume']].astype(float)
df['time'] = pd.to_datetime(df['time'] * 1000000)
df['ema_s'] = df['close'].ewm(span=ema_s).mean()
df['ema_f'] = df['close'].ewm(span=ema_f).mean()
df['operation'] = np.nan
return df
Operaciones
La función
operate()
determina si se ejecuta una orden de compra o de venta en función de la estrategia de cruce de las EMA. Si la EMA rápida (ema_f
) cruza por encima de la EMA lenta (ema_s
), se ejecuta una orden de compra. Del mismo modo, si la EMA rápida cruza por debajo de la EMA lenta, se ejecuta una orden de venta. La función interactúa con la API de Binance utilizando los métodos como order_market_buy()
y order_market_sell()
para ejecutar las órdenes. La función devuelve el tipo de operación ('BUY' o 'SELL') realizada.
def operate(df):
operation = ''
price = df['close'].iloc[-1]
if crossover(df.ema_f.values[-2:], df.ema_s.values[-2:]):
quantity = get_quantity(price, amount, min_qty, max_qty, max_float_qty)
balances = client.get_account()['balances']
balance = get_balance(balances, ref)
if not quantity:
print('No Quantity available')
elif balance <= amount:
print(f'No {ref} to buy {crypto}')
else:
order = client.order_market_buy(
symbol=symbol,
quantity=quantity)
print('BUY')
operation = 'BUY'
elif crossover(df.ema_s.values[-2:], df.ema_f.values[-2:]):
quantity = get_quantity(price, amount, min_qty, max_qty, max_float_qty)
balances = client.get_account()['balances']
balance = get_balance(balances, crypto)
if not quantity:
print('No Quantity available')
elif balance < quantity:
print(f'No {crypto} to sell for {ref}')
else:
order = client.order_market_sell(
symbol=symbol,
quantity=quantity)
print('SELL')
operation = 'SELL'
return operation
Ejecución principal
La lógica principal de trading se implementa en el bloque
if name == "main":
. Vamos a desglosar los pasos:
- Desactivar los mensajes de advertencia de pandas para la asignación encadenada:
- Crear un objeto cliente de Binance y obtener la información del par que se va a operar:
- Se inicializa el marco de datos llamando a la función
parser()
: - La variable "step" se determina en función del intervalo de tiempo especificado, Se llama a la función
synchronize()
para garantizar que el bot se inicia en el momento correcto: - El bucle principal comienza con un temporizador para medir el tiempo de ejecución. Vuelve a llamar a la función
parser()
para obtener los datos más recientes, asigna el tipo de operación a la última fila de la columna "operation" mediante la funciónoperate()
y añade la nueva fila al DataFrame existente. Si el DataFrame supera un determinado límite de tamaño, se recorta para mantener un conjunto de datos manejable. A continuación, el DataFrame se guarda en un archivo CSV con fines de registro. Por último, el bucle calcula el tiempo de retardo necesario para alcanzar el intervalo deseado y duerme durante el tiempo calculado:
pd.options.mode.chained_assignment = None
client = Client(API_KEY, API_SECRET)
info = client.get_symbol_info(symbol)
min_qty = float(info['filters'][1].get('minQty'))
step_size = float(info['filters'][1].get('stepSize'))
max_qty = float(info['filters'][1].get('maxQty'))
max_float_qty = get_max_float_qty(step_size)
df = parser()
step = int(period[:2]) if len(period) > 2 else int(period[0])
if 'h' in period:
step = step * 60
synchronize()
while True:
temp = time.time()
data_df = parser()
data_df['operation'].iloc[-1] = operate(data_df.tail(2))
df = pd.concat([df, data_df.tail(1)], ignore_index=True)
if df.shape[0] > 10000:
df = df.tail(10000)
df.to_csv(f'./{symbol}_{period}.csv')
delay = time.time() - temp
idle = 60 * step - delay
print(f'idle = {idle} seconds')
time.sleep(idle)
Hemos revisado paso a paso el código para construir un bot de trading de criptomonedas utilizando la API de Binance. El bot obtiene datos históricos del mercado, realiza análisis técnicos utilizando cruces EMA, y ejecuta órdenes de compra o venta basadas en condiciones predefinidas. Al entender este código, puedes avanzar en la construccion de tus propios bots de trading o personalizar el existente para adaptarlo a tus estrategias. Se puede mejorar aún más este código mediante la incorporación de indicadores técnicos adicionales, estrategias de gestión de riesgos y técnicas de backtesting. En el próximo post intentaré mejorar este bot añadiendo más funcionalidades.
Recuerda, los bots de trading implican riesgos financieros, y es esencial probar y validar a fondo tus estrategias antes de desplegarlas en entornos de trading en vivo.
Puedes consultar todo este código en mi GitHub y si tienes alguna pregunta o sugerencia no dudes en dejar un comentario.
referencias: pytz | python-binance
In the world of cryptocurrency trading, the use of automated trading software can help traders identify potential buying and selling opportunities in real time and take positions without the need to be in front of a computer. In this post, will walk you through the code to build a simple trading bot using a pair of moving averages. The bot will use the Binance API to get real-time market data and execute trades based on predefined strategies.
The real goal of the post is not to create a competitive bot, but rather to build a simple, easy to understand program that we can scale in the future, making it more complex and efficient.
Disclaimer
The information provided in this post is for educational purposes only and should not be construed as investment advice. Automated trading carries a high risk in which the invested capital can be lost. It is important to do your own research before making any investment decisions.
Prerequisites
- A device with python 3 (Windows, Linux, Mac, Termux, etc.)
- A code editor (VScode, Atom, PyCharm, Vim, Emacs, etc. )
- A verified Binance account.
- Basic python knowledge (not strictly necessary, but it will help you to understand the code better.)
Creating a binance API
To create a Binance API key, follow these steps:
|
|
Setting Up the Environment
To get started, make sure you have Python installed on your machine along with the required libraries:
datetime
, time
, pytz
, pandas
, numpy
, and python-binance
. You can install these libraries using pip, the Python package installer.
pip install pandas numpy python-binance pytz
Importing Libraries
Let's begin our script by importing the necessary libraries for the trading bot:
import datetime as dt
import time
import pytz
import pandas as pd
import numpy as np
from binance.client import Client
API Key and Secret
To access the Binance API, you need to provide the API key and secret that you created before from the Binance website. Once you have them, replace the placeholders
'YOUR API KEY'
and 'YOUR API SECRET'
with your actual API credentials:
API_KEY = 'YOUR_API_KEY'
API_SECRET = 'YOUR_API _SECRET'
Defining Variables and Parameters
Next, we define several variables and parameters that will be used throughout the code. These include the cryptocurrency symbol, reference symbol (e.g., USDT), the amount of cryptocurrency to trade, and the period for fetching candlestick data:
crypto = 'HIVE'
ref = 'USDT'
symbol = crypto + ref
amount = 15
# Eligible periods for candlesticks 1m, 3m, 5m, 15m, 1h, etc.
period = '15m'
# Moving Average Periods
ema_f = 15
ema_s = 50
Helper Functions
The code includes several helper functions that perform specific tasks:
get_balance(balances, asset)
: This function retrieves the balance of a specific asset from the account's balances.get_max_float_qty(step_size)
: It calculates the maximum floating quantity based on the step size.get_quantity(price, amount, min_qty, max_qty, max_float_qty)
: This function calculates the quantity to trade based on the price, desired amount, and minimum/maximum quantity constraints.crossover(ma_fast, ma_slow)
: This function checks if a crossover event has occurred between the fast and slow moving averages.
def get_balance(balances, asset):
for bal in balances:
if bal.get('asset') == asset:
return float(bal['free'])
def get_max_float_qty(step_size):
max_float_qty = 0
a = 10
while step_size * a < 1:
a = a*10**max_float_qty
max_float_qty += 1
return max_float_qty
def get_quantity(price, amount, min_qty, max_qty, max_float_qty):
quantity = amount / price
if (quantity < min_qty or quantity > max_qty):
return False
quantity = np.round(quantity, max_float_qty)
return quantity
def get_quantity(price, amount, min_qty, max_qty, max_float_qty):
quantity = amount / price
if (quantity < min_qty or quantity > max_qty):
return False
quantity = np.round(quantity, max_float_qty)
return quantity
Synchronization
The
synchronize()
function is responsible for synchronizing the bot's actions with the current time. It fetches the latest candlestick data and calculates the next synchronization time by adding the specified step (in minutes) to the last timestamp. The function then waits until the current time exceeds the synchronization time, ensuring the bot operates according to the desired time intervals.</
def synchronize():
candles = client.get_klines(symbol=symbol,interval=period,limit=1)
timer = pd.to_datetime(float(candles[0][0]) * 1000000)
start = timer + dt.timedelta(minutes=step)
print('Synchronizing .....')
while dt.datetime.now(dt.timezone.utc) < pytz.UTC.localize(start):
time.sleep(1)
time.sleep(2)
print('Bot synchronized')
Parsing Data
The
parser()
function is defined to fetch and parse candlestick data from the Binance API. It uses the client.get_klines()
method to retrieve historical market data for the specified symbol and time interval. The data is then converted into a pandas DataFrame for further analysis. Unnecessary columns are dropped, and the remaining columns are converted to their appropriate data types. The 'time' column is converted to a datetime format, and EMA values are calculated using the ewm() function from pandas. Finally, an 'operation' column is added to the DataFrame and initialized with NaN values. The parsed DataFrame is returned by the function.
def parser(limit=ema_s+1):
candles = client.get_klines(symbol=symbol,interval=period,limit=limit)
df = pd.DataFrame(candles)
df = df.drop([6, 7, 8, 9, 10, 11], axis=1)
df.columns = ['time', 'open', 'high', 'low', 'close', 'volume']
df[['time', 'open', 'high', 'low', 'close', 'volume']] = df[['time', 'open', 'high', 'low', 'close', 'volume']].astype(float)
df['time'] = pd.to_datetime(df['time'] * 1000000)
df['ema_s'] = df['close'].ewm(span=ema_s).mean()
df['ema_f'] = df['close'].ewm(span=ema_f).mean()
df['operation'] = np.nan
return df
Trading Operations
The
operate()
function determines whether to execute a buy or sell order based on the EMA crossover strategy. If the fast EMA (ema_f
) crosses above the slow EMA (ema_s
), a buy order is executed. Similarly, if the fast EMA crosses below the slow EMA, a sell order is executed. The function interacts with the Binance API using methods like order_market_buy()
and order_market_sell()
to execute the orders. The function returns the operation type ('BUY' or 'SELL') performed.
def operate(df):
operation = ''
price = df['close'].iloc[-1]
if crossover(df.ema_f.values[-2:], df.ema_s.values[-2:]):
quantity = get_quantity(price, amount, min_qty, max_qty, max_float_qty)
balances = client.get_account()['balances']
balance = get_balance(balances, ref)
if not quantity:
print('No Quantity available')
elif balance <= amount:
print(f'No {ref} to buy {crypto}')
else:
order = client.order_market_buy(
symbol=symbol,
quantity=quantity)
print('BUY')
operation = 'BUY'
elif crossover(df.ema_s.values[-2:], df.ema_f.values[-2:]):
quantity = get_quantity(price, amount, min_qty, max_qty, max_float_qty)
balances = client.get_account()['balances']
balance = get_balance(balances, crypto)
if not quantity:
print('No Quantity available')
elif balance < quantity:
print(f'No {crypto} to sell for {ref}')
else:
order = client.order_market_sell(
symbol=symbol,
quantity=quantity)
print('SELL')
operation = 'SELL'
return operation
Main Execution
The main trading logic is implemented in the
if name == "main":
block. Let's break down the steps:
pd.options.mode.chained_assignment = None
client = Client(API_KEY, API_SECRET)
info = client.get_symbol_info(symbol)
min_qty = float(info['filters'][1].get('minQty'))
step_size = float(info['filters'][1].get('stepSize'))
max_qty = float(info['filters'][1].get('maxQty'))
max_float_qty = get_max_float_qty(step_size)
parser()
function:
df = parser()
synchronize()
function is called to ensure the bot starts at the correct time:
step = int(period[:2]) if len(period) > 2 else int(period[0])
if 'h' in period:
step = step * 60
synchronize()
parser()
function again to fetch the latest data, assigns the operation type to the last row of the 'operation' column using the operate()
function, and appends the new row to the existing DataFrame. If the DataFrame exceeds a certain size limit, it is trimmed to maintain a manageable dataset. The DataFrame is then saved to a CSV file for record-keeping purposes. Finally, the loop calculates the time delay required to achieve the desired interval and sleeps for the calculated duration:
while True:
temp = time.time()
data_df = parser()
data_df['operation'].iloc[-1] = operate(data_df.tail(2))
df = pd.concat([df, data_df.tail(1)], ignore_index=True)
if df.shape[0] > 10000:
df = df.tail(10000)
df.to_csv(f'./{symbol}_{period}.csv')
delay = time.time() - temp
idle = 60 * step - delay
print(f'idle = {idle} seconds')
time.sleep(idle)
We explored the code for building a simple crypto trading bot using the Binance API. The code fetches historical market data, performs technical analysis using EMA crossovers, and executes buy or sell orders based on predefined conditions. By understanding this code, you can gain insights into building your own trading bots or customize the existing one to suit your trading strategies. You can further enhance this code by incorporating additional technical indicators, risk management strategies, and portfolio balancing techniques. In the next post I will try to improve this bot by adding more functionality.
Remember, trading bots involve financial risks, and it's essential to thoroughly test and validate your strategies before deploying them in live trading environments.
You can check all this code on my GitHub and if you have any questions or suggestions please feel free to leave a comment.
references: pytz | python-binance
Wow! Keep up the great work 👍
thank you, I will try my best 😀
That was a great job, interesting how Binance distributes their API for free, I've seen some similar interfaces charging a fee on the process, nice tutorial my friend.
thanks, Binance is great, let's hope they continue to be there for a long time.