Generate ASCII Graphs of Cryptocurrency Prices in Python
Tags: python, cryptocurrency, lambda, programming
Published: 2023-04-02 23:05:44

### Have you ever wanted to visualize the historical prices of a cryptocurrency in a fun and interactive way? Well, look no further! In this article, we'll explore how to generate an ASCII graph of cryptocurrency prices using Python.


#### Disclaimer: 
The author of this article is not affiliated with *Binance* in any way. This code was written to retrieve and visualize data, which the author found to be useful and accessible without requiring an API key. The author is not responsible for any errors or issues that may arise from using this code.

### Example
```
$ python3 ascii-currency-graphs.py --pair BTCEUR --start-date 2023-03-14 --end-date 2023-04-01
2023-03-14T01:00:00 ########################################### 22985.84
2023-03-15T01:00:00 ########################################### 23026.80
2023-03-16T01:00:00 ############################################ 23665.73
2023-03-17T01:00:00 ################################################ 25789.77
2023-03-18T01:00:00 ############################################### 25373.59
2023-03-19T01:00:00 ################################################## 26474.44
2023-03-20T01:00:00 ################################################# 26082.53
2023-03-21T01:00:00 ################################################# 26324.74
2023-03-22T01:00:00 ############################################### 25342.45
2023-03-23T01:00:00 ################################################# 26260.20
2023-03-24T01:00:00 ################################################ 25746.57
2023-03-25T01:00:00 ################################################ 25735.12
2023-03-26T01:00:00 ################################################# 26076.46
2023-03-27T02:00:00 ############################################### 25267.76
2023-03-28T02:00:00 ############################################### 25189.56
2023-03-29T02:00:00 ################################################# 26188.76
2023-03-30T02:00:00 ################################################ 25798.34
2023-03-31T02:00:00 ################################################# 26332.77
```

### Raw Data 

Here you can check the data that we get from Binance. The below presented script (*The Code*) receives it for command:
```bash
python3 ascii-currency-graphs.py --pair BTCEUR --start-date 2023-04-01 --end-date 2023-04-05
```

```json
[
  [
    1680307200000,
    "26330.62000000",
    "26633.95000000",
    "26127.13000000",
    "26315.71000000",
    "494.04749000",
    1680393599999,
    "13008528.45896390",
    50549,
    "256.75654000",
    "6762406.03339990",
    "0"
  ],
  [
    1680393600000,
    "26319.67000000",
    "26403.97000000",
    "25828.00000000",
    "26184.72000000",
    "571.36554000",
    1680479999999,
    "14920527.65324270",
    55327,
    "277.62573000",
    "7250885.00425640",
    "0"
  ],
  [
    1680480000000,
    "26187.25000000",
    "26349.00000000",
    "25221.16000000",
    "25662.56000000",
    "1681.40230000",
    1680566399999,
    "43525785.31802880",
    100106,
    "868.39176000",
    "22493356.97115660",
    "0"
  ],
  [
    1680566400000,
    "25662.15000000",
    "26182.85000000",
    "25488.59000000",
    "25795.05000000",
    "1008.78663000",
    1680652799999,
    "26053821.41279880",
    80241,
    "579.95600000",
    "14980595.35159550",
    "0"
  ]
]

```


### The Code

```Python
import argparse
import datetime
import requests


def iso_date(date_string):
    """Convert ISO-formatted date string to timestamp."""
    try:
        date = datetime.datetime.strptime(date_string, '%Y-%m-%d')
        timestamp = int(date.timestamp() * 1000)
        return timestamp
    except ValueError:
        raise argparse.ArgumentTypeError(
            f"Invalid date format: {date_string}. Date should be in the format YYYY-MM-DD."
        )


def get_crypto_prices(start_timestamp, end_timestamp, pair):
    """Retrieve historical prices for the specified trading pair and date range."""
    start_date = datetime.date.fromtimestamp(start_timestamp / 1000)
    end_date = datetime.date.fromtimestamp(end_timestamp / 1000)

    symbol = pair.replace(':', '').replace('_', '').upper()
    url = f"https://api.binance.com/api/v3/klines?symbol={symbol}&interval=1d&startTime={start_timestamp}&endTime={end_timestamp}"
    response = requests.get(url)

    if response.status_code == 200:
        prices = response.json()
        return [(datetime.datetime.fromtimestamp(int(price[0]) / 1000).isoformat(), float(price[4])) for price in prices]
    else:
        print(f"Failed to retrieve prices for {pair} from {start_date} - {end_date}")
        return []


def generate_ascii_graph(data):
    """Generate an ASCII graph of cryptocurrency prices."""
    max_price = max(data, key=lambda x: x[1])[1]

    for date, price in data:
        bar = '#' * int(price / max_price * 50)
        print(f"{date} {bar} {price:.2f}")


def list_cryptocurrencies():
    """List all possible cryptocurrencies supported by the Binance API."""
    url = 'https://api.binance.com/api/v3/exchangeInfo'
    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()
        symbols = data['symbols']
        currencies = set()

        for symbol in symbols:
            base_currency = symbol['baseAsset']
            quote_currency = symbol['quoteAsset']
            currencies.add(base_currency)
            currencies.add(quote_currency)

        print("Available cryptocurrencies on Binance:")
        for currency in sorted(currencies):
            print(currency)
    else:
        print("Failed to retrieve list of cryptocurrencies from Binance.")


if __name__ == '__main__':
    # Parse command-line arguments
    parser = argparse.ArgumentParser(description="Generate an ASCII graph of cryptocurrency prices for a given date range")
    parser.add_argument("--pair", help="Trading pair for the historical data in the format 'BTC:USDT' or 'BTCUSDT'", default='BTCUSDT')
    parser.add_argument("--list", help="List all possible cryptocurrencies supported by the Binance API", action='store_true')
    parser.add_argument("--start-date", type=iso_date, help="Start date (in YYYY-MM-DD format) for the historical data", default=int((datetime.datetime.now() - datetime.timedelta(days=1)).timestamp() * 1000))
    parser.add_argument("--end-date", type=iso_date, help="End date (in YYYY-MM-DD format) for the historical data", default=int(datetime.datetime.now().timestamp() * 1000))
    args = parser.parse_args()

    if args.list:
        list_cryptocurrencies()
    else:
        # Retrieve and process cryptocurrency prices
        prices = get_crypto_prices(args.start_date, args.end_date, args.pair)
        if prices:
            generate_ascii_graph(prices)
```

