{ "cells": [ { "cell_type": "code", "execution_count": 10, "id": "c31261ea", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAm4AAAGDCAYAAACSmpzSAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAi/klEQVR4nO3de5RmVX3m8e9jQ0BALgbUBhtaTdsRDTaxvazBa8zFS8JllInGNGgwyIpEmOCMLSiiSAZRQScXCQIjaqPLCXiJYIRhvBEjpsGGBhuDIijSA4IICEbp7t/88Z5KXsuqruruOlW1q76ftWq95+yz3/3u02d119N7n/2eVBWSJEma/R420x2QJEnS5BjcJEmSGmFwkyRJaoTBTZIkqREGN0mSpEYY3CRJkhphcJM0ZyR5fpLbZrofUy3JO5PcleT/Jdk3yU+SLOiOfTHJa2e6j5Kmh8FN0qyS5PNJ3jFG+SFdcNluJvq1JboAuakLWPcn+VaS12xlW4uAE4D9q+oxVfW9qtqlqjZOba8ltcDgJmm2+RCwIklGla8AVlXVhunv0la5vap2AXYF3gR8MMn+oytNIojuB9xdVXf20EdJjTG4SZptPgU8EnjOSEGSPYDfBz6cZIck70tye/fzviQ7jNVQkkrya0P7H0ryzm77+UluS/Lfk9yZZH2SQ5O8JMm/JvlRkhOH3vuwJCuTfCfJ3Uk+keSRE51MDXwKuAfYP8mrk/xTkrOS/Ag4JcluST6c5IdJbk3ylu7zfhu4HNi7G737UJLF3XmNGfiS/EmSdUnu6UYv95vwT1xSMwxukmaVqvop8AngiKHi/wLcWFXXAicBzwKWAU8FngG8ZSs/7jHAjsA+wMnAB4E/Bp7GIDienOTxXd03AIcCzwP2ZhDE/maiD+gC2GHA7sDarviZwM3Ao4DTgL8CdgMe37V/BPCaqvo/wIvpRu+q6tUTfNahwInAfwb2Ar4CfGyiPkpqh8FN0mx0AXB4kod3+0d0ZQCvAt5RVXdW1Q+BtzOYRt0aDwGnVdVDwMeBPYH3V9X9VXUDcANwQFf3dcBJVXVbVf0MOAV4+WamOvdO8mPgLuBtwIqq+lZ37Paq+qtu2vfnwB8Cb+4+9xbgvVt5Tq8D/kdVreva/ktgmaNu0twx62/ylTT/VNWVSX4IHJLk68DTGYwiwWC069ah6rd2ZVvj7qGb/H/avd4xdPynwC7d9n7AJ5NsGjq+EXg08IMx2r69qh47zud+f2h7T+BX+OVz2mfi7v+S/YD3J3nvUFm6tm4d+y2SWuKIm6TZ6sMMRtpWAJdV1Uigup1BQBmxb1c2lgeBnYb2H7MN/fk+8OKq2n3oZ8eqGiu0TaSGtu9iMPI3+py2pt3vA68b1ceHV9VXt6ItSbOQwU3SbPVh4LeBP+U/pklhcM/WW5LslWRPBvemfXScNtYAf5RkQZIXMbh/bGudDZw2Mu3Yff4h29AeAN2I3ye6th/Rtf8XjH9OE/XxzUme3PVxtySHb2sfJc0eBjdJs1J3r9dXgZ2BzwwdeiewGriOwc3+13RlYzkO+APgxwzujfvUNnTp/V0/LktyP/A1BosMpsKfAw8wWLBwJXAhcP6WNlJVnwTeBXw8yX3A9QwWN0iaI1JVE9eSJEnSjHPETZIkqREGN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkR8+LJCXvuuWctXrx4prshSZI0oauvvvquqtprrGPzIrgtXryY1atXz3Q3JEmSJpRk3EfUOVUqSZLUCIObJElSIwxukiRJjTC4SZIkNcLgJkmS1AiDmyRJUiMMbpIkSY0wuEmSJDXC4CZJktQIg5skSVIjDG6SJEmNMLhJkiQ1Yl48ZH7tD+5l8cpLZrob0pS55fSXznQXJEkzwBE3SZKkRhjcJEmSGmFwkyRJaoTBTZIkqREGN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkRBjdJkqRGGNwkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGmFwkyRJakRvwS3JoiRfSLIuyQ1JjuvKT01yXZI1SS5LsvfQew5I8s9d/bVJdhyj3UcmuTzJTd3rHn2dgyRJ0mzS54jbBuCEqnoS8Czg9Un2B95dVQdU1TLgs8DJAEm2Az4KHFNVTwaeDzw0RrsrgSuqaglwRbcvSZI05/UW3KpqfVVd023fD6wD9qmq+4aq7QxUt/27wHVVdW33nrurauMYTR8CXNBtXwAc2kP3JUmSZp3tpuNDkiwGDgSu6vZPA44A7gVe0FV7IlBJPg/sBXy8qs4Yo7lHV9V6GITDJI8a5zOPBo4GWLDrXlN3MpIkSTOk98UJSXYBLgKOHxltq6qTqmoRsAo4tqu6HfBs4FXd62FJXri1n1tV51TV8qpavmCn3bbpHCRJkmaDXkfckmzPILStqqqLx6hyIXAJ8DbgNuBLVXVX995Lgd9kcB/bsDuSLOxG2xYCd/Z2AtIstXjlJTPdhS1yy+kvnekuSNKc0Oeq0gDnAeuq6syh8iVD1Q4Gbuy2Pw8ckGSnbqHC84BvjtH0Z4Aju+0jgU9Pdd8lSZJmoz5H3A4CVgBrk6zpyk4EjkqyFNgE3AocA1BV9yQ5E/gXBgsWLq2qSwCSnAucXVWrgdOBTyQ5CvgecHiP5yBJkjRr9BbcqupKIGMcunQz7/kog68EGV3+2qHtu4GtvvdNkiSpVT45QZIkqREGN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkRBjdJkqRGGNwkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGmFwkyRJaoTBTZIkqREGN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkRBjdJkqRGGNwkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGmFwkyRJaoTBTZIkqREGN0mSpEYY3CRJkhphcJMkSWpEb8EtyaIkX0iyLskNSY7ryk9Ncl2SNUkuS7J3V744yU+78jVJzh6n3VOS/GCo3kv6OgdJkqTZZLse294AnFBV1yR5BHB1ksuBd1fVWwGSvAE4GTime893qmrZJNo+q6re00enJUmSZqveRtyqan1VXdNt3w+sA/apqvuGqu0MVF99kCRJmkum5R63JIuBA4Gruv3TknwfeBWDEbcRj0vyjSRfSvKczTR5bDfden6SPXrruCRJ0izSe3BLsgtwEXD8yGhbVZ1UVYuAVcCxXdX1wL5VdSDwF8CFSXYdo8kPAE8AlnXvee84n3t0ktVJVm988N6pPCVJkqQZ0WtwS7I9g9C2qqouHqPKhcDLAKrqZ1V1d7d9NfAd4Imj31BVd1TVxqraBHwQeMZYn11V51TV8qpavmCn3abmhCRJkmZQn6tKA5wHrKuqM4fKlwxVOxi4sSvfK8mCbvvxwBLg5jHaXTi0exhw/dT3XpIkafbpc1XpQcAKYG2SNV3ZicBRSZYCm4Bb+Y8Vpc8F3pFkA7AROKaqfgSQ5Fzg7KpaDZyRZBmDRQ23AK/r8RwkTYHFKy+Z6S705pbTXzrTXZA0j/QW3KrqSiBjHLp0nPoXMZhWHevYa4e2V0xJByVJkhrjkxMkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGmFwkyRJaoTBTZIkqRF9fgGvJAF+Sa0kTRVH3CRJkhphcJMkSWqEwU2SJKkRBjdJkqRGGNwkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGmFwkyRJaoTBTZIkqREGN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkRBjdJkqRGGNwkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGtFbcEuyKMkXkqxLckOS47ryU5Ncl2RNksuS7N2VL07y0658TZKzx2n3kUkuT3JT97pHX+cgSZI0m/Q54rYBOKGqngQ8C3h9kv2Bd1fVAVW1DPgscPLQe75TVcu6n2PGaXclcEVVLQGu6PYlSZLmvN6CW1Wtr6pruu37gXXAPlV131C1nYHawqYPAS7oti8ADt3GrkqSJDVhWu5xS7IYOBC4qts/Lcn3gVfxiyNuj0vyjSRfSvKccZp7dFWth0E4BB7VX88lSZJmj96DW5JdgIuA40dG26rqpKpaBKwCju2qrgf2raoDgb8ALkyy6zZ87tFJVidZvfHBe7ftJCRJkmaBVG3pTOUWNJ5sz+A+ts9X1ZljHN8PuKSqnjLGsS8Cb6yq1aPKvwU8v6rWJ1kIfLGqlm6uHzssXFILj3zf1p+IpN7dcvpLZ7oLkjQrJLm6qpaPdazPVaUBzgPWDYe2JEuGqh0M3NiV75VkQbf9eGAJcPMYTX8GOLLbPhL49NT3XpIkafbZrse2DwJWAGuTrOnKTgSOSrIU2ATcCoysHn0u8I4kG4CNwDFV9SOAJOcCZ3ejb6cDn0hyFPA94PAez0GSJGnW6HWqdLZwqlTS5jhNK2k2mZGpUkmSJE0tg5skSVIj+rzHTZKasHjlJVPeptOvkvrgiJskSVIjDG6SJEmNcKpU0pRwalCS+ueImyRJUiMMbpIkSY0wuEmSJDXC4CZJktQIg5skSVIjXFUqaUr08SW2s5GrZyXNJEfcJEmSGmFwkyRJaoRTpZK0BebLlPB0cwpamhxH3CRJkhphcJMkSWqEU6WSpBnnFPT0c3q6TY64SZIkNcLgJkmS1AinSiVJmodamZ52SvcXOeImSZLUCIObJElSIwxukiRJjTC4SZIkNcLgJkmS1AhXlUqSNMu4klLjccRNkiSpEQY3SZKkRvQ2VZpkEfBh4DHAJuCcqnp/klOBQ7qyO4FXV9XtQ+/bF/gmcEpVvWeMdk8B/hT4YVd0YlVd2td5SJI03Vr5ctwRTu1Onz5H3DYAJ1TVk4BnAa9Psj/w7qo6oKqWAZ8FTh71vrOAz03Q9llVtaz7MbRJkqR5obcRt6paD6zvtu9Psg7Yp6q+OVRtZ6BGdpIcCtwMPNBXvyRJklo1LatKkywGDgSu6vZPA44A7gVe0JXtDLwJ+B3gjRM0eWySI4DVDEb17hnjM48GjgZYsOteU3IekiTpl7U2tbs1Zst0cO+LE5LsAlwEHF9V9wFU1UlVtQhYBRzbVX07gynQn0zQ5AeAJwDLGIzovXesSlV1TlUtr6rlC3babdtPRJIkaYb1OuKWZHsGoW1VVV08RpULgUuAtwHPBF6e5Axgd2BTkn+rqr8efkNV3THU/gcZ3CcnSZI05/W5qjTAecC6qjpzqHxJVd3U7R4M3AhQVc8ZqnMK8JPRoa07trC7fw7gMOD6fs5AkiTNZbNl+nNL9DnidhCwAlibZE1XdiJwVJKlDL4O5FbgmIkaSnIucHZVrQbOSLKMwaKGW4DXTXnPJUmSZqE+V5VeCWSMQxN+fUdVnTJq/7VD2yu2uXOSJEkN8lmlkiSpWS1Od24LH3klSZLUiEkFtyRPTHJFkuu7/QOSvKXfrkmSJGnYZKdKPwj8N+DvAKrquiQXAu/sq2OSJEnjmW9TpCMmO1W6U1V9fVTZhqnujCRJksY32eB2V5In0D1XNMnL6Z5DKkmSpOkx2anS1wPnAL+e5AfAd4E/7q1XkiRp3pqv06CTMangVlU3A7/dPQj+YVV1f7/dkiRJ0miTXVX6l0l2r6oHqur+JHskcWGCJEnSNJrsVOmLq+rEkZ2quifJSwC/EkSSpFnCKca5b7KLExYk2WFkJ8nDgR02U1+SJElTbLIjbh8FrkjyvxisLP0T4ILeeiVJkqRfMtnFCWckWQu8kMGD40+tqs/32jNJ0qzllJw0Myb9kPmq+hzwuR77IkmSpM3YbHBLcmVVPTvJ/XRfvjtyCKiq2rXX3kmSJOnfbTa4VdWzu9dHTE93JElbw6lLaX6YcFVpkocluX46OiNJkqTxTRjcqmoTcG2SfaehP5IkSRrHZBcnLARuSPJ14IGRwqo6uJdeSZK2yOKVl0y6rtOqUrsmG9ze3msvJEmSNKGJVpXuCBwD/BqwFjivqjZMR8ckSZL0iyYacbsAeAj4CvBiYH/guL47JUnqz5ZMq0rTyWn8iU0U3Pavqt8ASHIe8PX+uyRJkqSxTLSq9KGRDadIJUmSZtZEI25PTXJftx3g4d2+T06QJEmT5jTo1JjoyQkLpqsjkiRJ2rwJv4BXkiRJs8Nkv8dNkiRpq/W9mnm+TMX2NuKWZFGSLyRZl+SGJMd15acmuS7JmiSXJdl71Pv2TfKTJG8cp91HJrk8yU3d6x59nYMkSdJs0udU6QbghKp6EvAs4PVJ9gfeXVUHVNUy4LPAyaPedxbwuc20uxK4oqqWAFd0+5IkSXNeb8GtqtZX1TXd9v3AOmCfqrpvqNrOQI3sJDkUuBm4YTNNH8Lgi4HpXg+dul5LkqTWzJdpUpime9ySLAYOBK7q9k8DjgDuBV7Qle0MvAn4HWDMadLOo6tqPQzCYZJH9ddzSZKk2aP3VaVJdgEuAo4fGW2rqpOqahGwCji2q/p24Kyq+skUfe7RSVYnWb3xwXunoklJkqQZ1euIW5LtGYS2VVV18RhVLgQuAd4GPBN4eZIzgN2BTUn+rar+etR77kiysBttWwjcOdZnV9U5wDkAOyxcUmPVkSRJbZpP06PDegtuSQKcB6yrqjOHypdU1U3d7sHAjQBV9ZyhOqcAPxkjtAF8BjgSOL17/XQvJyBJkjTL9DnidhCwAlibZE1XdiJwVJKlwCbgVuCYiRpKci5wdlWtZhDYPpHkKOB7wOE99F2SJGnWSdXcn0XcYeGSWnjk+2a6G5Ikach8ne6cSJKrq2r5WMd85JUkSVIjDG6SJEmN8FmlkqQZ55SZNDmOuEmSJDXC4CZJktQIp0olSVvF6U1p+jniJkmS1AiDmyRJUiOcKpUkbZXFKy+Z0c93qlbzkSNukiRJjTC4SZIkNcKpUklSk7ZkqtZpVc0VjrhJkiQ1wuAmSZLUCKdKJUmzhlOa0uY54iZJktQIg5skSVIjnCqVpDnO6Udp7nDETZIkqREGN0mSpEY4VSpJjXHqU5q/HHGTJElqhMFNkiSpEU6VSlJjtuQZnTPBqVypP464SZIkNcLgJkmS1AinSiVJU2pLpnKdVpW2jCNukiRJjTC4SZIkNaK3qdIki4APA48BNgHnVNX7k5wKHNKV3Qm8uqpuT/IM4JyRtwOnVNUnx2j3FOBPgR92RSdW1aV9nYckqT/TuULWaVnNBX3e47YBOKGqrknyCODqJJcD766qtwIkeQNwMnAMcD2wvKo2JFkIXJvkH6pqwxhtn1VV7+mx75IkSbNOb8GtqtYD67vt+5OsA/apqm8OVdsZqK7Og0PlO46US5IkaWBaVpUmWQwcCFzV7Z8GHAHcC7xgqN4zgfOB/YAV44y2ARyb5AhgNYNRvXvG+MyjgaMBFuy615SdiySpTZublnUaVa3ofXFCkl2Ai4Djq+o+gKo6qaoWAauAY0fqVtVVVfVk4OnAm5PsOEaTHwCeACxjMKL33rE+t6rOqarlVbV8wU67TeUpSZIkzYheg1uS7RmEtlVVdfEYVS4EXja6sKrWAQ8ATxnj2B1VtbGqNgEfBJ4xtb2WJEmanXoLbkkCnAesq6ozh8qXDFU7GLixK39cku267f2ApcAtY7S7cGj3MAaLGiRJkua8Pu9xOwhYAaxNsqYrOxE4KslSBl8HciuDFaUAzwZWJnmoO/ZnVXUXQJJzgbOrajVwRpJlDBYv3AK8rsdzkCRJmjX6XFV6JYPvYxttzO9cq6qPAB8Z59hrh7ZXTEkHJUmSGuOzSiWpUa6ElOYfH3klSZLUCIObJElSI5wqlaRJcFpS0mzgiJskSVIjDG6SJEmNMLhJkiQ1wuAmSZLUCIObJElSI1xVKmlKufpSkvrjiJskSVIjDG6SJEmNcKpU0pRavPKSXtp1ClaSHHGTJElqhsFNkiSpEU6VSo1zClGS5g9H3CRJkhphcJMkSWqEU6VS4/paxQlOw0rSbOOImyRJUiMMbpIkSY0wuEmSJDXC4CZJktQIg5skSVIjXFUqzVGuCJWkuccRN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkRvQW3JIuSfCHJuiQ3JDmuKz81yXVJ1iS5LMneXfkzurI1Sa5Nctg47T4yyeVJbupe9+jrHCRJkmaTVFU/DScLgYVVdU2SRwBXA4cCt1XVfV2dNwD7V9UxSXYCfl5VG7r3XgvsXVUbRrV7BvCjqjo9yUpgj6p60+b6ssPCJbXwyPdN9SlK28RVn5KksSS5uqqWj3WstxG3qlpfVdd02/cD64B9RkJbZ2egujoPDoW0HUfKx3AIcEG3fQGDMChJkjTnTcv3uCVZDBwIXNXtnwYcAdwLvGCo3jOB84H9gBWjR9s6j66q9TAIh0keNc5nHg0cDbBg172m7FwkSZJmSm9Tpf/+AckuwJeA06rq4lHH3gzsWFVvG1X+JAajac+tqn8bdezHVbX70P49VbXZ+9ycKtUIpyclSbPdjEyVdh+8PXARsGp0aOtcCLxsdGFVrQMeAJ4yxnvu6O6BG7mP7s6p67EkSdLs1eeq0gDnAeuq6syh8iVD1Q4GbuzKH5dku257P2ApcMsYTX8GOLLbPhL49JR3XpIkaRbq8x63g4AVwNoka7qyE4GjkiwFNgG3Asd0x54NrEzyUHfsz6rqLoAk5wJnV9Vq4HTgE0mOAr4HHN7jOWiOWbzykilry2lXSdJ06y24VdWVQMY4dOk49T8CfGScY68d2r4beOFU9FGSJKklPjlBkiSpEQY3SZKkRhjcJEmSGmFwkyRJasS0PDlBmq1cGSpJaokjbpIkSY0wuEmSJDXCqVLNOk5fSpI0NkfcJEmSGmFwkyRJaoTBTZIkqREGN0mSpEYY3CRJkhphcJMkSWqEwU2SJKkRBjdJkqRG+AW86p1fqCtJ0tRwxE2SJKkRBjdJkqRGOFU6hzglKUnS3OaImyRJUiMMbpIkSY0wuEmSJDXC4CZJktQIg5skSVIjXFU6zVz5KUmStpYjbpIkSY0wuEmSJDWit+CWZFGSLyRZl+SGJMd15acmuS7JmiSXJdm7K/+dJFcnWdu9/tY47Z6S5Afd+9ckeUlf5yBJkjSb9HmP2wbghKq6JskjgKuTXA68u6reCpDkDcDJwDHAXcAfVNXtSZ4CfB7YZ5y2z6qq9/TYd0mSpFmnt+BWVeuB9d32/UnWAftU1TeHqu0MVFfnG0PlNwA7Jtmhqn7WVx8lSZJaMi33uCVZDBwIXNXtn5bk+8CrGIy4jfYy4BubCW3HdtOt5yfZo48+S5IkzTa9B7ckuwAXAcdX1X0AVXVSVS0CVgHHjqr/ZOBdwOvGafIDwBOAZQxG9N47zucenWR1ktUbH7x3Kk5FkiRpRvUa3JJszyC0raqqi8eociGD0bWR+o8FPgkcUVXfGavNqrqjqjZW1Sbgg8Azxql3TlUtr6rlC3babVtPRZIkacb1do9bkgDnAeuq6syh8iVVdVO3ezBwY1e+O3AJ8Oaq+qfNtLuwu38O4DDg+h66v1l+ia4kSZoJfa4qPQhYAaxNsqYrOxE4KslSYBNwK4MVpTCYMv014K1J3tqV/W5V3ZnkXODsqloNnJFkGYNFDbcw/pSqJEnSnNLnqtIrgYxx6NJx6r8TeOc4x147tL1iSjooSZLUGJ+cIEmS1AiDmyRJUiMMbpIkSY0wuEmSJDXC4CZJktQIg5skSVIjDG6SJEmNMLhJkiQ1wuAmSZLUiD4feTVr/MY+u7Ha54tKkqTGOeImSZLUCIObJElSIwxukiRJjTC4SZIkNcLgJkmS1AiDmyRJUiMMbpIkSY0wuEmSJDXC4CZJktQIg5skSVIjDG6SJEmNMLhJkiQ1wuAmSZLUCIObJElSI1JVM92H3iW5H/jWTPdjntsTuGumOzHPeQ1mntdg5nkNZp7XYGL7VdVeYx3Ybrp7MkO+VVXLZ7oT81mS1V6DmeU1mHleg5nnNZh5XoNt41SpJElSIwxukiRJjZgvwe2cme6AvAazgNdg5nkNZp7XYOZ5DbbBvFicIEmSNBfMlxE3SZKk5s2p4JbkRUm+leTbSVaOcTxJ/md3/LokvzkT/ZzLJnENXtX92V+X5KtJnjoT/ZzLJroGQ/WenmRjkpdPZ//mg8lcgyTPT7ImyQ1JvjTdfZzrJvFv0W5J/iHJtd01eM1M9HOuSnJ+kjuTXD/OcX8fb6U5E9ySLAD+BngxsD/wyiT7j6r2YmBJ93M08IFp7eQcN8lr8F3geVV1AHAq3uswpSZ5DUbqvQv4/PT2cO6bzDVIsjvwt8DBVfVk4PDp7udcNsm/B68HvllVTwWeD7w3ya9Ma0fntg8BL9rMcX8fb6U5E9yAZwDfrqqbq+rnwMeBQ0bVOQT4cA18Ddg9ycLp7ugcNuE1qKqvVtU93e7XgMdOcx/nusn8PQD4c+Ai4M7p7Nw8MZlr8EfAxVX1PYCq8jpMrclcgwIekSTALsCPgA3T2825q6q+zODPdDz+Pt5Kcym47QN8f2j/tq5sS+to623pn+9RwOd67dH8M+E1SLIPcBhw9jT2az6ZzN+DJwJ7JPlikquTHDFtvZsfJnMN/hp4EnA7sBY4rqo2TU/3hL+Pt9pcenJCxigbvWR2MnW09Sb955vkBQyC27N77dH8M5lr8D7gTVW1cTDYoCk2mWuwHfA04IXAw4F/TvK1qvrXvjs3T0zmGvwesAb4LeAJwOVJvlJV9/XcNw34+3grzaXgdhuwaGj/sQz+J7WldbT1JvXnm+QA4FzgxVV19zT1bb6YzDVYDny8C217Ai9JsqGqPjUtPZz7Jvtv0V1V9QDwQJIvA08FDG5TYzLX4DXA6TX4TqxvJ/ku8OvA16eni/Oev4+30lyaKv0XYEmSx3U3mL4C+MyoOp8BjuhWszwLuLeq1k93R+ewCa9Bkn2Bi4EVji70YsJrUFWPq6rFVbUY+HvgzwxtU2oy/xZ9GnhOku2S7AQ8E1g3zf2cyyZzDb7HYMSTJI8GlgI3T2sv5zd/H2+lOTPiVlUbkhzLYJXcAuD8qrohyTHd8bOBS4GXAN8GHmTwPy5NkUleg5OBXwX+thvx2eDDhqfOJK+BejSZa1BV65L8I3AdsAk4t6rG/NoEbblJ/j04FfhQkrUMpu3eVFV3zVin55gkH2OwWnfPJLcBbwO2B38fbyufnCBJktSIuTRVKkmSNKcZ3CRJkhphcJMkSWqEwU2SJKkRBjdJkqQpkOT8JHcmmXCVeJKzkqzpfv41yY8n8xkGN0nzSveYqd8bVXZ8kr8dp/4tSfacnt5JatyHgBdNpmJV/deqWlZVy4C/YvAdpxMyuEmabz7G4AtZh72iK5ekrVZVXwZ+NFyW5AlJ/rF7LvFXkvz6GG99JZP8N8jgJmm++Xvg95PsAJBkMbA38Ngka5Ncn+Rdo9+UZPHw9EeSNyY5pdv+Yjft8eUk65I8PcnFSW5K8s6h9/xxkq93UyN/l2RBz+cqaeadA/x5VT0NeCPwC6P7SfYDHgf838k0ZnCTNK90z8f9Ov8xnfEKBt+w/y4GDxxfBjw9yaFb2PTPq+q5wNkMHmn1euApwKuT/GqSJwF/CBzUTY1sBF61TScjaVZLsgvwn4D/nWQN8HfAwlHVXgH8fVVtnEybc+aRV5K0BUamSz/dvX4S+GJV/RAgySrgucCntqDNkWdhrgVuGHnuYpKbGTxM+9nA04B/6R739nDgzm09EUmz2sOAH3f/WRvPKxj8R2/SDUrSfPMp4IVJfpNBgLp2Eu/ZwC/+m7njqOM/6143DW2P7G/H4HmYF4zcjFxVS6vqlK3ou6RGVNV9wHeTHA6QgaeOHE+yFNgD+OfJtmlwkzTvVNVPgC8C5zMYfbsKeF6SPbv7zl4JfGnU2+4AHtVNe+4A/P4WfuwVwMuTPAogySO7e1skzRFJPsYghC1NcluSoxjcEnFUkmuBG4BDht7ySuDjtQUPjneqVNJ89TEGy+9fUVXrk7wZ+AKDkbFLq+rTw5Wr6qEk72AQ8r4L3LglH1ZV30zyFuCyJA8DHmIwPXLrtp+KpNmgql45zqExvyJka0bdswUhT5IkSTPIqVJJkqRGGNwkSZIaYXCTJElqhMFNkiSpEQY3SZKkRhjcJEmSGmFwkyRJaoTBTZIkqRH/HwDLOE/Ye6aPAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import yfinance as yf\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "def fetch_stock_data(ticker, start, interval='5m'):\n", " \"\"\"\n", " Fetch stock data from Yahoo Finance.\n", " :param ticker: Stock ticker symbol\n", " :param start: Start date for data (YYYY-MM-DD)\n", " :param interval: Data interval (e.g., '1d', '5m')\n", " :return: DataFrame with stock data\n", " \"\"\"\n", " stock_data = yf.download(ticker, start=start, interval=interval)\n", " return stock_data\n", "\n", "def calculate_volume_profile(data, bins=100):\n", " \"\"\"\n", " Calculate the volume profile.\n", " :param data: DataFrame with stock data\n", " :param bins: Number of bins for price levels\n", " :return: volume profile DataFrame\n", " \"\"\"\n", " price_min = data['Low'].min()\n", " price_max = data['High'].max()\n", " bin_edges = np.linspace(price_min, price_max, bins)\n", " \n", " volume_profile = pd.DataFrame(index=bin_edges[:-1], columns=['Volume'])\n", " volume_profile['Volume'] = 0\n", "\n", " for index, row in data.iterrows():\n", " # Determine which bins the high and low price fall into\n", " bin_indices = np.digitize([row['Low'], row['High']], bin_edges) - 1\n", " \n", " # Ensure bin indices are within the valid range\n", " bin_indices = [max(0, min(bins-2, b)) for b in bin_indices]\n", " \n", " # Increment volume in corresponding bins\n", " for i in range(bin_indices[0], bin_indices[1] + 1):\n", " volume_profile.iloc[i] += row['Volume']\n", " \n", " return volume_profile\n", "\n", "def plot_volume_profile(volume_profile):\n", " \"\"\"\n", " Plot the volume profile.\n", " :param volume_profile: DataFrame with volume profile\n", " \"\"\"\n", " plt.figure(figsize=(10, 6))\n", " plt.barh(volume_profile.index, volume_profile['Volume'], height=volume_profile.index[1] - volume_profile.index[0])\n", " plt.xlabel('Volume')\n", " plt.ylabel('Price')\n", " plt.title('Volume Profile')\n", " plt.show()\n", "\n", "# Example usage\n", "ticker = 'AAPL'\n", "start_date = '2024-07-16'\n", "\n", "data = fetch_stock_data(ticker, start=start_date, interval='5m')\n", "volume_profile = calculate_volume_profile(data, bins=100)\n", "plot_volume_profile(volume_profile)\n" ] }, { "cell_type": "code", "execution_count": 12, "id": "33fb34e1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import yfinance as yf\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "def fetch_stock_data(ticker, start, interval='5m'):\n", " \"\"\"\n", " Fetch stock data from Yahoo Finance.\n", " :param ticker: Stock ticker symbol\n", " :param start: Start date for data (YYYY-MM-DD)\n", " :param interval: Data interval (e.g., '1d', '5m')\n", " :return: DataFrame with stock data\n", " \"\"\"\n", " stock_data = yf.download(ticker, start=start, interval=interval)\n", " return stock_data\n", "\n", "def calculate_volume_profile(data, bins=100):\n", " \"\"\"\n", " Calculate the volume profile.\n", " :param data: DataFrame with stock data\n", " :param bins: Number of bins for price levels\n", " :return: volume profile DataFrame with buy and sell volumes\n", " \"\"\"\n", " price_min = data['Low'].min()\n", " price_max = data['High'].max()\n", " bin_edges = np.linspace(price_min, price_max, bins)\n", " \n", " volume_profile = pd.DataFrame(index=bin_edges[:-1], columns=['Buy Volume', 'Sell Volume'])\n", " volume_profile['Buy Volume'] = 0\n", " volume_profile['Sell Volume'] = 0\n", "\n", " for index, row in data.iterrows():\n", " # Determine which bins the high and low price fall into\n", " bin_indices = np.digitize([row['Low'], row['High']], bin_edges) - 1\n", " \n", " # Ensure bin indices are within the valid range\n", " bin_indices = [max(0, min(bins-2, b)) for b in bin_indices]\n", " \n", " # Separate buy and sell volumes\n", " if row['Close'] > row['Open']:\n", " volume_profile.iloc[bin_indices[0]:bin_indices[1] + 1, volume_profile.columns.get_loc('Buy Volume')] += row['Volume']\n", " else:\n", " volume_profile.iloc[bin_indices[0]:bin_indices[1] + 1, volume_profile.columns.get_loc('Sell Volume')] += row['Volume']\n", " \n", " return volume_profile\n", "\n", "def plot_volume_profile(volume_profile):\n", " \"\"\"\n", " Plot the volume profile with buy and sell volumes.\n", " :param volume_profile: DataFrame with volume profile\n", " \"\"\"\n", " plt.figure(figsize=(10, 6))\n", " plt.barh(volume_profile.index, volume_profile['Buy Volume'], height=volume_profile.index[1] - volume_profile.index[0], color='blue', alpha=0.6, label='Buy Volume')\n", " plt.barh(volume_profile.index, volume_profile['Sell Volume'], height=volume_profile.index[1] - volume_profile.index[0], color='red', alpha=0.6, label='Sell Volume', left=volume_profile['Buy Volume'])\n", " plt.xlabel('Volume')\n", " plt.ylabel('Price')\n", " plt.title('Volume Profile with Buy and Sell Volumes')\n", " plt.legend()\n", " plt.show()\n", "\n", "# Example usage\n", "ticker = 'CAT'\n", "start_date = '2024-07-16'\n", "\n", "data = fetch_stock_data(ticker, start=start_date, interval='5m')\n", "volume_profile = calculate_volume_profile(data, bins=100)\n", "plot_volume_profile(volume_profile)\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "ed5e5818", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n", "Buy volume only prices:\n", "[223.27 - 223.31] with detailed volumes: {223.27499389648438: 80011, 223.31060004956794: 80011}\n", "\n", "Sell volume only prices:\n" ] } ], "source": [ "import yfinance as yf\n", "import numpy as np\n", "import pandas as pd\n", "\n", "def fetch_stock_data(ticker, start, interval='5m'):\n", " \"\"\"\n", " Fetch stock data from Yahoo Finance.\n", " :param ticker: Stock ticker symbol\n", " :param start: Start date for data (YYYY-MM-DD)\n", " :param interval: Data interval (e.g., '1d', '5m')\n", " :return: DataFrame with stock data\n", " \"\"\"\n", " stock_data = yf.download(ticker, start=start, interval=interval)\n", " return stock_data\n", "\n", "def calculate_volume_profile(data, bins=100):\n", " \"\"\"\n", " Calculate the volume profile.\n", " :param data: DataFrame with stock data\n", " :param bins: Number of bins for price levels\n", " :return: volume profile DataFrame with buy and sell volumes\n", " \"\"\"\n", " price_min = data['Low'].min()\n", " price_max = data['High'].max()\n", " bin_edges = np.linspace(price_min, price_max, bins)\n", " \n", " volume_profile = pd.DataFrame(index=bin_edges[:-1], columns=['Buy Volume', 'Sell Volume'])\n", " volume_profile['Buy Volume'] = 0\n", " volume_profile['Sell Volume'] = 0\n", "\n", " for index, row in data.iterrows():\n", " # Determine which bins the high and low price fall into\n", " bin_indices = np.digitize([row['Low'], row['High']], bin_edges) - 1\n", " \n", " # Ensure bin indices are within the valid range\n", " bin_indices = [max(0, min(bins-2, b)) for b in bin_indices]\n", " \n", " # Separate buy and sell volumes\n", " for i in range(bin_indices[0], bin_indices[1] + 1):\n", " if row['Close'] > row['Open']:\n", " volume_profile.iloc[i, volume_profile.columns.get_loc('Buy Volume')] += row['Volume']\n", " else:\n", " volume_profile.iloc[i, volume_profile.columns.get_loc('Sell Volume')] += row['Volume']\n", " \n", " return volume_profile\n", "\n", "def identify_volume_ranges(volume_profile):\n", " \"\"\"\n", " Identify and print ranges with only buy or sell volumes.\n", " :param volume_profile: DataFrame with volume profile\n", " \"\"\"\n", " buy_ranges = []\n", " sell_ranges = []\n", " buy_range = []\n", " sell_range = []\n", "\n", " for price, row in volume_profile.iterrows():\n", " if row['Buy Volume'] > 0 and row['Sell Volume'] == 0:\n", " if not buy_range:\n", " buy_range = [price]\n", " buy_range.append(price)\n", " else:\n", " if buy_range:\n", " buy_ranges.append(buy_range)\n", " buy_range = []\n", "\n", " if row['Sell Volume'] > 0 and row['Buy Volume'] == 0:\n", " if not sell_range:\n", " sell_range = [price]\n", " sell_range.append(price)\n", " else:\n", " if sell_range:\n", " sell_ranges.append(sell_range)\n", " sell_range = []\n", "\n", " if buy_range:\n", " buy_ranges.append(buy_range)\n", " if sell_range:\n", " sell_ranges.append(sell_range)\n", "\n", " print(\"Buy volume only prices:\")\n", " for r in buy_ranges:\n", " print(f\"[{r[0]:.2f} - {r[-1]:.2f}] with detailed volumes: {volume_profile.loc[r[0]:r[-1], 'Buy Volume'].to_dict()}\")\n", "\n", " print(\"\\nSell volume only prices:\")\n", " for r in sell_ranges:\n", " print(f\"[{r[0]:.2f} - {r[-1]:.2f}] with detailed volumes: {volume_profile.loc[r[0]:r[-1], 'Sell Volume'].to_dict()}\")\n", "\n", "# Example usage\n", "ticker = 'AAPL'\n", "start_date = '2024-07-19'\n", "\n", "data = fetch_stock_data(ticker, start=start_date, interval='1m')\n", "volume_profile = calculate_volume_profile(data, bins=100)\n", "identify_volume_ranges(volume_profile)\n" ] }, { "cell_type": "code", "execution_count": 36, "id": "b165d1ff", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n" ] } ], "source": [ "ticker = 'AAPL'\n", "start_date = '2024-07-18'\n", "interval='5m'\n", "data = yf.download(ticker, start=start_date, interval=interval)\n", "\n", "data.reset_index(inplace=True,drop=False)\n", "\n" ] }, { "cell_type": "code", "execution_count": 29, "id": "29139861", "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", "
DatetimeOpenHighLowCloseAdj CloseVolume
02024-07-19 09:30:00-04:00247.720993249.009995246.600006247.649002247.6490024777046
12024-07-19 09:35:00-04:00247.550095248.990005245.222000247.154999247.1549992478581
22024-07-19 09:40:00-04:00247.149994247.889999245.660004245.690002245.6900021665298
32024-07-19 09:45:00-04:00245.669998246.039993244.399994245.020004245.0200042526077
42024-07-19 09:50:00-04:00244.979996247.710007244.770004246.539993246.5399932289072
\n", "
" ], "text/plain": [ " Datetime Open High Low Close \\\n", "0 2024-07-19 09:30:00-04:00 247.720993 249.009995 246.600006 247.649002 \n", "1 2024-07-19 09:35:00-04:00 247.550095 248.990005 245.222000 247.154999 \n", "2 2024-07-19 09:40:00-04:00 247.149994 247.889999 245.660004 245.690002 \n", "3 2024-07-19 09:45:00-04:00 245.669998 246.039993 244.399994 245.020004 \n", "4 2024-07-19 09:50:00-04:00 244.979996 247.710007 244.770004 246.539993 \n", "\n", " Adj Close Volume \n", "0 247.649002 4777046 \n", "1 247.154999 2478581 \n", "2 245.690002 1665298 \n", "3 245.020004 2526077 \n", "4 246.539993 2289072 " ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data.head()" ] }, { "cell_type": "code", "execution_count": 30, "id": "c4938b50", "metadata": {}, "outputs": [], "source": [ "data['Open'] = round(data['Open'],2)\n", "data['High'] = round(data['High'],2)\n", "data['Low'] = round(data['Low'],2)\n", "data['Close'] = round(data['Close'],2)\n", "\n", "# Calculate net_volume\n", "data['Net Volume'] = 0\n", "data.loc[0, 'Net Volume'] = data.loc[0, 'Volume']\n", "\n", "for i in range(1, len(data)):\n", " if data.loc[i, 'Close'] > data.loc[i, 'Open']:\n", " data.loc[i, 'Net Volume'] = data.loc[i-1, 'Volume'] + data.loc[i, 'Volume']\n", " else:\n", " data.loc[i, 'Net Volume'] = data.loc[i-1, 'Volume'] - data.loc[i, 'Volume']\n" ] }, { "cell_type": "code", "execution_count": 37, "id": "69db3a35", "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", "
DatetimeOpenHighLowCloseAdj CloseVolume
772024-07-18 15:55:00-04:00223.845001224.580002223.830002224.190002224.1900021776479
782024-07-19 09:30:00-04:00224.852005225.929993224.419998224.940002224.9400026229122
792024-07-19 09:35:00-04:00224.940002226.419998224.930603226.419998226.4199981044908
802024-07-19 09:40:00-04:00226.419998226.490005224.809998225.039993225.0399931474936
\n", "
" ], "text/plain": [ " Datetime Open High Low Close \\\n", "77 2024-07-18 15:55:00-04:00 223.845001 224.580002 223.830002 224.190002 \n", "78 2024-07-19 09:30:00-04:00 224.852005 225.929993 224.419998 224.940002 \n", "79 2024-07-19 09:35:00-04:00 224.940002 226.419998 224.930603 226.419998 \n", "80 2024-07-19 09:40:00-04:00 226.419998 226.490005 224.809998 225.039993 \n", "\n", " Adj Close Volume \n", "77 224.190002 1776479 \n", "78 224.940002 6229122 \n", "79 226.419998 1044908 \n", "80 225.039993 1474936 " ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data[(data['Datetime'] >= '2024-07-18 15:55:00') & (data['Datetime'] <= '2024-07-19 09:40:00')]" ] }, { "cell_type": "code", "execution_count": 32, "id": "33bd76d2", "metadata": {}, "outputs": [ { "data": { "application/vnd.plotly.v1+json": { "config": { "plotlyServerURL": "https://plot.ly" }, "data": [ { "hovertemplate": "Datetime=%{x}
Net Volume=%{y}", "legendgroup": "", "line": { "color": "#636efa", "dash": "solid" }, "marker": { "symbol": "circle" }, "mode": "lines", "name": "", "orientation": "v", "showlegend": false, "type": "scatter", "x": [ "2024-07-19T09:30:00-04:00", "2024-07-19T09:35:00-04:00", "2024-07-19T09:40:00-04:00", "2024-07-19T09:45:00-04:00", "2024-07-19T09:50:00-04:00", "2024-07-19T09:55:00-04:00", "2024-07-19T10:00:00-04:00", "2024-07-19T10:05:00-04:00", "2024-07-19T10:10:00-04:00", "2024-07-19T10:15:00-04:00", "2024-07-19T10:20:00-04:00", "2024-07-19T10:25:00-04:00", "2024-07-19T10:30:00-04:00", "2024-07-19T10:35:00-04:00", "2024-07-19T10:40:00-04:00", "2024-07-19T10:45:00-04:00", "2024-07-19T10:50:00-04:00", "2024-07-19T10:55:00-04:00", "2024-07-19T11:00:00-04:00", "2024-07-19T11:05:00-04:00", "2024-07-19T11:10:00-04:00", "2024-07-19T11:15:00-04:00", "2024-07-19T11:20:00-04:00", "2024-07-19T11:25:00-04:00", "2024-07-19T11:30:00-04:00", "2024-07-19T11:35:00-04:00", "2024-07-19T11:40:00-04:00", "2024-07-19T11:45:00-04:00", "2024-07-19T11:50:00-04:00", "2024-07-19T11:55:00-04:00", "2024-07-19T12:00:00-04:00", "2024-07-19T12:05:00-04:00", "2024-07-19T12:10:00-04:00", "2024-07-19T12:15:00-04:00", "2024-07-19T12:20:00-04:00", "2024-07-19T12:25:00-04:00", "2024-07-19T12:30:00-04:00", "2024-07-19T12:35:00-04:00", "2024-07-19T12:40:00-04:00", "2024-07-19T12:45:00-04:00", "2024-07-19T12:50:00-04:00", "2024-07-19T12:55:00-04:00", "2024-07-19T13:00:00-04:00", "2024-07-19T13:05:00-04:00", "2024-07-19T13:10:00-04:00", "2024-07-19T13:15:00-04:00", "2024-07-19T13:20:00-04:00", "2024-07-19T13:25:00-04:00", "2024-07-19T13:30:00-04:00", "2024-07-19T13:35:00-04:00", "2024-07-19T13:40:00-04:00", "2024-07-19T13:45:00-04:00", "2024-07-19T13:50:00-04:00", "2024-07-19T13:55:00-04:00", "2024-07-19T14:00:00-04:00", "2024-07-19T14:05:00-04:00", "2024-07-19T14:10:00-04:00", "2024-07-19T14:15:00-04:00", "2024-07-19T14:20:00-04:00", "2024-07-19T14:25:00-04:00", "2024-07-19T14:30:00-04:00", "2024-07-19T14:35:00-04:00", "2024-07-19T14:40:00-04:00", "2024-07-19T14:45:00-04:00", "2024-07-19T14:50:00-04:00", "2024-07-19T14:55:00-04:00", "2024-07-19T15:00:00-04:00", "2024-07-19T15:05:00-04:00", "2024-07-19T15:10:00-04:00", "2024-07-19T15:15:00-04:00", "2024-07-19T15:20:00-04:00", "2024-07-19T15:25:00-04:00", "2024-07-19T15:30:00-04:00", "2024-07-19T15:35:00-04:00", "2024-07-19T15:40:00-04:00", "2024-07-19T15:45:00-04:00", "2024-07-19T15:50:00-04:00", "2024-07-19T15:55:00-04:00" ], "xaxis": "x", "y": [ 4777046, 2298465, 813283, -860779, 4815149, 933519, -1003606, 4177504, -638986, 4132166, 325083, -75120, -199707, 3727038, 1016208, 2408135, 2392279, -174852, 284963, -217093, 40359, 1841649, 1547859, -315983, -635408, 2891144, -318616, 152637, 2302522, 1709011, -245337, 1841659, 69304, -136704, 39067, 1842910, -67503, -223913, 2155742, 1915159, 63259, 1486703, -33207, 1264441, -19517, 108502, 1121542, 1280340, 1325163, -107326, -141347, 1737800, 113415, 1392862, 73515, 43185, 1178109, 175230, 44107, -156373, 1105278, -68493, 49481, 1267720, 1309222, 964043, 1029561, 1146673, 1089864, 1171210, -203307, 316156, -140915, 34427, -60123, -198035, 2018985, -788491 ], "yaxis": "y" } ], "layout": { "legend": { "tracegroupgap": 0 }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } }, "title": { "text": "Net Volume Over Time" }, "xaxis": { "anchor": "y", "domain": [ 0, 1 ], "title": { "text": "Datetime" } }, "yaxis": { "anchor": "x", "domain": [ 0, 1 ], "title": { "text": "Net Volume" } } } }, "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import plotly.express as px\n", "\n", "# Plot the line chart using Plotly\n", "fig = px.line(data, x='Datetime', y='Net Volume', title='Net Volume Over Time', labels={'Datetime': 'Datetime', 'Net Volume': 'Net Volume'})\n", "fig.show()" ] }, { "cell_type": "code", "execution_count": 9, "id": "8fd2a27d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "16366" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "96377 - 80011" ] }, { "cell_type": "code", "execution_count": 18, "id": "b168540d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n", "Buy volume only prices:\n", "[362.14 - 362.41] with detailed volumes: {362.1445821126302: 119282, 362.414789835612: 67795}\n", "\n", "Sell volume only prices:\n" ] } ], "source": [ "import yfinance as yf\n", "import numpy as np\n", "import pandas as pd\n", "\n", "def fetch_stock_data(ticker, start, interval='5m'):\n", " \"\"\"\n", " Fetch stock data from Yahoo Finance.\n", " :param ticker: Stock ticker symbol\n", " :param start: Start date for data (YYYY-MM-DD)\n", " :param interval: Data interval (e.g., '1d', '5m')\n", " :return: DataFrame with stock data\n", " \"\"\"\n", " stock_data = yf.download(ticker, start=start, interval=interval)\n", " return stock_data\n", "\n", "def calculate_volume_profile(data, row_size=24):\n", " \"\"\"\n", " Calculate the volume profile.\n", " :param data: DataFrame with stock data\n", " :param row_size: Number of rows for the price levels\n", " :return: volume profile DataFrame with buy and sell volumes\n", " \"\"\"\n", " price_min = data['Low'].min()\n", " price_max = data['High'].max()\n", " bin_edges = np.linspace(price_min, price_max, row_size + 1)\n", " \n", " volume_profile = pd.DataFrame(index=bin_edges[:-1], columns=['Buy Volume', 'Sell Volume'])\n", " volume_profile['Buy Volume'] = 0\n", " volume_profile['Sell Volume'] = 0\n", "\n", " for index, row in data.iterrows():\n", " # Determine which bins the high and low price fall into\n", " bin_indices = np.digitize([row['Low'], row['High']], bin_edges) - 1\n", " \n", " # Ensure bin indices are within the valid range\n", " bin_indices = [max(0, min(row_size-1, b)) for b in bin_indices]\n", " \n", " # Separate buy and sell volumes\n", " for i in range(bin_indices[0], bin_indices[1] + 1):\n", " if row['Close'] > row['Open']:\n", " volume_profile.iloc[i, volume_profile.columns.get_loc('Buy Volume')] += row['Volume']\n", " else:\n", " volume_profile.iloc[i, volume_profile.columns.get_loc('Sell Volume')] += row['Volume']\n", " \n", " return volume_profile\n", "\n", "def identify_volume_ranges(volume_profile):\n", " \"\"\"\n", " Identify and print ranges with only buy or sell volumes.\n", " :param volume_profile: DataFrame with volume profile\n", " \"\"\"\n", " buy_ranges = []\n", " sell_ranges = []\n", " current_buy_range = []\n", " current_sell_range = []\n", "\n", " for price, row in volume_profile.iterrows():\n", " if row['Buy Volume'] > 0 and row['Sell Volume'] == 0:\n", " current_buy_range.append(price)\n", " else:\n", " if current_buy_range:\n", " buy_ranges.append((current_buy_range[0], current_buy_range[-1], volume_profile.loc[current_buy_range[0]:current_buy_range[-1], 'Buy Volume'].to_dict()))\n", " current_buy_range = []\n", "\n", " if row['Sell Volume'] > 0 and row['Buy Volume'] == 0:\n", " current_sell_range.append(price)\n", " else:\n", " if current_sell_range:\n", " sell_ranges.append((current_sell_range[0], current_sell_range[-1], volume_profile.loc[current_sell_range[0]:current_sell_range[-1], 'Sell Volume'].to_dict()))\n", " current_sell_range = []\n", "\n", " if current_buy_range:\n", " buy_ranges.append((current_buy_range[0], current_buy_range[-1], volume_profile.loc[current_buy_range[0]:current_buy_range[-1], 'Buy Volume'].to_dict()))\n", " if current_sell_range:\n", " sell_ranges.append((current_sell_range[0], current_sell_range[-1], volume_profile.loc[current_sell_range[0]:current_sell_range[-1], 'Sell Volume'].to_dict()))\n", "\n", " print(\"Buy volume only prices:\")\n", " for start, end, volumes in buy_ranges:\n", " print(f\"[{start:.2f} - {end:.2f}] with detailed volumes: {volumes}\")\n", "\n", " print(\"\\nSell volume only prices:\")\n", " for start, end, volumes in sell_ranges:\n", " print(f\"[{start:.2f} - {end:.2f}] with detailed volumes: {volumes}\")\n", "\n", "# Example usage\n", "ticker = 'CAT'\n", "start_date = '2024-07-17'\n", "\n", "data = fetch_stock_data(ticker, start=start_date, interval='5m')\n", "volume_profile = calculate_volume_profile(data, row_size=24)\n", "identify_volume_ranges(volume_profile)\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "9c713130", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n", "Buy volume only prices:\n", "\n", "Sell volume only prices:\n", "[362.41 - 362.41] with detailed volumes: {362.414789835612: 20512}\n" ] } ], "source": [ "import yfinance as yf\n", "import numpy as np\n", "import pandas as pd\n", "\n", "def fetch_stock_data(ticker, start, interval='1m'):\n", " \"\"\"\n", " Fetch stock data from Yahoo Finance.\n", " :param ticker: Stock ticker symbol\n", " :param start: Start date for data (YYYY-MM-DD)\n", " :param interval: Data interval (e.g., '1m', '5m')\n", " :return: DataFrame with stock data\n", " \"\"\"\n", " stock_data = yf.download(ticker, start=start, interval=interval)\n", " return stock_data\n", "\n", "def calculate_volume_profile(data, row_size=24):\n", " \"\"\"\n", " Calculate the volume profile.\n", " :param data: DataFrame with stock data\n", " :param row_size: Number of rows for the price levels\n", " :return: volume profile DataFrame with buy and sell volumes\n", " \"\"\"\n", " price_min = data['Low'].min()\n", " price_max = data['High'].max()\n", " bin_edges = np.linspace(price_min, price_max, row_size + 1)\n", " \n", " volume_profile = pd.DataFrame(index=bin_edges[:-1], columns=['Buy Volume', 'Sell Volume'])\n", " volume_profile['Buy Volume'] = 0\n", " volume_profile['Sell Volume'] = 0\n", "\n", " for index, row in data.iterrows():\n", " # Determine which bins the high and low price fall into\n", " bin_indices = np.digitize([row['Low'], row['High']], bin_edges) - 1\n", " \n", " # Ensure bin indices are within the valid range\n", " bin_indices = [max(0, min(row_size-1, b)) for b in bin_indices]\n", " \n", " # Separate buy and sell volumes\n", " for i in range(bin_indices[0], bin_indices[1] + 1):\n", " if row['Close'] > row['Open']:\n", " volume_profile.iloc[i, volume_profile.columns.get_loc('Buy Volume')] += row['Volume']\n", " else:\n", " volume_profile.iloc[i, volume_profile.columns.get_loc('Sell Volume')] += row['Volume']\n", " \n", " return volume_profile\n", "\n", "def identify_volume_ranges(volume_profile):\n", " \"\"\"\n", " Identify and print ranges with only buy or sell volumes.\n", " :param volume_profile: DataFrame with volume profile\n", " \"\"\"\n", " buy_ranges = []\n", " sell_ranges = []\n", " current_buy_range = []\n", " current_sell_range = []\n", "\n", " for price, row in volume_profile.iterrows():\n", " if row['Buy Volume'] > 0 and row['Sell Volume'] == 0:\n", " current_buy_range.append(price)\n", " else:\n", " if current_buy_range:\n", " buy_ranges.append((current_buy_range[0], current_buy_range[-1], volume_profile.loc[current_buy_range[0]:current_buy_range[-1], 'Buy Volume'].to_dict()))\n", " current_buy_range = []\n", "\n", " if row['Sell Volume'] > 0 and row['Buy Volume'] == 0:\n", " current_sell_range.append(price)\n", " else:\n", " if current_sell_range:\n", " sell_ranges.append((current_sell_range[0], current_sell_range[-1], volume_profile.loc[current_sell_range[0]:current_sell_range[-1], 'Sell Volume'].to_dict()))\n", " current_sell_range = []\n", "\n", " if current_buy_range:\n", " buy_ranges.append((current_buy_range[0], current_buy_range[-1], volume_profile.loc[current_buy_range[0]:current_buy_range[-1], 'Buy Volume'].to_dict()))\n", " if current_sell_range:\n", " sell_ranges.append((current_sell_range[0], current_sell_range[-1], volume_profile.loc[current_sell_range[0]:current_sell_range[-1], 'Sell Volume'].to_dict()))\n", "\n", " print(\"Buy volume only prices:\")\n", " for start, end, volumes in buy_ranges:\n", " print(f\"[{start:.2f} - {end:.2f}] with detailed volumes: {volumes}\")\n", "\n", " print(\"\\nSell volume only prices:\")\n", " for start, end, volumes in sell_ranges:\n", " print(f\"[{start:.2f} - {end:.2f}] with detailed volumes: {volumes}\")\n", "\n", "# Example usage\n", "ticker = 'CAT'\n", "start_date = '2024-07-17'\n", "\n", "data = fetch_stock_data(ticker, start=start_date, interval='1m')\n", "volume_profile = calculate_volume_profile(data, row_size=24)\n", "identify_volume_ranges(volume_profile)\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "5aaf0165", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[*********************100%%**********************] 1 of 1 completed\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/gp/x0f5sgq13db073j79l3_2tb40000gn/T/ipykernel_7185/254227506.py:50: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " volume_profile.iloc[i]['Total Volume'] += volume\n", "/var/folders/gp/x0f5sgq13db073j79l3_2tb40000gn/T/ipykernel_7185/254227506.py:51: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " volume_profile.iloc[i]['Buy Volume'] += buy_volume\n", "/var/folders/gp/x0f5sgq13db073j79l3_2tb40000gn/T/ipykernel_7185/254227506.py:52: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " volume_profile.iloc[i]['Sell Volume'] += sell_volume\n" ] }, { "data": { "image/png": "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m6eddhonn3zyg8oGBwd50pOeNOo6xxxzDOeff/64t90rXuMmSZIe5PWvn9j2Pv3p9dfZdtttGRwcBOCSSy7h5JNP5sorrxzXdhcsWMChhx7KBz7wgbVl5557Lq985SvH1e5kcsRNkiRNKXfffTc77rgjAN/5znd48YtfvHbZCSecwBe/+EUuv/xyjjjiiLXll112GX/913/9oHb23ntvdthhB6655pq1Zeeddx7z589ncHCQAw44gLlz53LEEUfw29/+9iH96OvrY+XKlQAMDAxw0EEHAZ2RvIULF3LwwQfT19fHhRdeyNve9jbmzJnDIYccwqpVqwBYvHgxBx54IPvvvz8vfOELWb58+bifG4ObJEmadL///e+ZN28eT3ziE3nta1/Lu9/97nXWf97znseyZctYsWIFAF/4whc49thjH1JvwYIFnHvuuQD84Ac/YKeddmL27NkcffTRfOhDH+K6665jzpw5vPe9792g/t58881cfPHFXHTRRbz61a/muc99LkuWLGHbbbfl4osvZtWqVbzpTW/i/PPPZ/HixbzmNa/hlFNO2aBtjMTgJkmSJt3QqdIbb7yRf/3Xf+Xoo4+mqkatn4SjjjqKr3zlK9x5551cffXVHHrooQ+pN3/+fM4//3zWrFnDueeey4IFC7jrrru48847OfDAAwFYuHAh3/3udzeov4ceeijTp09nzpw53H///RxyyCEAzJkzh1tuuYWf/OQnXH/99bzgBS9g3rx5nHHGGdx+++0btI2ReI2bJEmaUv7iL/6ClStXsmLFCrbeemvWrFmzdln3x2cce+yxvOQlL2HGjBkceeSRbL31Q2PNrFmz6Ovr48orr+SCCy7g6quvHnM/urc9/GM7ttlmGwC22morpk+fvvYO0a222orVq1dTVey7774btL2xcMRNkiRNKTfeeCP3338/O+20E3vssQc33HADf/zjH7nrrru4/PLL19bbdddd2XXXXTnjjDM45phjRm1vwYIFvOUtb2GvvfZi991351GPehQ77rgjV111FQBf/vKX146+devr62Px4sUAXHDBBRu0D3vvvTcrVqxYG9xWrVrF0qVLN6iNkTjiJkmSJt3QNW7Q+VaBRYsWMW3aNGbNmsUrXvEK5s6dy+zZs9lvv/0etN6rXvUqVqxYwT777DNq20ceeSQnnngin/jEJ9aWLVq0iOOPP5777ruPxz/+8XzhC194yHrvec97OO6443j/+9/PM57xjA3an4c97GGcf/75vPnNb+auu+5i9erVnHTSSey7774b1M5wWdf5481Ff39/DQwMTHY3JEmakpYtW7bOzzabyk444QT2228/jjvuuMnuykYZ6blPsriq+keq74ibJElqpf3335/tttuOj370o5PdlU3G4CZJklpp6PqzLYk3J0iSJLWEwU2SJKklDG6SJEktYXCTJElqCYObJEmadGeeeSb77rsvc+fOZd68eQ/6YviRHHPMMZx//vkAHHTQQQz/2K/TTjuNk08++UFlg4OD6/zYk+42p6qe3VWaZBbwJeDPgDXAZ6rqn5KcDry0Kfs1cExV/aJZZy7waeCRzfKnVdUfhrX7aOD/A/qAW4BXVNVve7UfkiRtcV7/+olt79OfXufiq6++mm9+85tce+21bLPNNqxcuZI//elP49rkggULOPTQQ/nABz6wtuzcc8/lla985bjanWy9HHFbDby1qp4EHAC8Mck+wEeqam5VzQO+CZwKkGRr4CvA8VW1L3AQsGqEdt8BXF5Vs4HLm3lJktRSy5cvZ+edd177/Z8777wzu+66K9D5yI8DDzyQ/fffnxe+8IUsX758TG3uvffe7LDDDg8auTvvvPOYP38+g4ODHHDAAcydO5cjjjiC3/72oeM/fX19rFy5EoCBgQEOOuggoDOSt3DhQg4++GD6+vq48MILedvb3sacOXM45JBDWLVq1bj6vT49C25Vtbyqrm2m7wGWAbtV1d1d1bYDhr664WDguqr6cbPOHVV1/whNvxRY1EwvAg7vQfclSdImcvDBB3PbbbfxhCc8gTe84Q1ceeWVQOf7Pd/0pjdx/vnns3jxYl7zmtdwyimnjLndBQsWcO655wLwgx/8gJ122onZs2dz9NFH86EPfYjrrruOOXPm8N73vneD+nvzzTdz8cUXc9FFF/HqV7+a5z73uSxZsoRtt92Wiy++eNz9XpdN8gG8SfqA/YBrmvkzgaOBu4DnNtWeAFSSS4CZwLlV9eERmntsVS2HTjhM8pged1+SJPXQ9ttvz+LFi7nqqqu44oor+Ju/+Rs++MEP0t/fz/XXX88LXvACAO6//3522WWXMbc7f/58/vIv/5KPfvSjnHvuuSxYsIC77rqLO++8c+2Xyi9cuJAjjzxyg/p76KGHMn36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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "import yfinance as yf\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "def fetch_stock_data(ticker, start, intervals=['1m', '5m', '15m', '30m', '60m', '240m', '1d']):\n", " \"\"\"\n", " Fetch stock data from Yahoo Finance for the given intervals and select the appropriate interval.\n", " :param ticker: Stock ticker symbol\n", " :param start: Start date for data (YYYY-MM-DD)\n", " :param intervals: List of intervals to try\n", " :return: DataFrame with stock data for the selected interval\n", " \"\"\"\n", " for interval in intervals:\n", " data = yf.download(ticker, start=start, interval=interval)\n", " if len(data) < 5000:\n", " return data, interval\n", " return data, intervals[-1] # Return data with the largest interval if all are above 5000 bars\n", "\n", "def calculate_volume_profile(data, bins=25, volume_type='Up/Down'):\n", " \"\"\"\n", " Calculate the volume profile.\n", " :param data: DataFrame with stock data\n", " :param bins: Number of bins for price levels\n", " :param volume_type: Type of volume to display ('Total', 'Up/Down', 'Delta')\n", " :return: volume profile DataFrame\n", " \"\"\"\n", " price_min = data['Low'].min()\n", " price_max = data['High'].max()\n", " bin_edges = np.linspace(price_min, price_max, bins + 1)\n", " \n", " volume_profile = pd.DataFrame(index=bin_edges[:-1], columns=['Total Volume', 'Buy Volume', 'Sell Volume'])\n", " volume_profile['Total Volume'] = 0\n", " volume_profile['Buy Volume'] = 0\n", " volume_profile['Sell Volume'] = 0\n", "\n", " for index, row in data.iterrows():\n", " bin_indices = np.digitize([row['Low'], row['High']], bin_edges) - 1\n", " bin_indices = [max(0, min(bins-1, b)) for b in bin_indices]\n", " \n", " volume = row['Volume']\n", " if row['Close'] > row['Open']:\n", " buy_volume = volume\n", " sell_volume = 0\n", " else:\n", " buy_volume = 0\n", " sell_volume = volume\n", " \n", " for i in range(bin_indices[0], bin_indices[1] + 1):\n", " volume_profile.iloc[i]['Total Volume'] += volume\n", " volume_profile.iloc[i]['Buy Volume'] += buy_volume\n", " volume_profile.iloc[i]['Sell Volume'] += sell_volume\n", " \n", " if volume_type == 'Total':\n", " volume_profile['Volume'] = volume_profile['Total Volume']\n", " elif volume_type == 'Up/Down':\n", " volume_profile['Volume'] = volume_profile['Buy Volume'] - volume_profile['Sell Volume']\n", " elif volume_type == 'Delta':\n", " volume_profile['Volume'] = volume_profile['Buy Volume'] + volume_profile['Sell Volume']\n", " \n", " return volume_profile\n", "\n", "def plot_volume_profile(volume_profile, title):\n", " \"\"\"\n", " Plot the volume profile.\n", " :param volume_profile: DataFrame with volume profile\n", " :param title: Title for the plot\n", " \"\"\"\n", " plt.figure(figsize=(10, 6))\n", " plt.barh(volume_profile.index, volume_profile['Buy Volume'], height=volume_profile.index[1] - volume_profile.index[0], color='blue', alpha=0.6, label='Buy Volume')\n", " plt.barh(volume_profile.index, volume_profile['Sell Volume'], height=volume_profile.index[1] - volume_profile.index[0], color='red', alpha=0.6, label='Sell Volume', left=volume_profile['Buy Volume'])\n", " plt.xlabel('Volume')\n", " plt.ylabel('Price')\n", " plt.title(title)\n", " plt.legend()\n", " plt.show()\n", "\n", "# Example usage\n", "ticker = 'AAPL'\n", "start_date = '2024-07-16'\n", "\n", "data, selected_interval = fetch_stock_data(ticker, start=start_date)\n", "volume_profile = calculate_volume_profile(data, bins=25, volume_type='Up/Down')\n", "plot_volume_profile(volume_profile, title=f'Volume Profile for {ticker} on {start_date} (Interval: {selected_interval})')\n" ] }, { "cell_type": "code", "execution_count": null, "id": "28dbe32b", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12" } }, "nbformat": 4, "nbformat_minor": 5 }