
{"id":20096,"date":"2024-11-13T07:05:37","date_gmt":"2024-11-13T07:05:37","guid":{"rendered":"https:\/\/mycryptomania.com\/?p=20096"},"modified":"2024-11-13T07:05:37","modified_gmt":"2024-11-13T07:05:37","slug":"automated-crypto-trading-with-python-and-binance","status":"publish","type":"post","link":"https:\/\/mycryptomania.com\/?p=20096","title":{"rendered":"Automated Crypto Trading with Python and Binance"},"content":{"rendered":"<h4>Introduction to python-binance<\/h4>\n<p>With the introduction of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Bitcoin\">Bitcoin<\/a> 15 years ago, a new asset class emerged: cryptocurrency. While everyone must consider their own risk tolerance, there\u2019s no denying that crypto investments have experienced incredible highs and impressive returns, as well as devastating lows and significant losses.<\/p>\n<p>One defining feature of the crypto market is its (near) complete decentralization, marked by the absence of regulatory oversight and governing entities\u200a\u2014\u200afor better or worse. This also means that crypto assets can be traded 24\/7, unlike traditional stocks, which are limited to market hours. This continuous trading availability makes crypto particularly appealing for automated trading: with simple scripts, we can monitor the market and execute trades faster than any human, ready to seize opportunities day or\u00a0night.<\/p>\n<p>Photo by <a href=\"https:\/\/unsplash.com\/@kanchanara?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Kanchanara<\/a> on\u00a0<a href=\"https:\/\/unsplash.com\/s\/photos\/binance?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Unsplash<\/a><\/p>\n<p>In this post, we\u2019ll provide an introduction to this topic and, more specifically, introduce the Python API python-binance, which allows us to programmatically access the popular crypto trading platform, <a href=\"https:\/\/www.binance.com\/\">Binance<\/a>. We\u2019ll cover all the essential functionalities, such as retrieving current and historical prices, buying and selling crypto, and transferring it to other addresses. All the code examples shared here will also be available on <a href=\"https:\/\/github.com\/cryptoexplainer\/crypto_bot\/tree\/main\/crypto_bot\">GitHub<\/a>. In follow-up posts, we\u2019ll dive into trading strategies and develop fully automated trading\u00a0bots.<\/p>\n<h3>Binance and python-binance<\/h3>\n<p>Binance is the world\u2019s largest cryptocurrency exchange, known for its user-friendly interface and support for automation, along with relatively low trading fees (0.1%). If you\u2019re new to Binance, feel free to sign up using my <a href=\"https:\/\/www.binance.com\/en-GB\/activity\/referral-entry\/CPA?fromActivityPage=true&amp;ref=CPA_008DHX4MEN\">referral link<\/a> to enjoy benefits for both of us, such as a $100 USD trading fee\u00a0voucher.<\/p>\n<p>In this post, we\u2019ll use the python-binance library, a convenient Python wrapper around Binance\u2019s REST API. This library was the winner of a competition launched by Binance to identify the best API libraries across different programming languages. However, keep in mind that it\u2019s not your only option\u2014you can also directly interact with Binance\u2019s REST API if you prefer more control or want to use a different language or\u00a0tool.<\/p>\n<h4>Setup<\/h4>\n<p>To install, simply\u00a0run:<\/p>\n<p>pip install python-binance<\/p>\n<p>However, at the time of writing and with Python 3.10 this gave me some wrong dependencies for websocket calls (I will point this out later in the respective sections again, when necessary)\u200a\u2014\u200ameaning I additionally had to fix the following versions:<\/p>\n<p>pip install websockets==10.4<br \/>pip install aiohttp==3.8.5<\/p>\n<p>Next, we need to create an API key. For this, login to Binance, click on your profile icon and then select \u201cAPI Management\u201d \/ \u201cCreate API\u201d, and answer the security questions. You will be shown an <strong>API Key<\/strong> and <strong>Secret Key<\/strong>. Take note of these, they will not be visible anymore once navigating away from this\u00a0site.<\/p>\n<p>For some of the things shown in this post (namely trading and transferring cryptocurrencies), we\u2019ll need to tick the box \u201cEnable Spot &amp; Margin Trading\u201d and \u201cEnable Withdrawals\u201d. Thus, hit \u201cEdit Restrictions\u201d and enable the corresponding box. As you will see, this requires entering some trusted IP addresses from which the key is used. For that, head to e.g. <a href=\"https:\/\/whatismyipaddress.com\/\">https:\/\/whatismyipaddress.com\/<\/a> and copy your IP address. Note that your <a href=\"https:\/\/en.wikipedia.org\/wiki\/Internet_service_provider\">ISP<\/a> will regularly give you a new one, meaning you\u2019ll have to update the corresponding key whenever this\u00a0happens.<\/p>\n<p>With that, you\u2019re done! Now on to saving and using the key. It\u2019s never a good idea to store such secrets in code\u200a\u2014\u200athus one alternative is storing the keys somewhere on your system, and loading them from there in code. One such option are environment variables. To use these, on Linux,\u00a0execute:<\/p>\n<p>echo &#8216;export binance_api={API Key}&#8217; &gt;&gt; ~\/.bashrc<br \/>echo &#8216;export binance_secret={Secret Key}&#8217; &gt;&gt; ~\/.bashrc<\/p>\n<p>This will write the corresponding keys to your bashrc. Upon re-loading the terminal, you can query them in Python\u00a0via:<\/p>\n<p>api_key = os.environ.get(&#8216;binance_api&#8217;)<br \/>api_secret = os.environ.get(&#8216;binance_secret&#8217;)<\/p>\n<p>Then, we can instantiate a Binance\u00a0client:<\/p>\n<p>from binance.client import Client<br \/>client = Client(api_key, api_secret)<\/p>\n<p>Now we\u2019re all setup let\u2019s move on to actually using the\u00a0API.<\/p>\n<h3>Querying Account\u00a0Details<\/h3>\n<p>We begin by querying some simple information about our account \/\u00a0wallet.<\/p>\n<p>The line:<\/p>\n<p>client.get_account()<\/p>\n<p>prints all our account information \/ balances.<\/p>\n<p>To query the balance of a specific currency, run:<\/p>\n<p>client.get_asset_balance(asset=&#8217;BTC&#8217;)[&#8216;free&#8217;]<\/p>\n<h3>Retrieve Latest Price Information<\/h3>\n<p>Next, let\u2019s come to retrieving current price information. For this, there are two possibilities. One is a simple and direct API call, such\u00a0as:<\/p>\n<p>client.get_symbol_ticker(symbol=&#8217;BTCUSDT&#8217;)[&#8216;price&#8217;]<\/p>\n<p>This will give us the current price of the asset pair BTC-USDT.<\/p>\n<p>Alternatively, we can use websockets for periodic queries: after starting a websocket and registering a callback, this is called everytime new information is available\u200a\u2014\u200asuch as an updated price of an asset. This approach is more suited for regular and frequent calls, think of for example a bot doing automated trades based on recent price movements.<\/p>\n<p>To make use of the websockets, we first need a websocket manager:<\/p>\n<p>twm = ThreadedWebsocketManager()<br \/>twm.start()<\/p>\n<p>Next, we define a callback, and start a specific stream\u200a\u2014\u200ain our example a live ticker for the BTC-USDT\u00a0pair:<\/p>\n<p>def handle_socket_message(msg: str) -&gt; None:<br \/>    print(f&#8221;message type: {msg[&#8216;e&#8217;]}&#8221;)<br \/>    print(msg)<\/p>\n<p>btc_ticker = twm.start_symbol_ticker_socket(<br \/>    callback=handle_socket_message, symbol=&#8221;BTCUSDT&#8221;<br \/>)<\/p>\n<p>Starting the socket manager starts a background process, meaning the Python interpreter will continue over this line on to the next, but upon reaching the end of the file, will not terminate. We thus add the following code:<\/p>\n<p>sleep(4)<\/p>\n<p>twm.stop()<\/p>\n<p>I.e., we sleep for a few seconds to let the messages come in, and then terminate the socket manager (and the program overall).<\/p>\n<p>And for this line (stopping the socket manager), I needed to fix the aforementioned library versions:<\/p>\n<p>pip install websockets==10.4<br \/>pip install aiohttp==3.8.5<\/p>\n<p>Without these, I was getting an error along the lines\u00a0of:<\/p>\n<p>Task exception was never retrieved<br \/>AttributeError: &#8216;ClientConnection&#8217; object has no attribute &#8216;fail_connection&#8217;<\/p>\n<p>And I could never finish the program without force-killing it. Thus, look out for\u00a0this.<\/p>\n<p>In total, the full code looks as\u00a0follows:<\/p>\n<p>import os<br \/>from time import sleep<\/p>\n<p>from binance import ThreadedWebsocketManager<br \/>from binance.client import Client<\/p>\n<p>api_key = os.environ.get(&#8220;binance_api&#8221;)<br \/>api_secret = os.environ.get(&#8220;binance_secret&#8221;)<br \/>client = Client(api_key, api_secret)<\/p>\n<p>twm = ThreadedWebsocketManager()<br \/>twm.start()<\/p>\n<p>def handle_socket_message(msg: str) -&gt; None:<br \/>    print(f&#8221;message type: {msg[&#8216;e&#8217;]}&#8221;)<br \/>    print(msg)<\/p>\n<p>btc_ticker = twm.start_symbol_ticker_socket(<br \/>    callback=handle_socket_message, symbol=&#8221;BTCUSDT&#8221;<br \/>)<\/p>\n<p>sleep(4)<\/p>\n<p>twm.stop()<\/p>\n<p>Now let\u2019s analyze what\u2019s inside the messages we get from the ticker. Our callback prints something along the lines\u00a0of:<\/p>\n<p>message type: 24hrTicker<br \/>{&#8216;e&#8217;: &#8217;24hrTicker&#8217;, &#8216;E&#8217;: 1731260966852, &#8216;s&#8217;: &#8216;BTCUSDT&#8217;, &#8216;p&#8217;: &#8216;4176.51000000&#8217;, &#8216;P&#8217;: &#8216;5.491&#8217;, &#8216;w&#8217;: &#8216;78679.91492173&#8217;, &#8216;x&#8217;: &#8216;76065.49000000&#8217;, &#8216;c&#8217;: &#8216;80242.00000000&#8217;, &#8216;Q&#8217;: &#8216;0.01631000&#8217;, &#8216;b&#8217;: &#8216;80242.00000000&#8217;, &#8216;B&#8217;: &#8216;1.32691000&#8217;, &#8216;a&#8217;: &#8216;80242.01000000&#8217;, &#8216;A&#8217;: &#8216;6.20730000&#8217;, &#8216;o&#8217;: &#8216;76065.49000000&#8217;, &#8216;h&#8217;: &#8216;80349.00000000&#8217;, &#8216;l&#8217;: &#8216;76065.49000000&#8217;, &#8216;v&#8217;: &#8216;46358.04002900&#8217;, &#8216;q&#8217;: &#8216;3647446645.41970462&#8217;, &#8216;O&#8217;: 1731174566851, &#8216;C&#8217;: 1731260966851, &#8216;F&#8217;: 4028251704, &#8216;L&#8217;: 4033956844, &#8216;n&#8217;: 5705141}<\/p>\n<p>To decode the meaning of this (same for any future messages you might need), one can always look at the <a href=\"https:\/\/binance-docs.github.io\/apidocs\/spot\/en\/#all-market-mini-tickers-stream\">official Binance API docs<\/a>. There, we find the following information:<\/p>\n<p><a href=\"https:\/\/binance-docs.github.io\/apidocs\/spot\/en\/#all-market-mini-tickers-stream\">https:\/\/binance-docs.github.io\/apidocs\/spot\/en\/#all-market-mini-tickers-stream<\/a><\/p>\n<p>And with that, we have all the information we need. For example, we know now that the entry \u201cc\u201d contains the current \/ last price, i.e. the quantity we were looking\u00a0for.<\/p>\n<h3>Retrieving Historic Price Information<\/h3>\n<p>Often, we are further interested in historic prices of assets. A lot of trading strategies use some form of patterns in order to detect good timepoints to buy and sell assets, and many of these use historic information\u200a\u2014\u200asuch as the <a href=\"https:\/\/www.investopedia.com\/terms\/g\/goldencross.asp\">Golden cross<\/a>. This compares the historic average of an asset vs. its current price, and signals a buy indication whenever the current price \u201cbreaks\u201d the line of the historic\u00a0average.<\/p>\n<p>To obtain historic prices, similar as before we can use direct API calls or websockets\u200a\u2014\u200ajust the output is a bit different.<\/p>\n<p>Let\u2019s query the price of ETH over the last seven days and examine the returned\u00a0value:<\/p>\n<p>klines = client.get_historical_klines(<br \/>    &#8220;ETHUSDT&#8221;, Client.KLINE_INTERVAL_1DAY, &#8220;7 days ago UTC&#8221;<br \/>)<\/p>\n<p>We asked for historic ETH prices for the last seven days, with an interval of one day\u200a\u2014\u200ai.e., the return contains a list of length seven. Each of these now contains a <a href=\"https:\/\/www.linkedin.com\/pulse\/what-k-line-candlestick-chart-fundamentals-ftftx-global\">K-line or candlestick<\/a>, which is a common representation in the field of trading. The candlesticks we get are <a href=\"https:\/\/www.programcreek.com\/python\/?CodeExample=get+klines\">lists of length 12<\/a>, with the first seven values denoting:<\/p>\n<p>open timeopen pricehighest pricelowest priceclosing pricetrading volumeclosing time<\/p>\n<p>The format for these queries needs some time getting used to in my opinion\u200a\u2014\u200ayou can express desired intervals and duration in many ways\u200a\u2014\u200aI would recommend reading the docs and provided examples for a\u00a0bit.<\/p>\n<p>For the websocket approach, execute the following code:<\/p>\n<p>import os<br \/>from time import sleep<\/p>\n<p>from binance import ThreadedWebsocketManager<br \/>from binance.client import Client<\/p>\n<p>api_key = os.environ.get(&#8220;binance_api&#8221;)<br \/>api_secret = os.environ.get(&#8220;binance_secret&#8221;)<br \/>client = Client(api_key, api_secret)<\/p>\n<p>twm = ThreadedWebsocketManager()<br \/>twm.start()<\/p>\n<p>def handle_socket_message(msg: str) -&gt; None:<br \/>    print(f&#8221;message type: {msg[&#8216;e&#8217;]}&#8221;)<br \/>    print(msg)<\/p>\n<p>twm.start_kline_socket(callback=handle_socket_message, symbol=&#8221;ETHUSDT&#8221;)<\/p>\n<p>sleep(4)<\/p>\n<p>twm.stop()<\/p>\n<p>There should not be any surprises after seeing the first websocket application above. To understand the returned messages, <a href=\"https:\/\/binance-docs.github.io\/apidocs\/spot\/en\/#kline-candlestick-streams-for-utc\">here\u2019s<\/a> the full description.<\/p>\n<h3>Buying and Selling\u00a0Crypto<\/h3>\n<p>Next, let\u2019s come to (possibly?) the most awaited feature: automatically buying and selling crypto coins (hopefully with a hefty\u00a0gain).<\/p>\n<p>We begin with market orders, and then explain limit\u00a0orders.<\/p>\n<h4>Market Orders<\/h4>\n<p>Market orders maybe are slightly easier: they simply buy \/ sell the selected coin to the current market\u00a0price.<\/p>\n<p>This can be as simple as\u00a0this:<\/p>\n<p>buy_order = client.order_market_buy(symbol=&#8221;BNBUSDT&#8221;, quantity=0.01)<\/p>\n<p>Conversely, we can sell the 0.01 BNB we acquired above\u00a0via:<\/p>\n<p>sell_order = client.order_market_sell(symbol=&#8221;BNBUSDT&#8221;, quantity=0.01)<\/p>\n<p>The variables buy_order and sell_order eventually contain order summaries\u200a\u2014\u200ausually indicating the trades were immediately executed (indicated by the status \u201cFilled\u201d). For different outcomes, stay tuned till the next\u00a0section.<\/p>\n<p>There is one thing to consider though: we cannot trade arbitrary quantities. There are several filters which define ranges and minimal step sizes between quantities. We can query these\u00a0via:<\/p>\n<p>client.get_symbol_info(asset_pair)<\/p>\n<p>I will not go over all filters returned by this function, but only describe those which I mostly came across (and which should probably cover 99% of your use cases)\u200a\u2014\u200aand then list two nice convenience function, turning an arbitrary buy \/ sell amount into a valid one. The most important filters\u00a0are:<\/p>\n<p><strong>precision<\/strong>: this denotes the number of decimal digits a coin is\u00a0using.<strong>lot size<\/strong>: there is a minimal and maximal lot size (a buy \/ sell quantity), and a step size between allowed quantities.<strong>notional value<\/strong>: minimal and maximal values which can be traded in the base currency. Consider the trading pair BNB-USDT with a minimal notion value of 5. This expresses, that one can trade only BNB with a value above 5\u00a0USDT.<\/p>\n<p>We first define a function reducing the vast amount of symbol information we get into just the filters listed\u00a0above:<\/p>\n<p>import math<br \/>from typing import Any<\/p>\n<p>from binance.client import Client<\/p>\n<p>def get_symbol_info(client: Client, asset_pair: str) -&gt; dict[str, Any]:<br \/>    full_symbol_info = client.get_symbol_info(asset_pair)<br \/>    if not full_symbol_info:<br \/>        raise ValueError(f&#8221;Did not find pair {asset_pair}&#8221;)<\/p>\n<p>    symbol_info = {&#8220;precision&#8221;: full_symbol_info[&#8220;quotePrecision&#8221;]}<br \/>    filters = {f[&#8220;filterType&#8221;]: f for f in full_symbol_info[&#8220;filters&#8221;]}<\/p>\n<p>    symbol_info[&#8220;lot_size&#8221;] = {<br \/>        &#8220;min&#8221;: float(filters[&#8220;LOT_SIZE&#8221;][&#8220;minQty&#8221;]),<br \/>        &#8220;max&#8221;: float(filters[&#8220;LOT_SIZE&#8221;][&#8220;maxQty&#8221;]),<br \/>        &#8220;step&#8221;: float(filters[&#8220;LOT_SIZE&#8221;][&#8220;stepSize&#8221;]),<br \/>    }<br \/>    symbol_info[&#8220;notional&#8221;] = {<br \/>        &#8220;min&#8221;: float(filters[&#8220;NOTIONAL&#8221;][&#8220;minNotional&#8221;]),<br \/>        &#8220;max&#8221;: float(filters[&#8220;NOTIONAL&#8221;][&#8220;maxNotional&#8221;]),<br \/>    }<\/p>\n<p>    return symbol_info<\/p>\n<p>Then, the following function adheres to all described filters and gives the next-best quantity we can buy given a desired buy quantity:<\/p>\n<p>def get_valid_buy_quantity(<br \/>    client: Client, trading_pair: str, desired_value_quote: float<br \/>) -&gt; float:<br \/>    &#8220;&#8221;&#8221;Converts the desired buy value to an allowed one<br \/>    respecting all filters.<\/p>\n<p>    Args:<br \/>        client: Binance client<br \/>        trading_pair: trading pair to buy (e.g. BNBUSDT)<br \/>        desired_value_base: amount to buy in QUOTE value (e.g. USDT)<\/p>\n<p>    Returns:<br \/>        fixed buy value as base quantity (e.g. BNB)<br \/>    &#8220;&#8221;&#8221;<br \/>    symbol_info = get_symbol_info(client, trading_pair)<\/p>\n<p>    current_price = float(client.get_symbol_ticker(symbol=trading_pair)[&#8220;price&#8221;])<br \/>    buy_quantity = desired_value_quote \/ current_price<\/p>\n<p>    # Clip to [min, max] notional value<br \/>    buy_quantity = max(buy_quantity, symbol_info[&#8220;notional&#8221;][&#8220;min&#8221;] \/ current_price)<br \/>    buy_quantity = min(buy_quantity, symbol_info[&#8220;notional&#8221;][&#8220;max&#8221;] \/ current_price)<\/p>\n<p>    # Round to precision<br \/>    buy_quantity = round(buy_quantity, symbol_info[&#8220;precision&#8221;])<\/p>\n<p>    # Clip to [min, max] lot size, round to step size<br \/>    buy_quantity = round(<br \/>        buy_quantity, int(math.log10(1 \/ symbol_info[&#8220;lot_size&#8221;][&#8220;step&#8221;]))<br \/>    )<br \/>    buy_quantity = max(buy_quantity, symbol_info[&#8220;lot_size&#8221;][&#8220;min&#8221;])<br \/>    buy_quantity = min(buy_quantity, symbol_info[&#8220;lot_size&#8221;][&#8220;max&#8221;])<\/p>\n<p>    print(<br \/>        f&#8221;Requested buying {desired_value_quote} QUOTE of {trading_pair}. Adhering to filters gave a post-processed value of {buy_quantity} BASE, equal to approximately {buy_quantity * current_price} QUOTE&#8221;<br \/>    )<\/p>\n<p>    return buy_quantity<\/p>\n<p>Attention: this might alter your buy order (significantly, depending on the coin)\u200a\u2014\u200abe careful when executing this!<\/p>\n<p>Let\u2019s discuss this a bit more. We here again use the notion of a trading pair, also mentioned before. This is for example BNB-USDT. The first entry is called <em>BASE<\/em>, the second <em>QUOTE<\/em>. Our buy function expects a value in QUOTE, such as: \u201cbuy me BNB worth 10 USDT\u201d. We first get the relevant filter information as described above, and then determine the quantity the user intends to buy (buy_quantity \/ current_price). Next, we clip the quantity to be inside the allowed notional ranges. Then, we round to precision\u200a\u2014\u200aand also clip the quantity to adhere to the minimal and maximal lot size, and round to the corresponding step\u00a0size.<\/p>\n<p>Eventually, we print the resulting quantity and it\u2019s deviation from what was asked for by the user. This could look like\u00a0this:<\/p>\n<p>Requested buying 1 QUOTE of BNBUSDT. Adhering to filters gave a post-processed value of 0.008 BASE, equal to approximately 5.13024 QUOTE<\/p>\n<p>Again, attention\u200a\u2014\u200ait might be useful to add a user prompt confirming or rejecting the requested trade.<\/p>\n<p>Our function for selling looks very similar (and in fact, we could \/ should re-use some of the code\u00a0parts):<\/p>\n<p>def get_valid_sell_quantity(<br \/>    client: Client, trading_pair: str, desired_sell_quantiy: float<br \/>) -&gt; float:<br \/>    &#8220;&#8221;&#8221;Converts the requested sell quantity into an allowed one respecting all filters.<\/p>\n<p>    Args:<br \/>        client : Binance client<br \/>        trading_pair: trading pair to sell (e.g. BNBUSDT)<br \/>        desired_sell_quantiy: desired amount to sell in BASE<\/p>\n<p>    Returns:<br \/>        fixed amount to sell in BASE<br \/>    &#8220;&#8221;&#8221;<br \/>    symbol_info = get_symbol_info(client, trading_pair)<\/p>\n<p>    current_price = float(client.get_symbol_ticker(symbol=trading_pair)[&#8220;price&#8221;])<\/p>\n<p>    # Clip to [min, max] notional value<br \/>    sell_quantity = max(<br \/>        desired_sell_quantiy, symbol_info[&#8220;notional&#8221;][&#8220;min&#8221;] \/ current_price<br \/>    )<br \/>    sell_quantity = min(sell_quantity, symbol_info[&#8220;notional&#8221;][&#8220;max&#8221;] \/ current_price)<\/p>\n<p>    # Round to precision<br \/>    sell_quantity = round(sell_quantity, symbol_info[&#8220;precision&#8221;])<\/p>\n<p>    # Clip to [min, max] lot size, round to step size<br \/>    sell_quantity = round(<br \/>        sell_quantity, int(math.log10(1 \/ symbol_info[&#8220;lot_size&#8221;][&#8220;step&#8221;]))<br \/>    )<br \/>    sell_quantity = max(sell_quantity, symbol_info[&#8220;lot_size&#8221;][&#8220;min&#8221;])<br \/>    sell_quantity = min(sell_quantity, symbol_info[&#8220;lot_size&#8221;][&#8220;max&#8221;])<\/p>\n<p>    print(<br \/>        f&#8221;Requested selling {desired_sell_quantiy} {trading_pair}. Adhering to filters gave a post-processed value of {sell_quantity}, equal to approximately {sell_quantity * current_price} BASE&#8221;<br \/>    )<\/p>\n<p>    return sell_quantity<\/p>\n<p>For this function, we specify the desired sell amount in BASE, i.e. \u201csell 10 BNB\u201d\u200a\u2014\u200aand the rest works analogously.<\/p>\n<p>The following code shows how these functions could be used together:<\/p>\n<p>import os<\/p>\n<p>from binance.client import Client<\/p>\n<p>from utils import get_valid_buy_quantity, get_valid_sell_quantity<\/p>\n<p>api_key = os.environ.get(&#8220;binance_api&#8221;)<br \/>api_secret = os.environ.get(&#8220;binance_secret&#8221;)<br \/>client = Client(api_key, api_secret)<\/p>\n<p>buy_qty = get_valid_buy_quantity(client, &#8220;BNBUSDT&#8221;, 1)<br \/>buy_order = client.order_market_buy(symbol=&#8221;BNBUSDT&#8221;, quantity=buy_qty)<\/p>\n<p>sell_qty = get_valid_sell_quantity(client, &#8220;BNBUSDT&#8221;, buy_qty)<br \/>sell_order = client.order_market_sell(symbol=&#8221;BNBUSDT&#8221;, quantity=sell_qty)<\/p>\n<h4>Limit Orders<\/h4>\n<p>Next, we come to limit orders. These are planned orders, which are executed once the market reaches a desired price (for buying: execute the trade when the price falls low enough, for selling: sell when the price reaches the desired threshold).<\/p>\n<p>To create a limit order buying 0.1 BNB when the price reaches 500 USDT or below,\u00a0run:<\/p>\n<p>buy_order = client.order_limit_buy(<br \/>    symbol=&#8217;BNBUSDT&#8217;,<br \/>    quantity=0.1,<br \/>    price=500)<\/p>\n<p>Note that the specified price cannot be too far below the current price (same for selling, just in the other direction)\u200a\u2014\u200ato avoid market manipulation and improve stability.<\/p>\n<p>Now, when inspecting buy_order, we see the status \u201cNew\u201d\u200a\u2014\u200aas well as an empty field fills\u200a\u2014\u200aindicating the order was not yet executed. Note the order is valid till cancellation, if you did not set an expiration date.<\/p>\n<p>To query all active orders,\u00a0run:<\/p>\n<p>client.get_open_orders()<\/p>\n<p>And to cancel the order,\u00a0execute:<\/p>\n<p>client.cancel_order(symbol=buy_order[&#8220;symbol&#8221;], orderId=buy_order[&#8220;orderId&#8221;])<\/p>\n<p>For selling, we can analogously run:<\/p>\n<p>sell_order = client.order_limit_sell(<br \/>    symbol=&#8217;BNBUSDT&#8217;,<br \/>    quantity=0.1,<br \/>    price=800)<\/p>\n<p>This will sell 0.1 BNB in case the price reaches 800 USDT or\u00a0above.<\/p>\n<h3>Transfering Crypto<\/h3>\n<p>Lastly, let\u2019s come to sending crypto to another address (also known as withdrawing\u200a\u2014\u200ayour withdrawing coins from your account and adding it to another).<\/p>\n<p>To do this, we can simply\u00a0run:<\/p>\n<p>result = client.withdraw(<br \/>    coin=&#8221;{COIN}&#8221;, address=&#8221;{ADDRESS}&#8221;, amount={AMOUNT}, network=&#8221;{NETWORK}&#8221;<br \/>)<\/p>\n<p>Concretely, let\u2019s say for example, you want to buy me a (real) coffee using BNB, you can execute the following code:<\/p>\n<p>result = client.withdraw(<br \/>    coin=&#8221;BNB&#8221;, address=&#8221;0x73c3F0A96094E31fC3168f915e4Deb9D8Ff5239F&#8221;, amount=0.01, network=&#8221;BSC&#8221;<br \/>)<\/p>\n<p>We have selected BNB and the BSC network, my wallet address and an amount of 0.01 BNB. Again, caution! This will transfer the specified funds from your account. Also watch the current BNB price\u200a\u2014\u200aI\u2019m (still) paying Euros for my coffee\u200a\u2014\u200aand who knows how high we\u2019ll get\u00a0\ud83d\ude42<\/p>\n<h3>Conclusion<\/h3>\n<p>This brings us to the end of this post, where we provided a comprehensive introduction to python-binance, the most popular Python wrapper for programmatically accessing Binance, the world\u2019s largest cryptocurrency exchange.<\/p>\n<p>We covered setting up your Python environment and configuring your Binance account for API access. We demonstrated how to query account details, like available balances, and retrieve both current and historical crypto prices. Next, we walked through automating crypto trades, starting with market orders and then moving on to limit orders. Along the way, we explained Binance\u2019s trading filters that restrict quantities and prices and showed how to calculate these appropriately. Finally, we detailed how to send crypto to other accounts.<\/p>\n<p>All the code examples are available on <a href=\"https:\/\/github.com\/cryptoexplainer\/crypto_bot\/tree\/main\/crypto_bot\">GitHub<\/a>. Thank you very much for reading! If you enjoyed this content, please consider leaving some claps and following me to stay updated on future posts. And if you\u2019d like to support my work, sending a virtual crypto coffee (details above) would be greatly appreciated\u200a\u2014\u200ait helps me grow this channel and continue contributing to the community.<\/p>\n<p>See you next\u00a0time!<\/p>\n<p><a href=\"https:\/\/medium.com\/coinmonks\/automated-crypto-trading-with-python-and-binance-544f2ca1f204\">Automated Crypto Trading with Python and Binance<\/a> was originally published in <a href=\"https:\/\/medium.com\/coinmonks\">Coinmonks<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>Introduction to python-binance With the introduction of Bitcoin 15 years ago, a new asset class emerged: cryptocurrency. While everyone must consider their own risk tolerance, there\u2019s no denying that crypto investments have experienced incredible highs and impressive returns, as well as devastating lows and significant losses. One defining feature of the crypto market is its [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-20096","post","type-post","status-publish","format-standard","hentry","category-interesting"],"_links":{"self":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/20096"}],"collection":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=20096"}],"version-history":[{"count":0,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=\/wp\/v2\/posts\/20096\/revisions"}],"wp:attachment":[{"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=20096"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=20096"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mycryptomania.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=20096"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}