### What does this code do?

This Python code retrieves historical prices for a specified cryptocurrency trading pair from the Binance API and generates an ASCII graph of the prices for the specified date range. It also allows you to list all possible cryptocurrencies supported by the Binance API. You can easily run this code from the command line and get a cool visualization of the cryptocurrency prices.

### How can you add it to your .bashrc or MOTD regenerator?

If you're feeling adventurous, you can add this code to your .bashrc or MOTD regenerator for fun and profit! Just call the script to your .bashrc or MOTD regenerator. Now, every time you open your terminal or log in to your server, you'll be greeted with a visualization of the current cryptocurrency prices!

### How does the code work?

#### Parsing Command-Line Arguments

The code uses Python's built-in `argparse` module to parse command-line arguments. The `parser.add_argument()` method is used to define the different arguments that the script accepts. For example, the `--pair` argument is used to specify the trading pair for the historical data, while the `--start-date` and `--end-date` arguments are used to specify the date range for the historical data. The `--list` argument is used to list all possible cryptocurrencies supported by the Binance API. 

#### Retrieving Historical Data

The `get_crypto_prices()` function retrieves historical prices for a specified cryptocurrency trading pair and date range from the Binance API. It uses the `requests` module to make an HTTP GET request to the Binance API, and then parses the JSON response to extract the historical prices. The function returns a list of tuples, where each tuple contains a date and a price.

#### Generating an ASCII Graph

The `generate_ascii_graph()` function takes a list of tuples containing dates and prices, and generates an ASCII graph of the prices. It first determines the maximum price in the dataset using a lambda function that calls the `max` function with a `key` argument of `lambda x: x[1]`. This specifies that we want to get the maximum price based on the second element of each tuple in the dataset. It then loops through the data and generates a bar chart for each data point, with the length of the bar proportional to the price relative to the maximum price.

#### Listing All Cryptocurrencies Supported by Binance

The `list_cryptocurrencies()` function retrieves a list of all possible cryptocurrencies supported by the Binance API. It makes an HTTP GET request to the Binance API and parses the JSON response to extract the list of symbols. It then extracts the base and quote currencies from each symbol and adds them to a set of unique currencies. Finally, it prints out the set of unique currencies in alphabetical order.

### Lambda Explained

One interesting part of this code is the use of a lambda function to get the maximum price in the dataset. A lambda function is a small anonymous function that can have any number of arguments, but can only have one expression. In this code, we use a lambda function to get the maximum price in the dataset by calling the `max` function with a `key` argument of `lambda x: x[1]`. This specifies that we want to get the maximum price based on the second element of each tuple in the dataset. If you're interested in learning more about lambda functions, check out the [official Python documentation](https://docs.python.org/3/reference/expressions.html#lambda).


### Example Usage

Here are some example usage scenarios for this code (written in 2023 ;-)):

- To get the historical prices for BTCUSDT from the past week and generate an ASCII graph:
```Python
python ascii-currency-graphs.py --pair BTCUSDT --start-date 2023-03-26 --end-date 2023-04-02
```

- To get the historical prices for ETHBTC from the past year and generate an ASCII graph:
```Python
python ascii-currency-graphs.py --pair ETHBTC --start-date 2022-04-02`
```

- To list all possible cryptocurrencies supported by the Binance API:
```Python
python ascii-currency-graphs.py --list
```



### Conclusion

In this article, we learned how to generate an ASCII graph of cryptocurrency prices using Python. We explored the different parts of the code and how to use it from the command line. We also learned about lambda functions and how they can be used in Python. Now, go forth and visualize those cryptocurrency prices in style!

### Next read

Stay tuned for the next article in this series, where we will build upon this code to generate PNG graphs with financial trendlines. This will give us a better understanding of the historical performance of cryptocurrencies and help us make informed decisions about our investments.