From f3b515725cbf8a8d382c6d14604286865f4cc9a3 Mon Sep 17 00:00:00 2001 From: codez0mb1e Date: Thu, 23 Jun 2022 12:50:00 +0000 Subject: [PATCH] Binance lab --- src/candidate_tests.ipynb | 1276 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1276 insertions(+) create mode 100644 src/candidate_tests.ipynb diff --git a/src/candidate_tests.ipynb b/src/candidate_tests.ipynb new file mode 100644 index 0000000..643e5f9 --- /dev/null +++ b/src/candidate_tests.ipynb @@ -0,0 +1,1276 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A little non-economic research\n", + "\n", + "\n", + "## Existing quiz tests\n", + "\n", + "https://www.linkedin.com/skill-assessments/hub/quizzes/ \n", + "\n", + "![](../docs/li.png)\n", + "\n", + "https://www.w3schools.com/quiztest/quiztest.asp?qtest=PANDAS\n", + "\n", + "\n", + "![](../docs/w3.png)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Code interview\n", + "\n", + "Datasets:\n", + "\n", + "1. Binance Open Data: [spot candles](https://github.com/binance/binance-public-data/#klines)\n", + "2. OpenFIGI: [search API](https://www.openfigi.com/search).\n", + "\n", + "### Binance Open Data\n", + "\n", + "Downloading candles for `BTC/USDT` and `BTC/UDSC` using `bash` or `powershell`:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mkdir: cannot create directory ‘../data/binance’: File exists\n", + "--2022-06-23 12:48:13-- https://data.binance.vision/data/spot/daily/klines/BTCUSDT/1m/BTCUSDT-1m-2022-06-21.zip\n", + "Resolving data.binance.vision (data.binance.vision)... 13.224.2.90, 13.224.2.55, 13.224.2.128, ...\n", + "Connecting to data.binance.vision (data.binance.vision)|13.224.2.90|:443... connected.\n", + "HTTP request sent, awaiting response... 304 Not Modified\n", + "File ‘../data/binance/BTCUSDT-1m-2022-06-21.zip’ not modified on server. Omitting download.\n", + "\n", + "--2022-06-23 12:48:14-- https://data.binance.vision/data/spot/daily/klines/BTCUSDC/1m/BTCUSDC-1m-2022-06-21.zip\n", + "Resolving data.binance.vision (data.binance.vision)... 13.224.2.90, 13.224.2.55, 13.224.2.128, ...\n", + "Connecting to data.binance.vision (data.binance.vision)|13.224.2.90|:443... connected.\n", + "HTTP request sent, awaiting response... 304 Not Modified\n", + "File ‘../data/binance/BTCUSDC-1m-2022-06-21.zip’ not modified on server. Omitting download.\n", + "\n", + "Archive: ../data/binance/BTCUSDT-1m-2022-06-21.zip\n", + " inflating: ../data/binance/BTCUSDT-1m-2022-06-21.csv \n", + "Archive: ../data/binance/BTCUSDC-1m-2022-06-21.zip\n", + " inflating: ../data/binance/BTCUSDC-1m-2022-06-21.csv \n" + ] + } + ], + "source": [ + "#!/bin/sh\n", + "\n", + "# create dir for data\n", + "!mkdir ../data/binance\n", + "\n", + "# download data using GET request\n", + "!wget -N -P ../data/binance https://data.binance.vision/data/spot/daily/klines/BTCUSDT/1m/BTCUSDT-1m-2022-06-21.zip\n", + "!wget -N -P../data/binance https://data.binance.vision/data/spot/daily/klines/BTCUSDC/1m/BTCUSDC-1m-2022-06-21.zip\n", + "\n", + "# unzip\n", + "!unzip -o -d ../data/binance ../data/binance/BTCUSDT-1m-2022-06-21.zip \n", + "!unzip -o -d ../data/binance ../data/binance/BTCUSDC-1m-2022-06-21.zip" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Import packages for data analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "import httpx\n", + "\n", + "from datetime import datetime" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Read data from CSV file to Pandas DataFrame:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01234567891011
0165576960000020573.9020590.0020552.1720558.3670.7692516557696599991.455321e+06115037.368217.683845e+050
1165576966000020558.3520611.2120558.3520606.70118.0603216557697199992.430514e+06140261.257601.260950e+060
2165576972000020606.6920626.8920552.4020552.40130.4289416557697799992.686026e+06143355.805731.149409e+060
3165576978000020552.4120585.6920539.0920578.89103.5631816557698399992.128819e+06130164.573461.327338e+060
4165576984000020578.8920579.9020537.5720554.4683.5550916557698999991.717907e+06109836.409447.485065e+050
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 4 5 \\\n", + "0 1655769600000 20573.90 20590.00 20552.17 20558.36 70.76925 \n", + "1 1655769660000 20558.35 20611.21 20558.35 20606.70 118.06032 \n", + "2 1655769720000 20606.69 20626.89 20552.40 20552.40 130.42894 \n", + "3 1655769780000 20552.41 20585.69 20539.09 20578.89 103.56318 \n", + "4 1655769840000 20578.89 20579.90 20537.57 20554.46 83.55509 \n", + "\n", + " 6 7 8 9 10 11 \n", + "0 1655769659999 1.455321e+06 1150 37.36821 7.683845e+05 0 \n", + "1 1655769719999 2.430514e+06 1402 61.25760 1.260950e+06 0 \n", + "2 1655769779999 2.686026e+06 1433 55.80573 1.149409e+06 0 \n", + "3 1655769839999 2.128819e+06 1301 64.57346 1.327338e+06 0 \n", + "4 1655769899999 1.717907e+06 1098 36.40944 7.485065e+05 0 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def get_data(pair: str) -> pd.DataFrame:\n", + " return pd.read_csv(f'../data/binance/{pair}-1m-2022-06-21.csv', header = None)\n", + "\n", + "btcusdt_df = get_data('BTCUSDT')\n", + "btcusdt_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set names to columns with 1m candles:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Open_timeOpenHighLowCloseVolumeClose_timeQuote_asset_volumeNumber_of_tradesTaker_buy_base_asset_volumeTaker_buy_quote_asset_volumeIgnore
0165576960000020573.9020590.0020552.1720558.3670.7692516557696599991.455321e+06115037.368217.683845e+050
1165576966000020558.3520611.2120558.3520606.70118.0603216557697199992.430514e+06140261.257601.260950e+060
2165576972000020606.6920626.8920552.4020552.40130.4289416557697799992.686026e+06143355.805731.149409e+060
3165576978000020552.4120585.6920539.0920578.89103.5631816557698399992.128819e+06130164.573461.327338e+060
4165576984000020578.8920579.9020537.5720554.4683.5550916557698999991.717907e+06109836.409447.485065e+050
\n", + "
" + ], + "text/plain": [ + " Open_time Open High Low Close Volume \\\n", + "0 1655769600000 20573.90 20590.00 20552.17 20558.36 70.76925 \n", + "1 1655769660000 20558.35 20611.21 20558.35 20606.70 118.06032 \n", + "2 1655769720000 20606.69 20626.89 20552.40 20552.40 130.42894 \n", + "3 1655769780000 20552.41 20585.69 20539.09 20578.89 103.56318 \n", + "4 1655769840000 20578.89 20579.90 20537.57 20554.46 83.55509 \n", + "\n", + " Close_time Quote_asset_volume Number_of_trades \\\n", + "0 1655769659999 1.455321e+06 1150 \n", + "1 1655769719999 2.430514e+06 1402 \n", + "2 1655769779999 2.686026e+06 1433 \n", + "3 1655769839999 2.128819e+06 1301 \n", + "4 1655769899999 1.717907e+06 1098 \n", + "\n", + " Taker_buy_base_asset_volume Taker_buy_quote_asset_volume Ignore \n", + "0 37.36821 7.683845e+05 0 \n", + "1 61.25760 1.260950e+06 0 \n", + "2 55.80573 1.149409e+06 0 \n", + "3 64.57346 1.327338e+06 0 \n", + "4 36.40944 7.485065e+05 0 " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def set_column_names(df: pd.DataFrame) -> pd.DataFrame:\n", + " column_names_mapping = {\n", + " 0: 'Open_time',\n", + " 1: 'Open',\n", + " 2: 'High',\n", + " 3: 'Low',\n", + " 4: 'Close',\n", + " 5: 'Volume',\n", + " 6: 'Close_time',\n", + " 7: 'Quote_asset_volume',\n", + " 8: 'Number_of_trades',\n", + " 9: 'Taker_buy_base_asset_volume',\n", + " 10: 'Taker_buy_quote_asset_volume',\n", + " 11: 'Ignore'\n", + " }\n", + " return df.rename(columns=column_names_mapping)\n", + "\n", + "btcusdt_df = set_column_names(btcusdt_df)\n", + "btcusdt_df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Convert timestamp to human-readable date and time format:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "btcusdt_df['Open_time'] = btcusdt_df.iloc[:, 0].apply(lambda t: datetime.fromtimestamp(t/1000))\n", + "btcusdt_df['Close_time'] = btcusdt_df.iloc[:, 6].apply(lambda t: datetime.fromtimestamp(t/1000))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Find min and max time:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Open_timeClose_time
min2022-06-21 00:00:002022-06-21 00:00:59.999000
max2022-06-21 23:59:002022-06-21 23:59:59.999000
len14401440
\n", + "
" + ], + "text/plain": [ + " Open_time Close_time\n", + "min 2022-06-21 00:00:00 2022-06-21 00:00:59.999000\n", + "max 2022-06-21 23:59:00 2022-06-21 23:59:59.999000\n", + "len 1440 1440" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "btcusdt_df[['Open_time', 'Close_time']].aggregate(func=[min, max, len])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculate 1-hour `OHLCV` candles:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OpenHighLowCloseVolumeClose_time
020573.9020705.7420396.7720672.304235.773922022-06-21 00:59:59.999
120672.3020783.9920504.8920670.883892.914122022-06-21 01:59:59.999
220670.8720699.9320348.4020433.492876.889282022-06-21 02:59:59.999
320433.4920665.2620365.0020614.043306.770182022-06-21 03:59:59.999
420614.0420740.7220474.4120656.172925.335422022-06-21 04:59:59.999
520656.1721029.9320621.1420890.776516.656112022-06-21 05:59:59.999
620890.7721202.0020890.7721192.086114.516622022-06-21 06:59:59.999
721192.0821333.0020952.4621120.285433.086032022-06-21 07:59:59.999
821120.2821500.0121051.2521356.326241.368012022-06-21 08:59:59.999
921356.3221470.0021166.9421200.004961.574962022-06-21 09:59:59.999
1021200.0121307.8321061.5421299.273982.475782022-06-21 10:59:59.999
1121299.0221361.0320911.1320962.424685.425242022-06-21 11:59:59.999
1220962.4221163.2420853.3621106.205596.263032022-06-21 12:59:59.999
1321106.1921650.0020995.6421619.318667.590802022-06-21 13:59:59.999
1421619.3121723.0021427.8221590.796295.024292022-06-21 14:59:59.999
1521590.7921604.2721339.0721392.193809.546222022-06-21 15:59:59.999
1621392.1821550.3921355.7721401.522421.776292022-06-21 16:59:59.999
1721401.5221457.8221195.7021242.943755.829192022-06-21 17:59:59.999
1821242.9321256.9921076.4821100.012820.406752022-06-21 18:59:59.999
1921100.0021306.5120870.0120888.644015.335282022-06-21 19:59:59.999
2020888.6320987.3820666.0020859.864442.875962022-06-21 20:59:59.999
2120859.8621054.9920808.0020972.911813.562362022-06-21 21:59:59.999
2220972.9121003.7020741.0320897.002945.616502022-06-21 22:59:59.999
2320897.0020943.1720551.0020723.522613.774412022-06-21 23:59:59.999
\n", + "
" + ], + "text/plain": [ + " Open High Low Close Volume Close_time\n", + "0 20573.90 20705.74 20396.77 20672.30 4235.77392 2022-06-21 00:59:59.999\n", + "1 20672.30 20783.99 20504.89 20670.88 3892.91412 2022-06-21 01:59:59.999\n", + "2 20670.87 20699.93 20348.40 20433.49 2876.88928 2022-06-21 02:59:59.999\n", + "3 20433.49 20665.26 20365.00 20614.04 3306.77018 2022-06-21 03:59:59.999\n", + "4 20614.04 20740.72 20474.41 20656.17 2925.33542 2022-06-21 04:59:59.999\n", + "5 20656.17 21029.93 20621.14 20890.77 6516.65611 2022-06-21 05:59:59.999\n", + "6 20890.77 21202.00 20890.77 21192.08 6114.51662 2022-06-21 06:59:59.999\n", + "7 21192.08 21333.00 20952.46 21120.28 5433.08603 2022-06-21 07:59:59.999\n", + "8 21120.28 21500.01 21051.25 21356.32 6241.36801 2022-06-21 08:59:59.999\n", + "9 21356.32 21470.00 21166.94 21200.00 4961.57496 2022-06-21 09:59:59.999\n", + "10 21200.01 21307.83 21061.54 21299.27 3982.47578 2022-06-21 10:59:59.999\n", + "11 21299.02 21361.03 20911.13 20962.42 4685.42524 2022-06-21 11:59:59.999\n", + "12 20962.42 21163.24 20853.36 21106.20 5596.26303 2022-06-21 12:59:59.999\n", + "13 21106.19 21650.00 20995.64 21619.31 8667.59080 2022-06-21 13:59:59.999\n", + "14 21619.31 21723.00 21427.82 21590.79 6295.02429 2022-06-21 14:59:59.999\n", + "15 21590.79 21604.27 21339.07 21392.19 3809.54622 2022-06-21 15:59:59.999\n", + "16 21392.18 21550.39 21355.77 21401.52 2421.77629 2022-06-21 16:59:59.999\n", + "17 21401.52 21457.82 21195.70 21242.94 3755.82919 2022-06-21 17:59:59.999\n", + "18 21242.93 21256.99 21076.48 21100.01 2820.40675 2022-06-21 18:59:59.999\n", + "19 21100.00 21306.51 20870.01 20888.64 4015.33528 2022-06-21 19:59:59.999\n", + "20 20888.63 20987.38 20666.00 20859.86 4442.87596 2022-06-21 20:59:59.999\n", + "21 20859.86 21054.99 20808.00 20972.91 1813.56236 2022-06-21 21:59:59.999\n", + "22 20972.91 21003.70 20741.03 20897.00 2945.61650 2022-06-21 22:59:59.999\n", + "23 20897.00 20943.17 20551.00 20723.52 2613.77441 2022-06-21 23:59:59.999" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def calculate_ohclv(df: pd.DataFrame) -> pd.DataFrame:\n", + " df['hour'] = df['Close_time'].apply(lambda t: t.hour)\n", + "\n", + " return (\n", + " df\n", + " .groupby(['hour'])\n", + " .agg(\n", + " {\n", + " 'Open': 'first',\n", + " 'High': max,\n", + " 'Low': min,\n", + " 'Close': 'last',\n", + " 'Volume': sum,\n", + " 'Close_time': max\n", + " }\n", + " )\n", + " .reset_index()\n", + " .drop(columns=['hour'])\n", + " )\n", + "\n", + "btcusdt_1h_df = calculate_ohclv(btcusdt_df)\n", + "btcusdt_1h_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Validate results:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "assert(\n", + " isinstance(btcusdt_1h_df, pd.DataFrame)\n", + " and btcusdt_1h_df.shape == (24, 6)\n", + " and not btcusdt_1h_df.isnull().any().any()\n", + " and btcusdt_1h_df.iloc[:, 0:5].ge(0).all().all()\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Do the same for `BTC/USDC` pair:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
OpenHighLowCloseVolumeClose_time
020549.6520703.0820371.7520647.35284.735212022-06-21 00:59:59.999
120648.0620771.0720482.8320646.88192.505132022-06-21 01:59:59.999
220644.7820672.9820331.3620406.71195.670232022-06-21 02:59:59.999
320402.2720649.9920331.4820585.98290.392102022-06-21 03:59:59.999
420586.6320721.1020449.5720632.33205.784592022-06-21 04:59:59.999
520640.3320999.0020594.5820866.07412.424772022-06-21 05:59:59.999
620873.2521178.0020873.2521169.64524.258942022-06-21 06:59:59.999
721166.5821300.0020913.4021097.44304.651132022-06-21 07:59:59.999
821097.2021471.9121023.6421327.56366.292012022-06-21 08:59:59.999
921342.7621448.2221144.2421182.12350.775432022-06-21 09:59:59.999
1021175.7521298.5221038.3021270.98526.666022022-06-21 10:59:59.999
1121273.7321336.9420887.1720948.96579.002002022-06-21 11:59:59.999
1220936.5921143.9920800.0021079.42452.072142022-06-21 12:59:59.999
1321079.4121629.3620968.2121592.69507.911902022-06-21 13:59:59.999
1421595.1321699.9821394.0521572.00445.739782022-06-21 14:59:59.999
1521571.9621671.3421314.9421370.87435.992372022-06-21 15:59:59.999
1621370.0821533.1421330.0021377.52243.103682022-06-21 16:59:59.999
1721377.8521434.5821168.5921220.14291.461372022-06-21 17:59:59.999
1821220.1421233.9421054.7221074.20423.058362022-06-21 18:59:59.999
1921074.8121279.5220851.1020866.39266.464882022-06-21 19:59:59.999
2020864.3120960.9820645.0320838.52330.795692022-06-21 20:59:59.999
2120838.5121057.0120780.2920958.2299.098362022-06-21 21:59:59.999
2220950.0720975.9220719.0220875.37177.082032022-06-21 22:59:59.999
2320880.7120916.8520527.9020699.78173.227972022-06-21 23:59:59.999
\n", + "
" + ], + "text/plain": [ + " Open High Low Close Volume Close_time\n", + "0 20549.65 20703.08 20371.75 20647.35 284.73521 2022-06-21 00:59:59.999\n", + "1 20648.06 20771.07 20482.83 20646.88 192.50513 2022-06-21 01:59:59.999\n", + "2 20644.78 20672.98 20331.36 20406.71 195.67023 2022-06-21 02:59:59.999\n", + "3 20402.27 20649.99 20331.48 20585.98 290.39210 2022-06-21 03:59:59.999\n", + "4 20586.63 20721.10 20449.57 20632.33 205.78459 2022-06-21 04:59:59.999\n", + "5 20640.33 20999.00 20594.58 20866.07 412.42477 2022-06-21 05:59:59.999\n", + "6 20873.25 21178.00 20873.25 21169.64 524.25894 2022-06-21 06:59:59.999\n", + "7 21166.58 21300.00 20913.40 21097.44 304.65113 2022-06-21 07:59:59.999\n", + "8 21097.20 21471.91 21023.64 21327.56 366.29201 2022-06-21 08:59:59.999\n", + "9 21342.76 21448.22 21144.24 21182.12 350.77543 2022-06-21 09:59:59.999\n", + "10 21175.75 21298.52 21038.30 21270.98 526.66602 2022-06-21 10:59:59.999\n", + "11 21273.73 21336.94 20887.17 20948.96 579.00200 2022-06-21 11:59:59.999\n", + "12 20936.59 21143.99 20800.00 21079.42 452.07214 2022-06-21 12:59:59.999\n", + "13 21079.41 21629.36 20968.21 21592.69 507.91190 2022-06-21 13:59:59.999\n", + "14 21595.13 21699.98 21394.05 21572.00 445.73978 2022-06-21 14:59:59.999\n", + "15 21571.96 21671.34 21314.94 21370.87 435.99237 2022-06-21 15:59:59.999\n", + "16 21370.08 21533.14 21330.00 21377.52 243.10368 2022-06-21 16:59:59.999\n", + "17 21377.85 21434.58 21168.59 21220.14 291.46137 2022-06-21 17:59:59.999\n", + "18 21220.14 21233.94 21054.72 21074.20 423.05836 2022-06-21 18:59:59.999\n", + "19 21074.81 21279.52 20851.10 20866.39 266.46488 2022-06-21 19:59:59.999\n", + "20 20864.31 20960.98 20645.03 20838.52 330.79569 2022-06-21 20:59:59.999\n", + "21 20838.51 21057.01 20780.29 20958.22 99.09836 2022-06-21 21:59:59.999\n", + "22 20950.07 20975.92 20719.02 20875.37 177.08203 2022-06-21 22:59:59.999\n", + "23 20880.71 20916.85 20527.90 20699.78 173.22797 2022-06-21 23:59:59.999" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "btcusdc_df = get_data('BTCUSDC')\n", + "btcusdc_df = set_column_names(btcusdc_df)\n", + "btcusdc_df['Close_time'] = btcusdc_df.iloc[:, 6].apply(lambda t: datetime.fromtimestamp(t/1000))\n", + "\n", + "btcusdc_1h_df = calculate_ohclv(btcusdc_df)\n", + "btcusdc_1h_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Join altogether:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "btcusdt_1h_df['pair'] = 'BTC-USDT'\n", + "btcusdc_1h_df['pair'] = 'BTC-USDC'\n", + "\n", + "candles_1h_df = pd.concat([btcusdt_1h_df, btcusdc_1h_df])\n", + "\n", + "assert(\n", + " isinstance(candles_1h_df, pd.DataFrame)\n", + " and candles_1h_df.shape == (48, 7)\n", + " and (candles_1h_df['pair'].unique() == ['BTC-USDT', 'BTC-USDC']).all()\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot something interesting... :bulb:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Enrich dataset using Open FIGI API Interaction" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "JSONDecodeError", + "evalue": "Expecting value: line 1 column 1 (char 0)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mJSONDecodeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m/home/dictator/apps/resistance/src/candidate.ipynb Cell 24'\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 5\u001b[0m json_response \u001b[39m=\u001b[39m response\u001b[39m.\u001b[39mjson()\n\u001b[1;32m 7\u001b[0m \u001b[39mreturn\u001b[39;00m pd\u001b[39m.\u001b[39mDataFrame\u001b[39m.\u001b[39mfrom_dict(json_response[\u001b[39m'\u001b[39m\u001b[39mresult\u001b[39m\u001b[39m'\u001b[39m], orient\u001b[39m=\u001b[39m\u001b[39m'\u001b[39m\u001b[39mcolumns\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[0;32m----> 9\u001b[0m send_request(\u001b[39m'\u001b[39;49m\u001b[39mBTCUSDT\u001b[39;49m\u001b[39m'\u001b[39;49m)\n", + "\u001b[1;32m/home/dictator/apps/resistance/src/candidate.ipynb Cell 24'\u001b[0m in \u001b[0;36msend_request\u001b[0;34m(ticker)\u001b[0m\n\u001b[1;32m 2\u001b[0m api_url \u001b[39m=\u001b[39m \u001b[39mf\u001b[39m\u001b[39m'\u001b[39m\u001b[39mhttps://www.openfigi.com/search/query?facetQuery=MARKET_SECTOR_DES:%22Curncy%22&num_rows=100&simpleSearchString=\u001b[39m\u001b[39m{\u001b[39;00mticker\u001b[39m}\u001b[39;00m\u001b[39m&start=0\u001b[39m\u001b[39m'\u001b[39m\n\u001b[1;32m 4\u001b[0m response \u001b[39m=\u001b[39m httpx\u001b[39m.\u001b[39mget(api_url)\n\u001b[0;32m----> 5\u001b[0m json_response \u001b[39m=\u001b[39m response\u001b[39m.\u001b[39;49mjson()\n\u001b[1;32m 7\u001b[0m \u001b[39mreturn\u001b[39;00m pd\u001b[39m.\u001b[39mDataFrame\u001b[39m.\u001b[39mfrom_dict(json_response[\u001b[39m'\u001b[39m\u001b[39mresult\u001b[39m\u001b[39m'\u001b[39m], orient\u001b[39m=\u001b[39m\u001b[39m'\u001b[39m\u001b[39mcolumns\u001b[39m\u001b[39m'\u001b[39m)\n", + "File \u001b[0;32m~/miniconda3/lib/python3.9/site-packages/httpx/_models.py:1517\u001b[0m, in \u001b[0;36mResponse.json\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 1515\u001b[0m \u001b[39mif\u001b[39;00m encoding \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n\u001b[1;32m 1516\u001b[0m \u001b[39mreturn\u001b[39;00m jsonlib\u001b[39m.\u001b[39mloads(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mcontent\u001b[39m.\u001b[39mdecode(encoding), \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mkwargs)\n\u001b[0;32m-> 1517\u001b[0m \u001b[39mreturn\u001b[39;00m jsonlib\u001b[39m.\u001b[39;49mloads(\u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mtext, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n", + "File \u001b[0;32m~/miniconda3/lib/python3.9/json/__init__.py:346\u001b[0m, in \u001b[0;36mloads\u001b[0;34m(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001b[0m\n\u001b[1;32m 341\u001b[0m s \u001b[39m=\u001b[39m s\u001b[39m.\u001b[39mdecode(detect_encoding(s), \u001b[39m'\u001b[39m\u001b[39msurrogatepass\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[1;32m 343\u001b[0m \u001b[39mif\u001b[39;00m (\u001b[39mcls\u001b[39m \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m object_hook \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m\n\u001b[1;32m 344\u001b[0m parse_int \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m parse_float \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m\n\u001b[1;32m 345\u001b[0m parse_constant \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m object_pairs_hook \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m \u001b[39mand\u001b[39;00m \u001b[39mnot\u001b[39;00m kw):\n\u001b[0;32m--> 346\u001b[0m \u001b[39mreturn\u001b[39;00m _default_decoder\u001b[39m.\u001b[39;49mdecode(s)\n\u001b[1;32m 347\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mcls\u001b[39m \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n\u001b[1;32m 348\u001b[0m \u001b[39mcls\u001b[39m \u001b[39m=\u001b[39m JSONDecoder\n", + "File \u001b[0;32m~/miniconda3/lib/python3.9/json/decoder.py:337\u001b[0m, in \u001b[0;36mJSONDecoder.decode\u001b[0;34m(self, s, _w)\u001b[0m\n\u001b[1;32m 332\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mdecode\u001b[39m(\u001b[39mself\u001b[39m, s, _w\u001b[39m=\u001b[39mWHITESPACE\u001b[39m.\u001b[39mmatch):\n\u001b[1;32m 333\u001b[0m \u001b[39m\"\"\"Return the Python representation of ``s`` (a ``str`` instance\u001b[39;00m\n\u001b[1;32m 334\u001b[0m \u001b[39m containing a JSON document).\u001b[39;00m\n\u001b[1;32m 335\u001b[0m \n\u001b[1;32m 336\u001b[0m \u001b[39m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 337\u001b[0m obj, end \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mraw_decode(s, idx\u001b[39m=\u001b[39;49m_w(s, \u001b[39m0\u001b[39;49m)\u001b[39m.\u001b[39;49mend())\n\u001b[1;32m 338\u001b[0m end \u001b[39m=\u001b[39m _w(s, end)\u001b[39m.\u001b[39mend()\n\u001b[1;32m 339\u001b[0m \u001b[39mif\u001b[39;00m end \u001b[39m!=\u001b[39m \u001b[39mlen\u001b[39m(s):\n", + "File \u001b[0;32m~/miniconda3/lib/python3.9/json/decoder.py:355\u001b[0m, in \u001b[0;36mJSONDecoder.raw_decode\u001b[0;34m(self, s, idx)\u001b[0m\n\u001b[1;32m 353\u001b[0m obj, end \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mscan_once(s, idx)\n\u001b[1;32m 354\u001b[0m \u001b[39mexcept\u001b[39;00m \u001b[39mStopIteration\u001b[39;00m \u001b[39mas\u001b[39;00m err:\n\u001b[0;32m--> 355\u001b[0m \u001b[39mraise\u001b[39;00m JSONDecodeError(\u001b[39m\"\u001b[39m\u001b[39mExpecting value\u001b[39m\u001b[39m\"\u001b[39m, s, err\u001b[39m.\u001b[39mvalue) \u001b[39mfrom\u001b[39;00m \u001b[39mNone\u001b[39m\n\u001b[1;32m 356\u001b[0m \u001b[39mreturn\u001b[39;00m obj, end\n", + "\u001b[0;31mJSONDecodeError\u001b[0m: Expecting value: line 1 column 1 (char 0)" + ] + } + ], + "source": [ + "def send_request(ticker: str) -> pd.DataFrame:\n", + " api_url = f'https://www.openfigi.com/search/query?facetQuery=MARKET_SECTOR_DES:%22Curncy%22&num_rows=100&simpleSearchString={ticker}&start=0'\n", + "\n", + " response = httpx.get(api_url)\n", + " json_response = response.json()\n", + " \n", + " return pd.DataFrame.from_dict(json_response['result'], orient='columns')\n", + "\n", + "send_request('BTCUSDT')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.9.13 ('base')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "6fd7ff10be7e3a66c1b3745c4cbc00041a2589eb74ab4be46a3698a7b56001aa" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}