Upload 100 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +2 -0
- examples/BacktestingMomentumTrading.ipynb +0 -0
- examples/COMMUNITY_EXAMPLE_TEMPLATE.ipynb +71 -0
- examples/EthereumTrendAnalysis.ipynb +0 -0
- examples/README.md +95 -0
- examples/content.json +57 -0
- examples/copperToGoldRatio.ipynb +0 -0
- examples/currencyExchangeRateForecasting.ipynb +0 -0
- examples/financialStatements.ipynb +1244 -0
- examples/financialStatements.webp +0 -0
- examples/findSymbols.ipynb +0 -0
- examples/findSymbols.webp +0 -0
- examples/googleColab.ipynb +0 -0
- examples/googleColab.webp +0 -0
- examples/impliedEarningsMove.ipynb +691 -0
- examples/impliedEarningsMove.webp +0 -0
- examples/loadHistoricalPriceData.ipynb +2514 -0
- examples/mAndAImpact.ipynb +0 -0
- examples/openbb-apachebeam/README.md +12 -0
- examples/openbb-apachebeam/requirements.txt +2 -0
- examples/openbb-apachebeam/tests/__init__.py +0 -0
- examples/openbb-apachebeam/tests/test_obb_pipeline.py +48 -0
- examples/openbbPlatformAsLLMTools.ipynb +0 -0
- examples/platform_standardization.ipynb +761 -0
- examples/portfolioOptimizationUsingModernPortfolioTheory.ipynb +0 -0
- examples/riskReturnAnalysis.ipynb +0 -0
- examples/sectorRotationStrategy.ipynb +0 -0
- examples/streamlit/news.py +444 -0
- examples/streamlit/requirements.txt +3 -0
- examples/streamlit_news.webp +0 -0
- examples/usdLiquidityIndex.ipynb +0 -0
- frontend-components/fonts/FiraCode-Regular.ttf +3 -0
- frontend-components/fonts/FiraCode-VF.ttf +3 -0
- frontend-components/plotly/.gitignore +24 -0
- frontend-components/plotly/README.md +70 -0
- frontend-components/plotly/index.html +40 -0
- frontend-components/plotly/package-lock.json +0 -0
- frontend-components/plotly/package.json +42 -0
- frontend-components/plotly/postcss.config.cjs +6 -0
- frontend-components/plotly/src/App.tsx +142 -0
- frontend-components/plotly/src/components/AutoScaling.tsx +232 -0
- frontend-components/plotly/src/components/ChangeColor.tsx +95 -0
- frontend-components/plotly/src/components/Chart.tsx +902 -0
- frontend-components/plotly/src/components/Config.tsx +800 -0
- frontend-components/plotly/src/components/Dialogs/AlertDialog.tsx +42 -0
- frontend-components/plotly/src/components/Dialogs/CommonDialog.tsx +43 -0
- frontend-components/plotly/src/components/Dialogs/OverlayChartDialog.tsx +651 -0
- frontend-components/plotly/src/components/Dialogs/TextChartDialog.tsx +315 -0
- frontend-components/plotly/src/components/Dialogs/TitleChartDialog.tsx +157 -0
- frontend-components/plotly/src/components/Icons/Close.tsx +28 -0
.gitattributes
CHANGED
|
@@ -36,3 +36,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 36 |
build/conda/installer/assets/dmg_volume.icns filter=lfs diff=lfs merge=lfs -text
|
| 37 |
build/conda/installer/assets/Installer_vertical2.bmp filter=lfs diff=lfs merge=lfs -text
|
| 38 |
cli/openbb_cli/assets/styles/default/Consolas.ttf filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 36 |
build/conda/installer/assets/dmg_volume.icns filter=lfs diff=lfs merge=lfs -text
|
| 37 |
build/conda/installer/assets/Installer_vertical2.bmp filter=lfs diff=lfs merge=lfs -text
|
| 38 |
cli/openbb_cli/assets/styles/default/Consolas.ttf filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
frontend-components/fonts/FiraCode-Regular.ttf filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
frontend-components/fonts/FiraCode-VF.ttf filter=lfs diff=lfs merge=lfs -text
|
examples/BacktestingMomentumTrading.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/COMMUNITY_EXAMPLE_TEMPLATE.ipynb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Instructions for Contributors\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"Welcome to this example notebook for OpenBB! Please follow the steps below:\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"1. **Fill in the details**: Customize the second cell with the name of the notebook, your GitHub profile link, and a brief description of what your notebook demonstrates.\n",
|
| 12 |
+
"2. **Add Your Code**: Make sure to include clean and commented code sections throughout the notebook.\n",
|
| 13 |
+
"3. **Test Before Submitting**: Run all cells to ensure the notebook functions as expected.\n",
|
| 14 |
+
"4. **Keep it Simple and Clear**: Make your explanations and code as clear as possible for others to follow.\n",
|
| 15 |
+
"5. **Run in Colab Button**: Ensure the \"Run in Colab\" button links properly to the notebook. You can test it by clicking the button and verifying it loads your notebook.\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"Please refer to the documentation at [OpenBB Documentation](https://docs.openbb.co/) for additional guidance.\n",
|
| 18 |
+
"\n",
|
| 19 |
+
"Remove this cell before submitting your notebook."
|
| 20 |
+
]
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"cell_type": "markdown",
|
| 24 |
+
"metadata": {},
|
| 25 |
+
"source": [
|
| 26 |
+
"## [Notebook Name]\n",
|
| 27 |
+
"\n",
|
| 28 |
+
"#### Description\n",
|
| 29 |
+
"[Briefly describe what this notebook demonstrates, e.g., \"This notebook demonstrates how to backtest a momentum trading strategy using OpenBB's historical data.\"]\n",
|
| 30 |
+
"\n",
|
| 31 |
+
"#### Author\n",
|
| 32 |
+
"[Your Name](https://github.com/[YourGitHubUsername])\n",
|
| 33 |
+
"\n",
|
| 34 |
+
"[](https://colab.research.google.com/github/OpenBB-Finance/OpenBB/blob/develop/examples/[Notebook_Name].ipynb)"
|
| 35 |
+
]
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"cell_type": "markdown",
|
| 39 |
+
"metadata": {},
|
| 40 |
+
"source": [
|
| 41 |
+
"If you are running this notebook in Colab, you can run the following command to install the OpenBB Platform:\n",
|
| 42 |
+
"\n",
|
| 43 |
+
"```python\n",
|
| 44 |
+
"!pip install openbb\n",
|
| 45 |
+
"```\n"
|
| 46 |
+
]
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
"cell_type": "code",
|
| 50 |
+
"execution_count": null,
|
| 51 |
+
"metadata": {},
|
| 52 |
+
"outputs": [],
|
| 53 |
+
"source": [
|
| 54 |
+
"from openbb import obb"
|
| 55 |
+
]
|
| 56 |
+
}
|
| 57 |
+
],
|
| 58 |
+
"metadata": {
|
| 59 |
+
"kernelspec": {
|
| 60 |
+
"display_name": "obb",
|
| 61 |
+
"language": "python",
|
| 62 |
+
"name": "python3"
|
| 63 |
+
},
|
| 64 |
+
"language_info": {
|
| 65 |
+
"name": "python",
|
| 66 |
+
"version": "3.9.19"
|
| 67 |
+
}
|
| 68 |
+
},
|
| 69 |
+
"nbformat": 4,
|
| 70 |
+
"nbformat_minor": 2
|
| 71 |
+
}
|
examples/EthereumTrendAnalysis.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Jupyter Notebook Examples Using the OpenBB Platform
|
| 2 |
+
|
| 3 |
+
This folder is a collection of example notebooks that demonstrate some of the ways to get started with using the OpenBB Platform. To run them, ensure that the active kernel selected is the same Python virtual environment where OpenBB was installed.
|
| 4 |
+
|
| 5 |
+
## Table of Contents
|
| 6 |
+
|
| 7 |
+
### googleColab
|
| 8 |
+
|
| 9 |
+
This notebook installs the OpenBB Platform in a Google Colab environment with examples for:
|
| 10 |
+
|
| 11 |
+
- Logging into OpenBB Hub
|
| 12 |
+
- Setting the output preference
|
| 13 |
+
- Fetching options and company fundamentals data
|
| 14 |
+
- Creating bar chart visualizations
|
| 15 |
+
|
| 16 |
+
### findSymbols
|
| 17 |
+
|
| 18 |
+
This notebook provides an introduction to discovering, finding, and searching ticker symbols.
|
| 19 |
+
|
| 20 |
+
- Search
|
| 21 |
+
- Find company and institutional filings
|
| 22 |
+
- Screen stocks by region and metrics
|
| 23 |
+
|
| 24 |
+
### loadHistoricalPriceData
|
| 25 |
+
|
| 26 |
+
This notebook walks through collecting historical price data, at different intervals, using a variety of sources.
|
| 27 |
+
|
| 28 |
+
- Loading data with different intervals, and changing sources
|
| 29 |
+
- A brief explanation of ticker symbology
|
| 30 |
+
- Resampling a time series index
|
| 31 |
+
- Some differences between providers, and comparing outputs
|
| 32 |
+
|
| 33 |
+
### financialStatements
|
| 34 |
+
|
| 35 |
+
This set of examples introduces financial statements in the OpenBB Platform and compares the free cash flow yields of large-cap retail industry companies.
|
| 36 |
+
|
| 37 |
+
- Financial statements
|
| 38 |
+
- What to expect with data from different sources
|
| 39 |
+
- Financial attributes
|
| 40 |
+
- Ratios and other metrics
|
| 41 |
+
|
| 42 |
+
### copperToGoldRatio
|
| 43 |
+
|
| 44 |
+
This notebook explains how to calculate and plot the Copper-to-Gold ratio.
|
| 45 |
+
|
| 46 |
+
- Loading historical front-month futures prices.
|
| 47 |
+
- Getting the historical series from FRED for the 10-year constant maturity US treasury bill.
|
| 48 |
+
- Performing basic DataFrame operations.
|
| 49 |
+
- Creating charts with Plotly Graph Objects.
|
| 50 |
+
|
| 51 |
+
### openbbPlatformAsLLMTools
|
| 52 |
+
|
| 53 |
+
This notebook shows you how you can use OpenbB Platform as functions in an LLM by leveraging function calling.
|
| 54 |
+
|
| 55 |
+
- Create an LLM tool from an OpenBB Platform function
|
| 56 |
+
- Convert all OpenBB Platform functions to LLM tools
|
| 57 |
+
- Build a basic Langchain agent that can utilize function calling
|
| 58 |
+
- Run the agent
|
| 59 |
+
|
| 60 |
+
### usdLiquidityIndex
|
| 61 |
+
|
| 62 |
+
This notebook demonstrates how to query the Federal Reserve Economic Database and recreate the USD Liquidity Index.
|
| 63 |
+
|
| 64 |
+
- Search FRED for series IDs.
|
| 65 |
+
- Load multiple series as a single call.
|
| 66 |
+
- Unpacking the data response from the FRED query.
|
| 67 |
+
- Perform arithmetic operations on a DataFrame.
|
| 68 |
+
- Normalization methods for a series or DataFrame.
|
| 69 |
+
- Simple processes for creating charts.
|
| 70 |
+
|
| 71 |
+
### impliedEarningsMove
|
| 72 |
+
|
| 73 |
+
This notebook demonstrates how to calculate the implied earnings move using options prices from free sources.
|
| 74 |
+
|
| 75 |
+
- Get upcoming earnings calendar.
|
| 76 |
+
- Fetch options chains data.
|
| 77 |
+
- Get the last price of the underlying stock.
|
| 78 |
+
- Find the nearest call and put strikes to the last price of the stock.
|
| 79 |
+
- Calculate the implied daily move using the price of a straddle.
|
| 80 |
+
|
| 81 |
+
### streamlit/news
|
| 82 |
+
|
| 83 |
+
This is an example Streamlit dashboard for news headlines with data from Biztoc, Benzinga, FMP, Intrinio, and Tiingo.
|
| 84 |
+
|
| 85 |
+
:::warning
|
| 86 |
+
At least one API key is required. You can get a free Biztoc API key [here](https://rapidapi.com/thma/api/biztoc)
|
| 87 |
+
:::
|
| 88 |
+
|
| 89 |
+
To run, copy the file to your system, open a terminal, navigate to where the file is, and with your `obb` Python environment active, enter:
|
| 90 |
+
|
| 91 |
+
```
|
| 92 |
+
pip install streamlit
|
| 93 |
+
pip install openbb-biztoc
|
| 94 |
+
streamlit run news.py
|
| 95 |
+
```
|
examples/content.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"title": "Install in Google Colab",
|
| 4 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/googleColab.ipynb",
|
| 5 |
+
"img":"https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/googleColab.webp",
|
| 6 |
+
"description":
|
| 7 |
+
"Install the OpenBB Platform in Google Colab and get started pulling data and creating visualizations."
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"title": "Find Symbols",
|
| 11 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/findSymbols.ipynb",
|
| 12 |
+
"img": "https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/findSymbols.webp",
|
| 13 |
+
"description":
|
| 14 |
+
"An introduction to discovering, finding, screening, and searching symbols using different sources."
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"title": "Load Historical Price Data",
|
| 18 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/loadHistoricalPriceData.ipynb",
|
| 19 |
+
"img": "https://my.openbb.co/assets/images/sdk/examples/loadHistoricalPriceData.webp",
|
| 20 |
+
"description":
|
| 21 |
+
"Loading data with different intervals and sources, ticker symbology, load data from other asset classes, load multiple tickers in one go, draw lines on plotly."
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"title": "Copper To Gold Ratio",
|
| 25 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/copperToGoldRatio.ipynb",
|
| 26 |
+
"img": "https://my.openbb.co/assets/images/sdk/examples/copperToGoldRatio.webp",
|
| 27 |
+
"description":
|
| 28 |
+
"Calculate copper to gold ratio, load front-month future prices, 10-year constant maturity vs treasury bill, basic dataframe operations, plotting on 2 y-axis."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"title": "USD Liquidity Index",
|
| 32 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/usdLiquidityIndex.ipynb",
|
| 33 |
+
"img": "https://my.openbb.co/assets/images/sdk/examples/usdLiquidityIndex.webp",
|
| 34 |
+
"description":
|
| 35 |
+
"Query the Federal Reserve Economic Database and recreate the USD Liquidity Index, load multiple data series, basic operations on a dataframe, normalization methods, and creating custom chart."
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"title": "Financial Statements",
|
| 39 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/financialStatements.ipynb",
|
| 40 |
+
"img": "https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/financialStatements.webp",
|
| 41 |
+
"description":
|
| 42 |
+
"Get started with financial statements in the OpenBB Platform. This notebook compares the data from different providers and demonstrates how to access items within the three main financial statements - balance, cash, and income."
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"title": "Implied Earnings Move",
|
| 46 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/impliedEarningsMove.ipynb",
|
| 47 |
+
"img": "https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/impliedEarningsMove.webp",
|
| 48 |
+
"description":
|
| 49 |
+
"Calculate the implied earnings move using options prices. This notebook demonstrates how to get the data from free sources and apply filters to arrive at the expected move, as a percent, in either direction."
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"title": "Streamlit News Headlines",
|
| 53 |
+
"url": "https://github.com/OpenBB-finance/OpenBB/blob/develop/examples/streamlit/news.py",
|
| 54 |
+
"img": "https://raw.githubusercontent.com/OpenBB-finance/OpenBBTerminal/develop/examples/streamlit_news.webp",
|
| 55 |
+
"description": "An example Streamlit dashboard for news headlines with data from Biztoc, Benzinga, FMP, Intrinio, and Tiingo."
|
| 56 |
+
}
|
| 57 |
+
]
|
examples/copperToGoldRatio.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/currencyExchangeRateForecasting.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/financialStatements.ipynb
ADDED
|
@@ -0,0 +1,1244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Financial Statements in the OpenBB Platform\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"OpenBB Platform data extensions provide access to financial statements as quarterly or annual. There are also endpoints for ratios and other common non-GAAP metrics. Most data providers require a subscription to access all data. Refer to the website of a specific provider for details on entitlements and coverage.\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"Financial statement functions are grouped under the `obb.equity.fundamental` module.\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"## Endpoints\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"The typical financial statements consist of three endpoints:\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"- Balance Sheet: `obb.equity.fundamental.balance()`\n",
|
| 18 |
+
"- Income Statement: `obb.equity.fundamental.income()`\n",
|
| 19 |
+
"- Cash Flow Statement: `obb.equity.fundamental.cash()`\n",
|
| 20 |
+
"\n",
|
| 21 |
+
"The main parameters are:\n",
|
| 22 |
+
"\n",
|
| 23 |
+
"- `symbol`: The company's symbol.\n",
|
| 24 |
+
"- `period`: 'annual' or 'quarter'. Default is 'annual'.\n",
|
| 25 |
+
"- `limit`: Limit the number of results returned, from the latest. Default is 5. For perspective, 150 will go back to 1985. The amount of historical records varies by provider.\n",
|
| 26 |
+
"\n",
|
| 27 |
+
"### Field Names\n",
|
| 28 |
+
"\n",
|
| 29 |
+
"Some considerations to keep in mind when working with financial statements data are:\n",
|
| 30 |
+
"\n",
|
| 31 |
+
"- Every data provider has their own way of parsing and organizing the three financial statements.\n",
|
| 32 |
+
"- Items within each statement will vary by source and by the type of company reporting.\n",
|
| 33 |
+
"- Names of line items will vary by source.\n",
|
| 34 |
+
"- \"Date\" values may differ because they are from the period starting/ending or date of reporting.\n",
|
| 35 |
+
"\n",
|
| 36 |
+
"This example highlights how different providers will have different labels for compnay facts.\n",
|
| 37 |
+
"\n",
|
| 38 |
+
"\n",
|
| 39 |
+
"**Note**: API Keys are required for FMP, Intrinio, and Polygon."
|
| 40 |
+
]
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"cell_type": "code",
|
| 44 |
+
"execution_count": 48,
|
| 45 |
+
"metadata": {},
|
| 46 |
+
"outputs": [],
|
| 47 |
+
"source": [
|
| 48 |
+
"import pandas as pd\n",
|
| 49 |
+
"from openbb import obb"
|
| 50 |
+
]
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"cell_type": "code",
|
| 54 |
+
"execution_count": 49,
|
| 55 |
+
"metadata": {},
|
| 56 |
+
"outputs": [
|
| 57 |
+
{
|
| 58 |
+
"data": {
|
| 59 |
+
"text/html": [
|
| 60 |
+
"<div>\n",
|
| 61 |
+
"<style scoped>\n",
|
| 62 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 63 |
+
" vertical-align: middle;\n",
|
| 64 |
+
" }\n",
|
| 65 |
+
"\n",
|
| 66 |
+
" .dataframe tbody tr th {\n",
|
| 67 |
+
" vertical-align: top;\n",
|
| 68 |
+
" }\n",
|
| 69 |
+
"\n",
|
| 70 |
+
" .dataframe thead th {\n",
|
| 71 |
+
" text-align: right;\n",
|
| 72 |
+
" }\n",
|
| 73 |
+
"</style>\n",
|
| 74 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 75 |
+
" <thead>\n",
|
| 76 |
+
" <tr style=\"text-align: right;\">\n",
|
| 77 |
+
" <th></th>\n",
|
| 78 |
+
" <th>yfinance</th>\n",
|
| 79 |
+
" <th>fmp</th>\n",
|
| 80 |
+
" <th>intrinio</th>\n",
|
| 81 |
+
" <th>polygon</th>\n",
|
| 82 |
+
" </tr>\n",
|
| 83 |
+
" </thead>\n",
|
| 84 |
+
" <tbody>\n",
|
| 85 |
+
" <tr>\n",
|
| 86 |
+
" <th>0</th>\n",
|
| 87 |
+
" <td>5.535600e+10</td>\n",
|
| 88 |
+
" <td>5.535600e+10</td>\n",
|
| 89 |
+
" <td>5.535600e+10</td>\n",
|
| 90 |
+
" <td>5.535600e+10</td>\n",
|
| 91 |
+
" </tr>\n",
|
| 92 |
+
" <tr>\n",
|
| 93 |
+
" <th>1</th>\n",
|
| 94 |
+
" <td>5.333500e+10</td>\n",
|
| 95 |
+
" <td>5.333500e+10</td>\n",
|
| 96 |
+
" <td>5.333500e+10</td>\n",
|
| 97 |
+
" <td>5.333500e+10</td>\n",
|
| 98 |
+
" </tr>\n",
|
| 99 |
+
" <tr>\n",
|
| 100 |
+
" <th>2</th>\n",
|
| 101 |
+
" <td>5.381100e+10</td>\n",
|
| 102 |
+
" <td>5.381100e+10</td>\n",
|
| 103 |
+
" <td>5.381100e+10</td>\n",
|
| 104 |
+
" <td>5.381100e+10</td>\n",
|
| 105 |
+
" </tr>\n",
|
| 106 |
+
" </tbody>\n",
|
| 107 |
+
"</table>\n",
|
| 108 |
+
"</div>"
|
| 109 |
+
],
|
| 110 |
+
"text/plain": [
|
| 111 |
+
" yfinance fmp intrinio polygon\n",
|
| 112 |
+
"0 5.535600e+10 5.535600e+10 5.535600e+10 5.535600e+10\n",
|
| 113 |
+
"1 5.333500e+10 5.333500e+10 5.333500e+10 5.333500e+10\n",
|
| 114 |
+
"2 5.381100e+10 5.381100e+10 5.381100e+10 5.381100e+10"
|
| 115 |
+
]
|
| 116 |
+
},
|
| 117 |
+
"execution_count": 49,
|
| 118 |
+
"metadata": {},
|
| 119 |
+
"output_type": "execute_result"
|
| 120 |
+
}
|
| 121 |
+
],
|
| 122 |
+
"source": [
|
| 123 |
+
"df = pd.DataFrame()\n",
|
| 124 |
+
"\n",
|
| 125 |
+
"df[\"yfinance\"] = (\n",
|
| 126 |
+
" obb.equity.fundamental.balance(\n",
|
| 127 |
+
" \"TGT\", provider=\"yfinance\"\n",
|
| 128 |
+
" ) # There is no limit for yFinance, historical data is limited.\n",
|
| 129 |
+
" .to_df()\n",
|
| 130 |
+
" .get(\"total_assets\")\n",
|
| 131 |
+
" .head(3)\n",
|
| 132 |
+
")\n",
|
| 133 |
+
"\n",
|
| 134 |
+
"df[\"fmp\"] = (\n",
|
| 135 |
+
" obb.equity.fundamental.balance(\"TGT\", provider=\"fmp\", limit=3)\n",
|
| 136 |
+
" .to_df()\n",
|
| 137 |
+
" .get(\"total_assets\")\n",
|
| 138 |
+
")\n",
|
| 139 |
+
"\n",
|
| 140 |
+
"df[\"intrinio\"] = (\n",
|
| 141 |
+
" obb.equity.fundamental.balance(\"TGT\", provider=\"intrinio\", limit=3)\n",
|
| 142 |
+
" .to_df()\n",
|
| 143 |
+
" .get(\"total_assets\")\n",
|
| 144 |
+
")\n",
|
| 145 |
+
"\n",
|
| 146 |
+
"df[\"polygon\"] = (\n",
|
| 147 |
+
" obb.equity.fundamental.balance(\"TGT\", provider=\"polygon\", limit=3)\n",
|
| 148 |
+
" .to_df()\n",
|
| 149 |
+
" .get(\"total_assets\")\n",
|
| 150 |
+
")\n",
|
| 151 |
+
"\n",
|
| 152 |
+
"df"
|
| 153 |
+
]
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"cell_type": "markdown",
|
| 157 |
+
"metadata": {},
|
| 158 |
+
"source": [
|
| 159 |
+
"### Weighted Average Shares Outstanding\n",
|
| 160 |
+
"\n",
|
| 161 |
+
"This key metric will be found under the income statement. It might also be called, 'basic', and the numbers do not include authorized but unissued shares. A declining count over time is a sign that the company is returning capital to shareholders in the form of buy backs. Under ideal circumstances, it is more capital-efficient, for both company and shareholders, because distributions are double-taxed. The company pays income tax on paid dividends, and the beneficiary pays income tax again on receipt.\n",
|
| 162 |
+
"\n",
|
| 163 |
+
"A company will disclose how many shares are outstanding at the end of the period as a weighted average over the reporting period - three months.\n",
|
| 164 |
+
"\n",
|
| 165 |
+
"Let's take a look at Target. To make the numbers easier to read, we'll divide the entire column by one million."
|
| 166 |
+
]
|
| 167 |
+
},
|
| 168 |
+
{
|
| 169 |
+
"cell_type": "code",
|
| 170 |
+
"execution_count": 50,
|
| 171 |
+
"metadata": {},
|
| 172 |
+
"outputs": [
|
| 173 |
+
{
|
| 174 |
+
"data": {
|
| 175 |
+
"text/plain": [
|
| 176 |
+
"0 462.5\n",
|
| 177 |
+
"Name: weighted_average_basic_shares_outstanding, dtype: float64"
|
| 178 |
+
]
|
| 179 |
+
},
|
| 180 |
+
"metadata": {},
|
| 181 |
+
"output_type": "display_data"
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"data": {
|
| 185 |
+
"text/plain": [
|
| 186 |
+
"149 1169.248\n",
|
| 187 |
+
"Name: weighted_average_basic_shares_outstanding, dtype: float64"
|
| 188 |
+
]
|
| 189 |
+
},
|
| 190 |
+
"metadata": {},
|
| 191 |
+
"output_type": "display_data"
|
| 192 |
+
}
|
| 193 |
+
],
|
| 194 |
+
"source": [
|
| 195 |
+
"data = obb.equity.fundamental.income(\n",
|
| 196 |
+
" \"TGT\", provider=\"fmp\", limit=150, period=\"quarter\"\n",
|
| 197 |
+
").to_df()\n",
|
| 198 |
+
"\n",
|
| 199 |
+
"shares = data[\"weighted_average_basic_shares_outstanding\"] / 1000000\n",
|
| 200 |
+
"\n",
|
| 201 |
+
"display(shares.head(1))\n",
|
| 202 |
+
"\n",
|
| 203 |
+
"display(shares.tail(1))"
|
| 204 |
+
]
|
| 205 |
+
},
|
| 206 |
+
{
|
| 207 |
+
"cell_type": "markdown",
|
| 208 |
+
"metadata": {},
|
| 209 |
+
"source": [
|
| 210 |
+
"Thirty-seven years later, the share count is approaching a two-thirds reduction. 12.2% over the past five years. In four reporting periods, 1.3 million shares have been taken out of the float."
|
| 211 |
+
]
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
"cell_type": "code",
|
| 215 |
+
"execution_count": 51,
|
| 216 |
+
"metadata": {},
|
| 217 |
+
"outputs": [
|
| 218 |
+
{
|
| 219 |
+
"data": {
|
| 220 |
+
"text/plain": [
|
| 221 |
+
"0.3362834285714287"
|
| 222 |
+
]
|
| 223 |
+
},
|
| 224 |
+
"metadata": {},
|
| 225 |
+
"output_type": "display_data"
|
| 226 |
+
},
|
| 227 |
+
{
|
| 228 |
+
"data": {
|
| 229 |
+
"text/plain": [
|
| 230 |
+
"-65.75199999999995"
|
| 231 |
+
]
|
| 232 |
+
},
|
| 233 |
+
"metadata": {},
|
| 234 |
+
"output_type": "display_data"
|
| 235 |
+
}
|
| 236 |
+
],
|
| 237 |
+
"source": [
|
| 238 |
+
"display(shares.pct_change(20).iloc[-1])\n",
|
| 239 |
+
"\n",
|
| 240 |
+
"display(shares.iloc[-4] - shares.iloc[-1])"
|
| 241 |
+
]
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"cell_type": "markdown",
|
| 245 |
+
"metadata": {},
|
| 246 |
+
"source": [
|
| 247 |
+
"With an average closing price of $143.37, that represents approximately $190M in buy backs."
|
| 248 |
+
]
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"cell_type": "code",
|
| 252 |
+
"execution_count": 52,
|
| 253 |
+
"metadata": {},
|
| 254 |
+
"outputs": [
|
| 255 |
+
{
|
| 256 |
+
"data": {
|
| 257 |
+
"text/plain": [
|
| 258 |
+
"190.75"
|
| 259 |
+
]
|
| 260 |
+
},
|
| 261 |
+
"execution_count": 52,
|
| 262 |
+
"metadata": {},
|
| 263 |
+
"output_type": "execute_result"
|
| 264 |
+
}
|
| 265 |
+
],
|
| 266 |
+
"source": [
|
| 267 |
+
"price = obb.equity.price.historical(\n",
|
| 268 |
+
" \"TGT\", start_date=\"2022-10-01\", provider=\"fmp\"\n",
|
| 269 |
+
").to_df()\n",
|
| 270 |
+
"\n",
|
| 271 |
+
"round((price[\"close\"].mean() * 1300000) / 1000000, 2)"
|
| 272 |
+
]
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"cell_type": "markdown",
|
| 276 |
+
"metadata": {},
|
| 277 |
+
"source": [
|
| 278 |
+
"### Dividends Paid\n",
|
| 279 |
+
"\n",
|
| 280 |
+
"Dividends paid is in the cash flow statement. We can calculate the amount-per-share with the reported data."
|
| 281 |
+
]
|
| 282 |
+
},
|
| 283 |
+
{
|
| 284 |
+
"cell_type": "code",
|
| 285 |
+
"execution_count": 54,
|
| 286 |
+
"metadata": {},
|
| 287 |
+
"outputs": [
|
| 288 |
+
{
|
| 289 |
+
"data": {
|
| 290 |
+
"text/plain": [
|
| 291 |
+
"136 0.040339\n",
|
| 292 |
+
"137 0.023793\n",
|
| 293 |
+
"138 0.020690\n",
|
| 294 |
+
"139 0.022969\n",
|
| 295 |
+
"Name: div_per_share, dtype: float64"
|
| 296 |
+
]
|
| 297 |
+
},
|
| 298 |
+
"execution_count": 54,
|
| 299 |
+
"metadata": {},
|
| 300 |
+
"output_type": "execute_result"
|
| 301 |
+
}
|
| 302 |
+
],
|
| 303 |
+
"source": [
|
| 304 |
+
"dividends = obb.equity.fundamental.cash(\n",
|
| 305 |
+
" \"TGT\", provider=\"fmp\", limit=150, period=\"quarter\"\n",
|
| 306 |
+
").to_df()[[\"payment_of_dividends\"]]\n",
|
| 307 |
+
"\n",
|
| 308 |
+
"dividends[\"shares\"] = data[[\"weighted_average_basic_shares_outstanding\"]]\n",
|
| 309 |
+
"dividends[\"div_per_share\"] = abs(\n",
|
| 310 |
+
" dividends[\"payment_of_dividends\"] / dividends[\"shares\"]\n",
|
| 311 |
+
")\n",
|
| 312 |
+
"\n",
|
| 313 |
+
"dividends[\"div_per_share\"].tail(4)"
|
| 314 |
+
]
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"cell_type": "markdown",
|
| 318 |
+
"metadata": {},
|
| 319 |
+
"source": [
|
| 320 |
+
"This can be compared against the real amounts paid to common share holders, as announced. Note that the dates above represent the report date, and that dividends paid are attributed to the quarter they were paid in. The value from \"2023-01-28\" equates to the fourth quarter of 2022."
|
| 321 |
+
]
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"cell_type": "code",
|
| 325 |
+
"execution_count": 55,
|
| 326 |
+
"metadata": {},
|
| 327 |
+
"outputs": [
|
| 328 |
+
{
|
| 329 |
+
"data": {
|
| 330 |
+
"text/html": [
|
| 331 |
+
"<div>\n",
|
| 332 |
+
"<style scoped>\n",
|
| 333 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 334 |
+
" vertical-align: middle;\n",
|
| 335 |
+
" }\n",
|
| 336 |
+
"\n",
|
| 337 |
+
" .dataframe tbody tr th {\n",
|
| 338 |
+
" vertical-align: top;\n",
|
| 339 |
+
" }\n",
|
| 340 |
+
"\n",
|
| 341 |
+
" .dataframe thead th {\n",
|
| 342 |
+
" text-align: right;\n",
|
| 343 |
+
" }\n",
|
| 344 |
+
"</style>\n",
|
| 345 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 346 |
+
" <thead>\n",
|
| 347 |
+
" <tr style=\"text-align: right;\">\n",
|
| 348 |
+
" <th></th>\n",
|
| 349 |
+
" <th>amount</th>\n",
|
| 350 |
+
" </tr>\n",
|
| 351 |
+
" <tr>\n",
|
| 352 |
+
" <th>ex_dividend_date</th>\n",
|
| 353 |
+
" <th></th>\n",
|
| 354 |
+
" </tr>\n",
|
| 355 |
+
" </thead>\n",
|
| 356 |
+
" <tbody>\n",
|
| 357 |
+
" <tr>\n",
|
| 358 |
+
" <th>2023-08-15</th>\n",
|
| 359 |
+
" <td>1.10</td>\n",
|
| 360 |
+
" </tr>\n",
|
| 361 |
+
" <tr>\n",
|
| 362 |
+
" <th>2023-05-16</th>\n",
|
| 363 |
+
" <td>1.08</td>\n",
|
| 364 |
+
" </tr>\n",
|
| 365 |
+
" <tr>\n",
|
| 366 |
+
" <th>2023-02-14</th>\n",
|
| 367 |
+
" <td>1.08</td>\n",
|
| 368 |
+
" </tr>\n",
|
| 369 |
+
" <tr>\n",
|
| 370 |
+
" <th>2022-11-15</th>\n",
|
| 371 |
+
" <td>1.08</td>\n",
|
| 372 |
+
" </tr>\n",
|
| 373 |
+
" </tbody>\n",
|
| 374 |
+
"</table>\n",
|
| 375 |
+
"</div>"
|
| 376 |
+
],
|
| 377 |
+
"text/plain": [
|
| 378 |
+
" amount\n",
|
| 379 |
+
"ex_dividend_date \n",
|
| 380 |
+
"2023-08-15 1.10\n",
|
| 381 |
+
"2023-05-16 1.08\n",
|
| 382 |
+
"2023-02-14 1.08\n",
|
| 383 |
+
"2022-11-15 1.08"
|
| 384 |
+
]
|
| 385 |
+
},
|
| 386 |
+
"execution_count": 55,
|
| 387 |
+
"metadata": {},
|
| 388 |
+
"output_type": "execute_result"
|
| 389 |
+
}
|
| 390 |
+
],
|
| 391 |
+
"source": [
|
| 392 |
+
"data = obb.equity.fundamental.dividends(\"TGT\", provider=\"fmp\").to_df()[\n",
|
| 393 |
+
" [\"ex_dividend_date\", \"amount\"]\n",
|
| 394 |
+
"]\n",
|
| 395 |
+
"data.ex_dividend_date = data.ex_dividend_date.astype(str)\n",
|
| 396 |
+
"data.set_index(\"ex_dividend_date\").loc[\"2023-08-15\":\"2022-11-15\"]"
|
| 397 |
+
]
|
| 398 |
+
},
|
| 399 |
+
{
|
| 400 |
+
"cell_type": "markdown",
|
| 401 |
+
"metadata": {},
|
| 402 |
+
"source": [
|
| 403 |
+
"The numbers check out, and the $2B paid to investors over four quarters is more than ten times the $190M returned through share buy backs.\n",
|
| 404 |
+
"\n",
|
| 405 |
+
"### Financial Attributes\n",
|
| 406 |
+
"\n",
|
| 407 |
+
"The `openbb-intrinio` data extension has an endpoint for extracting a single fact from financial statements. There is a helper function for looking up the correct `tag`.\n",
|
| 408 |
+
"\n",
|
| 409 |
+
"**Note:** Intrinio does not offer a free API level with access to data.\n",
|
| 410 |
+
"\n",
|
| 411 |
+
"#### Search Financial Attributes\n",
|
| 412 |
+
"\n",
|
| 413 |
+
"Search attributes by keyword."
|
| 414 |
+
]
|
| 415 |
+
},
|
| 416 |
+
{
|
| 417 |
+
"cell_type": "code",
|
| 418 |
+
"execution_count": 10,
|
| 419 |
+
"metadata": {},
|
| 420 |
+
"outputs": [
|
| 421 |
+
{
|
| 422 |
+
"data": {
|
| 423 |
+
"text/html": [
|
| 424 |
+
"<div>\n",
|
| 425 |
+
"<style scoped>\n",
|
| 426 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 427 |
+
" vertical-align: middle;\n",
|
| 428 |
+
" }\n",
|
| 429 |
+
"\n",
|
| 430 |
+
" .dataframe tbody tr th {\n",
|
| 431 |
+
" vertical-align: top;\n",
|
| 432 |
+
" }\n",
|
| 433 |
+
"\n",
|
| 434 |
+
" .dataframe thead th {\n",
|
| 435 |
+
" text-align: right;\n",
|
| 436 |
+
" }\n",
|
| 437 |
+
"</style>\n",
|
| 438 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 439 |
+
" <thead>\n",
|
| 440 |
+
" <tr style=\"text-align: right;\">\n",
|
| 441 |
+
" <th></th>\n",
|
| 442 |
+
" <th>id</th>\n",
|
| 443 |
+
" <th>name</th>\n",
|
| 444 |
+
" <th>tag</th>\n",
|
| 445 |
+
" <th>statement_code</th>\n",
|
| 446 |
+
" <th>statement_type</th>\n",
|
| 447 |
+
" <th>type</th>\n",
|
| 448 |
+
" <th>unit</th>\n",
|
| 449 |
+
" <th>parent_name</th>\n",
|
| 450 |
+
" <th>sequence</th>\n",
|
| 451 |
+
" <th>factor</th>\n",
|
| 452 |
+
" <th>transaction</th>\n",
|
| 453 |
+
" </tr>\n",
|
| 454 |
+
" </thead>\n",
|
| 455 |
+
" <tbody>\n",
|
| 456 |
+
" <tr>\n",
|
| 457 |
+
" <th>0</th>\n",
|
| 458 |
+
" <td>tag_BgkbWy</td>\n",
|
| 459 |
+
" <td>Market Capitalization</td>\n",
|
| 460 |
+
" <td>marketcap</td>\n",
|
| 461 |
+
" <td>calculations</td>\n",
|
| 462 |
+
" <td>industrial</td>\n",
|
| 463 |
+
" <td>valuation</td>\n",
|
| 464 |
+
" <td>usd</td>\n",
|
| 465 |
+
" <td>NaN</td>\n",
|
| 466 |
+
" <td>NaN</td>\n",
|
| 467 |
+
" <td>NaN</td>\n",
|
| 468 |
+
" <td>NaN</td>\n",
|
| 469 |
+
" </tr>\n",
|
| 470 |
+
" <tr>\n",
|
| 471 |
+
" <th>1</th>\n",
|
| 472 |
+
" <td>tag_kylOqz</td>\n",
|
| 473 |
+
" <td>Market Capitalization</td>\n",
|
| 474 |
+
" <td>marketcap</td>\n",
|
| 475 |
+
" <td>calculations</td>\n",
|
| 476 |
+
" <td>financial</td>\n",
|
| 477 |
+
" <td>valuation</td>\n",
|
| 478 |
+
" <td>usd</td>\n",
|
| 479 |
+
" <td>NaN</td>\n",
|
| 480 |
+
" <td>NaN</td>\n",
|
| 481 |
+
" <td>NaN</td>\n",
|
| 482 |
+
" <td>NaN</td>\n",
|
| 483 |
+
" </tr>\n",
|
| 484 |
+
" <tr>\n",
|
| 485 |
+
" <th>2</th>\n",
|
| 486 |
+
" <td>tag_XLRlqy</td>\n",
|
| 487 |
+
" <td>Market Sector</td>\n",
|
| 488 |
+
" <td>market_sector</td>\n",
|
| 489 |
+
" <td>current</td>\n",
|
| 490 |
+
" <td>NaN</td>\n",
|
| 491 |
+
" <td>security</td>\n",
|
| 492 |
+
" <td>string</td>\n",
|
| 493 |
+
" <td>NaN</td>\n",
|
| 494 |
+
" <td>NaN</td>\n",
|
| 495 |
+
" <td>NaN</td>\n",
|
| 496 |
+
" <td>NaN</td>\n",
|
| 497 |
+
" </tr>\n",
|
| 498 |
+
" <tr>\n",
|
| 499 |
+
" <th>3</th>\n",
|
| 500 |
+
" <td>tag_2gBA8y</td>\n",
|
| 501 |
+
" <td>Market Category</td>\n",
|
| 502 |
+
" <td>market_category</td>\n",
|
| 503 |
+
" <td>current</td>\n",
|
| 504 |
+
" <td>NaN</td>\n",
|
| 505 |
+
" <td>security</td>\n",
|
| 506 |
+
" <td>string</td>\n",
|
| 507 |
+
" <td>NaN</td>\n",
|
| 508 |
+
" <td>NaN</td>\n",
|
| 509 |
+
" <td>NaN</td>\n",
|
| 510 |
+
" <td>NaN</td>\n",
|
| 511 |
+
" </tr>\n",
|
| 512 |
+
" <tr>\n",
|
| 513 |
+
" <th>4</th>\n",
|
| 514 |
+
" <td>tag_DzonXe</td>\n",
|
| 515 |
+
" <td>Marketing Expense</td>\n",
|
| 516 |
+
" <td>marketingexpense</td>\n",
|
| 517 |
+
" <td>income_statement</td>\n",
|
| 518 |
+
" <td>industrial</td>\n",
|
| 519 |
+
" <td>income_statement_metric</td>\n",
|
| 520 |
+
" <td>usd</td>\n",
|
| 521 |
+
" <td>totaloperatingexpenses</td>\n",
|
| 522 |
+
" <td>9.0</td>\n",
|
| 523 |
+
" <td>+</td>\n",
|
| 524 |
+
" <td>debit</td>\n",
|
| 525 |
+
" </tr>\n",
|
| 526 |
+
" <tr>\n",
|
| 527 |
+
" <th>...</th>\n",
|
| 528 |
+
" <td>...</td>\n",
|
| 529 |
+
" <td>...</td>\n",
|
| 530 |
+
" <td>...</td>\n",
|
| 531 |
+
" <td>...</td>\n",
|
| 532 |
+
" <td>...</td>\n",
|
| 533 |
+
" <td>...</td>\n",
|
| 534 |
+
" <td>...</td>\n",
|
| 535 |
+
" <td>...</td>\n",
|
| 536 |
+
" <td>...</td>\n",
|
| 537 |
+
" <td>...</td>\n",
|
| 538 |
+
" <td>...</td>\n",
|
| 539 |
+
" </tr>\n",
|
| 540 |
+
" <tr>\n",
|
| 541 |
+
" <th>95</th>\n",
|
| 542 |
+
" <td>tag_nzJAmX</td>\n",
|
| 543 |
+
" <td>Total Long-Term Debt</td>\n",
|
| 544 |
+
" <td>ltdebtandcapleases</td>\n",
|
| 545 |
+
" <td>calculations</td>\n",
|
| 546 |
+
" <td>financial</td>\n",
|
| 547 |
+
" <td>metric</td>\n",
|
| 548 |
+
" <td>usd</td>\n",
|
| 549 |
+
" <td>NaN</td>\n",
|
| 550 |
+
" <td>NaN</td>\n",
|
| 551 |
+
" <td>NaN</td>\n",
|
| 552 |
+
" <td>NaN</td>\n",
|
| 553 |
+
" </tr>\n",
|
| 554 |
+
" <tr>\n",
|
| 555 |
+
" <th>96</th>\n",
|
| 556 |
+
" <td>tag_9XaL5g</td>\n",
|
| 557 |
+
" <td>Other Net Changes in Cash</td>\n",
|
| 558 |
+
" <td>othernetchangesincash</td>\n",
|
| 559 |
+
" <td>cash_flow_statement</td>\n",
|
| 560 |
+
" <td>industrial</td>\n",
|
| 561 |
+
" <td>cash_flow_statement_metric</td>\n",
|
| 562 |
+
" <td>usd</td>\n",
|
| 563 |
+
" <td>netchangeincash</td>\n",
|
| 564 |
+
" <td>33.0</td>\n",
|
| 565 |
+
" <td>+</td>\n",
|
| 566 |
+
" <td>debit</td>\n",
|
| 567 |
+
" </tr>\n",
|
| 568 |
+
" <tr>\n",
|
| 569 |
+
" <th>97</th>\n",
|
| 570 |
+
" <td>tag_5X7p6z</td>\n",
|
| 571 |
+
" <td>Other Net Changes in Cash</td>\n",
|
| 572 |
+
" <td>othernetchangesincash</td>\n",
|
| 573 |
+
" <td>cash_flow_statement</td>\n",
|
| 574 |
+
" <td>financial</td>\n",
|
| 575 |
+
" <td>cash_flow_statement_metric</td>\n",
|
| 576 |
+
" <td>usd</td>\n",
|
| 577 |
+
" <td>netchangeincash</td>\n",
|
| 578 |
+
" <td>37.0</td>\n",
|
| 579 |
+
" <td>+</td>\n",
|
| 580 |
+
" <td>debit</td>\n",
|
| 581 |
+
" </tr>\n",
|
| 582 |
+
" <tr>\n",
|
| 583 |
+
" <th>98</th>\n",
|
| 584 |
+
" <td>tag_qzEwng</td>\n",
|
| 585 |
+
" <td>Changes in Operating Assets and Liabilities, net</td>\n",
|
| 586 |
+
" <td>increasedecreaseinoperatingcapital</td>\n",
|
| 587 |
+
" <td>cash_flow_statement</td>\n",
|
| 588 |
+
" <td>financial</td>\n",
|
| 589 |
+
" <td>cash_flow_statement_metric</td>\n",
|
| 590 |
+
" <td>usd</td>\n",
|
| 591 |
+
" <td>netcashfromcontinuingoperatingactivities</td>\n",
|
| 592 |
+
" <td>8.0</td>\n",
|
| 593 |
+
" <td>+</td>\n",
|
| 594 |
+
" <td>debit</td>\n",
|
| 595 |
+
" </tr>\n",
|
| 596 |
+
" <tr>\n",
|
| 597 |
+
" <th>99</th>\n",
|
| 598 |
+
" <td>tag_pgVB2g</td>\n",
|
| 599 |
+
" <td>Changes in Operating Assets and Liabilities, net</td>\n",
|
| 600 |
+
" <td>increasedecreaseinoperatingcapital</td>\n",
|
| 601 |
+
" <td>cash_flow_statement</td>\n",
|
| 602 |
+
" <td>industrial</td>\n",
|
| 603 |
+
" <td>cash_flow_statement_metric</td>\n",
|
| 604 |
+
" <td>usd</td>\n",
|
| 605 |
+
" <td>netcashfromcontinuingoperatingactivities</td>\n",
|
| 606 |
+
" <td>7.0</td>\n",
|
| 607 |
+
" <td>+</td>\n",
|
| 608 |
+
" <td>debit</td>\n",
|
| 609 |
+
" </tr>\n",
|
| 610 |
+
" </tbody>\n",
|
| 611 |
+
"</table>\n",
|
| 612 |
+
"<p>100 rows × 11 columns</p>\n",
|
| 613 |
+
"</div>"
|
| 614 |
+
],
|
| 615 |
+
"text/plain": [
|
| 616 |
+
" id name \\\n",
|
| 617 |
+
"0 tag_BgkbWy Market Capitalization \n",
|
| 618 |
+
"1 tag_kylOqz Market Capitalization \n",
|
| 619 |
+
"2 tag_XLRlqy Market Sector \n",
|
| 620 |
+
"3 tag_2gBA8y Market Category \n",
|
| 621 |
+
"4 tag_DzonXe Marketing Expense \n",
|
| 622 |
+
".. ... ... \n",
|
| 623 |
+
"95 tag_nzJAmX Total Long-Term Debt \n",
|
| 624 |
+
"96 tag_9XaL5g Other Net Changes in Cash \n",
|
| 625 |
+
"97 tag_5X7p6z Other Net Changes in Cash \n",
|
| 626 |
+
"98 tag_qzEwng Changes in Operating Assets and Liabilities, net \n",
|
| 627 |
+
"99 tag_pgVB2g Changes in Operating Assets and Liabilities, net \n",
|
| 628 |
+
"\n",
|
| 629 |
+
" tag statement_code statement_type \\\n",
|
| 630 |
+
"0 marketcap calculations industrial \n",
|
| 631 |
+
"1 marketcap calculations financial \n",
|
| 632 |
+
"2 market_sector current NaN \n",
|
| 633 |
+
"3 market_category current NaN \n",
|
| 634 |
+
"4 marketingexpense income_statement industrial \n",
|
| 635 |
+
".. ... ... ... \n",
|
| 636 |
+
"95 ltdebtandcapleases calculations financial \n",
|
| 637 |
+
"96 othernetchangesincash cash_flow_statement industrial \n",
|
| 638 |
+
"97 othernetchangesincash cash_flow_statement financial \n",
|
| 639 |
+
"98 increasedecreaseinoperatingcapital cash_flow_statement financial \n",
|
| 640 |
+
"99 increasedecreaseinoperatingcapital cash_flow_statement industrial \n",
|
| 641 |
+
"\n",
|
| 642 |
+
" type unit \\\n",
|
| 643 |
+
"0 valuation usd \n",
|
| 644 |
+
"1 valuation usd \n",
|
| 645 |
+
"2 security string \n",
|
| 646 |
+
"3 security string \n",
|
| 647 |
+
"4 income_statement_metric usd \n",
|
| 648 |
+
".. ... ... \n",
|
| 649 |
+
"95 metric usd \n",
|
| 650 |
+
"96 cash_flow_statement_metric usd \n",
|
| 651 |
+
"97 cash_flow_statement_metric usd \n",
|
| 652 |
+
"98 cash_flow_statement_metric usd \n",
|
| 653 |
+
"99 cash_flow_statement_metric usd \n",
|
| 654 |
+
"\n",
|
| 655 |
+
" parent_name sequence factor transaction \n",
|
| 656 |
+
"0 NaN NaN NaN NaN \n",
|
| 657 |
+
"1 NaN NaN NaN NaN \n",
|
| 658 |
+
"2 NaN NaN NaN NaN \n",
|
| 659 |
+
"3 NaN NaN NaN NaN \n",
|
| 660 |
+
"4 totaloperatingexpenses 9.0 + debit \n",
|
| 661 |
+
".. ... ... ... ... \n",
|
| 662 |
+
"95 NaN NaN NaN NaN \n",
|
| 663 |
+
"96 netchangeincash 33.0 + debit \n",
|
| 664 |
+
"97 netchangeincash 37.0 + debit \n",
|
| 665 |
+
"98 netcashfromcontinuingoperatingactivities 8.0 + debit \n",
|
| 666 |
+
"99 netcashfromcontinuingoperatingactivities 7.0 + debit \n",
|
| 667 |
+
"\n",
|
| 668 |
+
"[100 rows x 11 columns]"
|
| 669 |
+
]
|
| 670 |
+
},
|
| 671 |
+
"execution_count": 10,
|
| 672 |
+
"metadata": {},
|
| 673 |
+
"output_type": "execute_result"
|
| 674 |
+
}
|
| 675 |
+
],
|
| 676 |
+
"source": [
|
| 677 |
+
"(obb.equity.fundamental.search_attributes(\"marketcap\", provider=\"intrinio\").to_df())"
|
| 678 |
+
]
|
| 679 |
+
},
|
| 680 |
+
{
|
| 681 |
+
"cell_type": "markdown",
|
| 682 |
+
"metadata": {},
|
| 683 |
+
"source": [
|
| 684 |
+
"The `tag` is what we need, in this case it is what we searched for."
|
| 685 |
+
]
|
| 686 |
+
},
|
| 687 |
+
{
|
| 688 |
+
"cell_type": "code",
|
| 689 |
+
"execution_count": 20,
|
| 690 |
+
"metadata": {},
|
| 691 |
+
"outputs": [
|
| 692 |
+
{
|
| 693 |
+
"data": {
|
| 694 |
+
"text/html": [
|
| 695 |
+
"<div>\n",
|
| 696 |
+
"<style scoped>\n",
|
| 697 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 698 |
+
" vertical-align: middle;\n",
|
| 699 |
+
" }\n",
|
| 700 |
+
"\n",
|
| 701 |
+
" .dataframe tbody tr th {\n",
|
| 702 |
+
" vertical-align: top;\n",
|
| 703 |
+
" }\n",
|
| 704 |
+
"\n",
|
| 705 |
+
" .dataframe thead th {\n",
|
| 706 |
+
" text-align: right;\n",
|
| 707 |
+
" }\n",
|
| 708 |
+
"</style>\n",
|
| 709 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 710 |
+
" <thead>\n",
|
| 711 |
+
" <tr style=\"text-align: right;\">\n",
|
| 712 |
+
" <th></th>\n",
|
| 713 |
+
" <th>symbol</th>\n",
|
| 714 |
+
" <th>tag</th>\n",
|
| 715 |
+
" <th>value</th>\n",
|
| 716 |
+
" </tr>\n",
|
| 717 |
+
" <tr>\n",
|
| 718 |
+
" <th>date</th>\n",
|
| 719 |
+
" <th></th>\n",
|
| 720 |
+
" <th></th>\n",
|
| 721 |
+
" <th></th>\n",
|
| 722 |
+
" </tr>\n",
|
| 723 |
+
" </thead>\n",
|
| 724 |
+
" <tbody>\n",
|
| 725 |
+
" <tr>\n",
|
| 726 |
+
" <th>2023-09-30</th>\n",
|
| 727 |
+
" <td>TGT</td>\n",
|
| 728 |
+
" <td>marketcap</td>\n",
|
| 729 |
+
" <td>4.951153e+10</td>\n",
|
| 730 |
+
" </tr>\n",
|
| 731 |
+
" <tr>\n",
|
| 732 |
+
" <th>2023-12-31</th>\n",
|
| 733 |
+
" <td>TGT</td>\n",
|
| 734 |
+
" <td>marketcap</td>\n",
|
| 735 |
+
" <td>6.443403e+10</td>\n",
|
| 736 |
+
" </tr>\n",
|
| 737 |
+
" <tr>\n",
|
| 738 |
+
" <th>2024-03-31</th>\n",
|
| 739 |
+
" <td>TGT</td>\n",
|
| 740 |
+
" <td>marketcap</td>\n",
|
| 741 |
+
" <td>8.082004e+10</td>\n",
|
| 742 |
+
" </tr>\n",
|
| 743 |
+
" <tr>\n",
|
| 744 |
+
" <th>2024-06-30</th>\n",
|
| 745 |
+
" <td>TGT</td>\n",
|
| 746 |
+
" <td>marketcap</td>\n",
|
| 747 |
+
" <td>6.814283e+10</td>\n",
|
| 748 |
+
" </tr>\n",
|
| 749 |
+
" <tr>\n",
|
| 750 |
+
" <th>2024-08-22</th>\n",
|
| 751 |
+
" <td>TGT</td>\n",
|
| 752 |
+
" <td>marketcap</td>\n",
|
| 753 |
+
" <td>7.387608e+10</td>\n",
|
| 754 |
+
" </tr>\n",
|
| 755 |
+
" </tbody>\n",
|
| 756 |
+
"</table>\n",
|
| 757 |
+
"</div>"
|
| 758 |
+
],
|
| 759 |
+
"text/plain": [
|
| 760 |
+
" symbol tag value\n",
|
| 761 |
+
"date \n",
|
| 762 |
+
"2023-09-30 TGT marketcap 4.951153e+10\n",
|
| 763 |
+
"2023-12-31 TGT marketcap 6.443403e+10\n",
|
| 764 |
+
"2024-03-31 TGT marketcap 8.082004e+10\n",
|
| 765 |
+
"2024-06-30 TGT marketcap 6.814283e+10\n",
|
| 766 |
+
"2024-08-22 TGT marketcap 7.387608e+10"
|
| 767 |
+
]
|
| 768 |
+
},
|
| 769 |
+
"execution_count": 20,
|
| 770 |
+
"metadata": {},
|
| 771 |
+
"output_type": "execute_result"
|
| 772 |
+
}
|
| 773 |
+
],
|
| 774 |
+
"source": [
|
| 775 |
+
"marketcap = obb.equity.fundamental.historical_attributes(\n",
|
| 776 |
+
" symbol=\"TGT\", tag=\"marketcap\", frequency=\"quarterly\", provider=\"intrinio\"\n",
|
| 777 |
+
").to_df()\n",
|
| 778 |
+
"\n",
|
| 779 |
+
"marketcap.tail(5)"
|
| 780 |
+
]
|
| 781 |
+
},
|
| 782 |
+
{
|
| 783 |
+
"cell_type": "markdown",
|
| 784 |
+
"metadata": {},
|
| 785 |
+
"source": [
|
| 786 |
+
"Doing some quick math, and ignoring the most recent value, we can see that the market cap of Target was down nearly a quarter over the last four reporting periods."
|
| 787 |
+
]
|
| 788 |
+
},
|
| 789 |
+
{
|
| 790 |
+
"cell_type": "code",
|
| 791 |
+
"execution_count": 40,
|
| 792 |
+
"metadata": {},
|
| 793 |
+
"outputs": [
|
| 794 |
+
{
|
| 795 |
+
"data": {
|
| 796 |
+
"text/plain": [
|
| 797 |
+
"-0.243767327909974"
|
| 798 |
+
]
|
| 799 |
+
},
|
| 800 |
+
"execution_count": 40,
|
| 801 |
+
"metadata": {},
|
| 802 |
+
"output_type": "execute_result"
|
| 803 |
+
}
|
| 804 |
+
],
|
| 805 |
+
"source": [
|
| 806 |
+
"marketcap.index = marketcap.index.astype(str)\n",
|
| 807 |
+
"(\n",
|
| 808 |
+
" (marketcap.loc[\"2023-09-30\"].value - marketcap.loc[\"2022-12-31\"].value)\n",
|
| 809 |
+
" / marketcap.loc[\"2022-12-31\"].value\n",
|
| 810 |
+
")"
|
| 811 |
+
]
|
| 812 |
+
},
|
| 813 |
+
{
|
| 814 |
+
"cell_type": "markdown",
|
| 815 |
+
"metadata": {},
|
| 816 |
+
"source": [
|
| 817 |
+
"Historial market cap is also available as a daily metric from FMP. We can resample it as quarterly to approximate the same results."
|
| 818 |
+
]
|
| 819 |
+
},
|
| 820 |
+
{
|
| 821 |
+
"cell_type": "code",
|
| 822 |
+
"execution_count": 43,
|
| 823 |
+
"metadata": {},
|
| 824 |
+
"outputs": [
|
| 825 |
+
{
|
| 826 |
+
"data": {
|
| 827 |
+
"text/html": [
|
| 828 |
+
"<div>\n",
|
| 829 |
+
"<style scoped>\n",
|
| 830 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 831 |
+
" vertical-align: middle;\n",
|
| 832 |
+
" }\n",
|
| 833 |
+
"\n",
|
| 834 |
+
" .dataframe tbody tr th {\n",
|
| 835 |
+
" vertical-align: top;\n",
|
| 836 |
+
" }\n",
|
| 837 |
+
"\n",
|
| 838 |
+
" .dataframe thead th {\n",
|
| 839 |
+
" text-align: right;\n",
|
| 840 |
+
" }\n",
|
| 841 |
+
"</style>\n",
|
| 842 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 843 |
+
" <thead>\n",
|
| 844 |
+
" <tr style=\"text-align: right;\">\n",
|
| 845 |
+
" <th></th>\n",
|
| 846 |
+
" <th>market_cap</th>\n",
|
| 847 |
+
" </tr>\n",
|
| 848 |
+
" <tr>\n",
|
| 849 |
+
" <th>date</th>\n",
|
| 850 |
+
" <th></th>\n",
|
| 851 |
+
" </tr>\n",
|
| 852 |
+
" </thead>\n",
|
| 853 |
+
" <tbody>\n",
|
| 854 |
+
" <tr>\n",
|
| 855 |
+
" <th>2022-03-31</th>\n",
|
| 856 |
+
" <td>98470080000</td>\n",
|
| 857 |
+
" </tr>\n",
|
| 858 |
+
" <tr>\n",
|
| 859 |
+
" <th>2022-06-30</th>\n",
|
| 860 |
+
" <td>65177644999</td>\n",
|
| 861 |
+
" </tr>\n",
|
| 862 |
+
" <tr>\n",
|
| 863 |
+
" <th>2022-09-30</th>\n",
|
| 864 |
+
" <td>68303916999</td>\n",
|
| 865 |
+
" </tr>\n",
|
| 866 |
+
" <tr>\n",
|
| 867 |
+
" <th>2022-12-31</th>\n",
|
| 868 |
+
" <td>68603112000</td>\n",
|
| 869 |
+
" </tr>\n",
|
| 870 |
+
" <tr>\n",
|
| 871 |
+
" <th>2023-03-31</th>\n",
|
| 872 |
+
" <td>76338867000</td>\n",
|
| 873 |
+
" </tr>\n",
|
| 874 |
+
" <tr>\n",
|
| 875 |
+
" <th>2023-06-30</th>\n",
|
| 876 |
+
" <td>60885040000</td>\n",
|
| 877 |
+
" </tr>\n",
|
| 878 |
+
" <tr>\n",
|
| 879 |
+
" <th>2023-09-30</th>\n",
|
| 880 |
+
" <td>51039112000</td>\n",
|
| 881 |
+
" </tr>\n",
|
| 882 |
+
" <tr>\n",
|
| 883 |
+
" <th>2023-12-31</th>\n",
|
| 884 |
+
" <td>65755313999</td>\n",
|
| 885 |
+
" </tr>\n",
|
| 886 |
+
" <tr>\n",
|
| 887 |
+
" <th>2024-03-31</th>\n",
|
| 888 |
+
" <td>81906462000</td>\n",
|
| 889 |
+
" </tr>\n",
|
| 890 |
+
" <tr>\n",
|
| 891 |
+
" <th>2024-06-30</th>\n",
|
| 892 |
+
" <td>68424088000</td>\n",
|
| 893 |
+
" </tr>\n",
|
| 894 |
+
" <tr>\n",
|
| 895 |
+
" <th>2024-09-30</th>\n",
|
| 896 |
+
" <td>73653125000</td>\n",
|
| 897 |
+
" </tr>\n",
|
| 898 |
+
" </tbody>\n",
|
| 899 |
+
"</table>\n",
|
| 900 |
+
"</div>"
|
| 901 |
+
],
|
| 902 |
+
"text/plain": [
|
| 903 |
+
" market_cap\n",
|
| 904 |
+
"date \n",
|
| 905 |
+
"2022-03-31 98470080000\n",
|
| 906 |
+
"2022-06-30 65177644999\n",
|
| 907 |
+
"2022-09-30 68303916999\n",
|
| 908 |
+
"2022-12-31 68603112000\n",
|
| 909 |
+
"2023-03-31 76338867000\n",
|
| 910 |
+
"2023-06-30 60885040000\n",
|
| 911 |
+
"2023-09-30 51039112000\n",
|
| 912 |
+
"2023-12-31 65755313999\n",
|
| 913 |
+
"2024-03-31 81906462000\n",
|
| 914 |
+
"2024-06-30 68424088000\n",
|
| 915 |
+
"2024-09-30 73653125000"
|
| 916 |
+
]
|
| 917 |
+
},
|
| 918 |
+
"metadata": {},
|
| 919 |
+
"output_type": "display_data"
|
| 920 |
+
},
|
| 921 |
+
{
|
| 922 |
+
"data": {
|
| 923 |
+
"text/plain": [
|
| 924 |
+
"market_cap -0.256023\n",
|
| 925 |
+
"dtype: float64"
|
| 926 |
+
]
|
| 927 |
+
},
|
| 928 |
+
"execution_count": 43,
|
| 929 |
+
"metadata": {},
|
| 930 |
+
"output_type": "execute_result"
|
| 931 |
+
}
|
| 932 |
+
],
|
| 933 |
+
"source": [
|
| 934 |
+
"df = obb.equity.historical_market_cap(\n",
|
| 935 |
+
" \"TGT\", start_date=\"2022-01-01\", provider=\"fmp\"\n",
|
| 936 |
+
").to_df()\n",
|
| 937 |
+
"\n",
|
| 938 |
+
"resampled = df.copy()\n",
|
| 939 |
+
"resampled.index = pd.to_datetime(resampled.index)\n",
|
| 940 |
+
"resampled = resampled[[\"market_cap\"]]\n",
|
| 941 |
+
"resampled = resampled.resample(\"QE\").last()\n",
|
| 942 |
+
"resampled.index = resampled.index.astype(str)\n",
|
| 943 |
+
"display(resampled)\n",
|
| 944 |
+
"(\n",
|
| 945 |
+
" (resampled.loc[\"2023-09-30\"] - resampled.loc[\"2022-12-31\"])\n",
|
| 946 |
+
" / resampled.loc[\"2022-12-31\"]\n",
|
| 947 |
+
")"
|
| 948 |
+
]
|
| 949 |
+
},
|
| 950 |
+
{
|
| 951 |
+
"cell_type": "markdown",
|
| 952 |
+
"metadata": {},
|
| 953 |
+
"source": [
|
| 954 |
+
"## Ratios and Other Metrics\n",
|
| 955 |
+
"\n",
|
| 956 |
+
"Other valuation functions are derivatives of the financial statements, but the data provider does the math. Values are typically ratios between line items, on a per-share basis, or as a percent growth.\n",
|
| 957 |
+
"\n",
|
| 958 |
+
"This data set is where you can find EPS, FCF, P/B, EBIT, quick ratio, etc.\n",
|
| 959 |
+
"\n",
|
| 960 |
+
"### Quick Ratio\n",
|
| 961 |
+
"\n",
|
| 962 |
+
"Target's quick ratio could be one reason why its share price is losing traction against the market. Its ability to pay current obligations is not optimistically reflected in a 0.27 score, approximately 50% below the historical median."
|
| 963 |
+
]
|
| 964 |
+
},
|
| 965 |
+
{
|
| 966 |
+
"cell_type": "code",
|
| 967 |
+
"execution_count": 56,
|
| 968 |
+
"metadata": {},
|
| 969 |
+
"outputs": [
|
| 970 |
+
{
|
| 971 |
+
"data": {
|
| 972 |
+
"text/plain": [
|
| 973 |
+
"'Current Quick Ratio: 0.8998'"
|
| 974 |
+
]
|
| 975 |
+
},
|
| 976 |
+
"metadata": {},
|
| 977 |
+
"output_type": "display_data"
|
| 978 |
+
},
|
| 979 |
+
{
|
| 980 |
+
"data": {
|
| 981 |
+
"text/plain": [
|
| 982 |
+
"'Median Quick Ratio: 0.6047'"
|
| 983 |
+
]
|
| 984 |
+
},
|
| 985 |
+
"metadata": {},
|
| 986 |
+
"output_type": "display_data"
|
| 987 |
+
}
|
| 988 |
+
],
|
| 989 |
+
"source": [
|
| 990 |
+
"ratios = obb.equity.fundamental.ratios(\"TGT\", limit=50, provider=\"fmp\").to_df()\n",
|
| 991 |
+
"\n",
|
| 992 |
+
"display(f\"Current Quick Ratio: {round(ratios['quick_ratio'].iloc[-1], 4)}\")\n",
|
| 993 |
+
"display(f\"Median Quick Ratio: {round(ratios['quick_ratio'].median(), 4)}\")"
|
| 994 |
+
]
|
| 995 |
+
},
|
| 996 |
+
{
|
| 997 |
+
"cell_type": "markdown",
|
| 998 |
+
"metadata": {},
|
| 999 |
+
"source": [
|
| 1000 |
+
"### Free Cash Flow Yield\n",
|
| 1001 |
+
"\n",
|
| 1002 |
+
"The `metrics` endpoint, with the `openbb-fmp` data extension, has a field for free cash flow yield. It is calculated by taking the free cash flow per share divided by the current share price. We could arrive at this answer by writing some code, but these types of endpoints do the work so we don't have to. This is part of the value-add that API data distributors provide, they allow you to get straight to work with data.\n",
|
| 1003 |
+
"\n",
|
| 1004 |
+
"We'll use this endpoint to extract the data, and compare with some of Target's competition over the last ten years."
|
| 1005 |
+
]
|
| 1006 |
+
},
|
| 1007 |
+
{
|
| 1008 |
+
"cell_type": "code",
|
| 1009 |
+
"execution_count": 57,
|
| 1010 |
+
"metadata": {},
|
| 1011 |
+
"outputs": [
|
| 1012 |
+
{
|
| 1013 |
+
"data": {
|
| 1014 |
+
"text/html": [
|
| 1015 |
+
"<div>\n",
|
| 1016 |
+
"<style scoped>\n",
|
| 1017 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1018 |
+
" vertical-align: middle;\n",
|
| 1019 |
+
" }\n",
|
| 1020 |
+
"\n",
|
| 1021 |
+
" .dataframe tbody tr th {\n",
|
| 1022 |
+
" vertical-align: top;\n",
|
| 1023 |
+
" }\n",
|
| 1024 |
+
"\n",
|
| 1025 |
+
" .dataframe thead th {\n",
|
| 1026 |
+
" text-align: right;\n",
|
| 1027 |
+
" }\n",
|
| 1028 |
+
"</style>\n",
|
| 1029 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1030 |
+
" <thead>\n",
|
| 1031 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1032 |
+
" <th>calendar_year</th>\n",
|
| 1033 |
+
" <th>2023</th>\n",
|
| 1034 |
+
" <th>2022</th>\n",
|
| 1035 |
+
" <th>2021</th>\n",
|
| 1036 |
+
" <th>2020</th>\n",
|
| 1037 |
+
" <th>2019</th>\n",
|
| 1038 |
+
" <th>2018</th>\n",
|
| 1039 |
+
" <th>2017</th>\n",
|
| 1040 |
+
" <th>2016</th>\n",
|
| 1041 |
+
" <th>2015</th>\n",
|
| 1042 |
+
" <th>2014</th>\n",
|
| 1043 |
+
" </tr>\n",
|
| 1044 |
+
" </thead>\n",
|
| 1045 |
+
" <tbody>\n",
|
| 1046 |
+
" <tr>\n",
|
| 1047 |
+
" <th>COST</th>\n",
|
| 1048 |
+
" <td>0.027922</td>\n",
|
| 1049 |
+
" <td>0.014860</td>\n",
|
| 1050 |
+
" <td>0.026582</td>\n",
|
| 1051 |
+
" <td>0.039351</td>\n",
|
| 1052 |
+
" <td>0.025906</td>\n",
|
| 1053 |
+
" <td>0.027438</td>\n",
|
| 1054 |
+
" <td>0.060884</td>\n",
|
| 1055 |
+
" <td>0.008941</td>\n",
|
| 1056 |
+
" <td>0.030741</td>\n",
|
| 1057 |
+
" <td>0.037483</td>\n",
|
| 1058 |
+
" </tr>\n",
|
| 1059 |
+
" <tr>\n",
|
| 1060 |
+
" <th>BJ</th>\n",
|
| 1061 |
+
" <td>0.029338</td>\n",
|
| 1062 |
+
" <td>0.044709</td>\n",
|
| 1063 |
+
" <td>0.067213</td>\n",
|
| 1064 |
+
" <td>0.113551</td>\n",
|
| 1065 |
+
" <td>0.056631</td>\n",
|
| 1066 |
+
" <td>0.091107</td>\n",
|
| 1067 |
+
" <td>0.026186</td>\n",
|
| 1068 |
+
" <td>0.065871</td>\n",
|
| 1069 |
+
" <td>0.016947</td>\n",
|
| 1070 |
+
" <td>NaN</td>\n",
|
| 1071 |
+
" </tr>\n",
|
| 1072 |
+
" <tr>\n",
|
| 1073 |
+
" <th>DLTR</th>\n",
|
| 1074 |
+
" <td>0.018948</td>\n",
|
| 1075 |
+
" <td>0.010756</td>\n",
|
| 1076 |
+
" <td>0.013957</td>\n",
|
| 1077 |
+
" <td>0.075627</td>\n",
|
| 1078 |
+
" <td>0.040338</td>\n",
|
| 1079 |
+
" <td>0.041252</td>\n",
|
| 1080 |
+
" <td>0.034069</td>\n",
|
| 1081 |
+
" <td>0.063465</td>\n",
|
| 1082 |
+
" <td>0.016602</td>\n",
|
| 1083 |
+
" <td>0.041047</td>\n",
|
| 1084 |
+
" </tr>\n",
|
| 1085 |
+
" <tr>\n",
|
| 1086 |
+
" <th>DG</th>\n",
|
| 1087 |
+
" <td>0.023149</td>\n",
|
| 1088 |
+
" <td>0.008256</td>\n",
|
| 1089 |
+
" <td>0.037507</td>\n",
|
| 1090 |
+
" <td>0.058973</td>\n",
|
| 1091 |
+
" <td>0.036922</td>\n",
|
| 1092 |
+
" <td>0.046197</td>\n",
|
| 1093 |
+
" <td>0.042609</td>\n",
|
| 1094 |
+
" <td>0.050776</td>\n",
|
| 1095 |
+
" <td>0.039524</td>\n",
|
| 1096 |
+
" <td>0.046052</td>\n",
|
| 1097 |
+
" </tr>\n",
|
| 1098 |
+
" <tr>\n",
|
| 1099 |
+
" <th>WMT</th>\n",
|
| 1100 |
+
" <td>0.030577</td>\n",
|
| 1101 |
+
" <td>0.028374</td>\n",
|
| 1102 |
+
" <td>0.065467</td>\n",
|
| 1103 |
+
" <td>0.044595</td>\n",
|
| 1104 |
+
" <td>0.062030</td>\n",
|
| 1105 |
+
" <td>0.057280</td>\n",
|
| 1106 |
+
" <td>0.101023</td>\n",
|
| 1107 |
+
" <td>0.073506</td>\n",
|
| 1108 |
+
" <td>0.059705</td>\n",
|
| 1109 |
+
" <td>NaN</td>\n",
|
| 1110 |
+
" </tr>\n",
|
| 1111 |
+
" <tr>\n",
|
| 1112 |
+
" <th>BIG</th>\n",
|
| 1113 |
+
" <td>-1.856996</td>\n",
|
| 1114 |
+
" <td>-0.624151</td>\n",
|
| 1115 |
+
" <td>0.025262</td>\n",
|
| 1116 |
+
" <td>0.115757</td>\n",
|
| 1117 |
+
" <td>0.069464</td>\n",
|
| 1118 |
+
" <td>-0.111853</td>\n",
|
| 1119 |
+
" <td>0.037219</td>\n",
|
| 1120 |
+
" <td>0.100721</td>\n",
|
| 1121 |
+
" <td>0.110443</td>\n",
|
| 1122 |
+
" <td>0.089253</td>\n",
|
| 1123 |
+
" </tr>\n",
|
| 1124 |
+
" <tr>\n",
|
| 1125 |
+
" <th>M</th>\n",
|
| 1126 |
+
" <td>0.061077</td>\n",
|
| 1127 |
+
" <td>0.050473</td>\n",
|
| 1128 |
+
" <td>0.270980</td>\n",
|
| 1129 |
+
" <td>0.039111</td>\n",
|
| 1130 |
+
" <td>0.091301</td>\n",
|
| 1131 |
+
" <td>0.101426</td>\n",
|
| 1132 |
+
" <td>0.155761</td>\n",
|
| 1133 |
+
" <td>0.098993</td>\n",
|
| 1134 |
+
" <td>0.065634</td>\n",
|
| 1135 |
+
" <td>0.072322</td>\n",
|
| 1136 |
+
" </tr>\n",
|
| 1137 |
+
" <tr>\n",
|
| 1138 |
+
" <th>KSS</th>\n",
|
| 1139 |
+
" <td>0.203512</td>\n",
|
| 1140 |
+
" <td>-0.143961</td>\n",
|
| 1141 |
+
" <td>0.189677</td>\n",
|
| 1142 |
+
" <td>0.147968</td>\n",
|
| 1143 |
+
" <td>0.119492</td>\n",
|
| 1144 |
+
" <td>0.139799</td>\n",
|
| 1145 |
+
" <td>0.096137</td>\n",
|
| 1146 |
+
" <td>0.198790</td>\n",
|
| 1147 |
+
" <td>0.081652</td>\n",
|
| 1148 |
+
" <td>0.110697</td>\n",
|
| 1149 |
+
" </tr>\n",
|
| 1150 |
+
" <tr>\n",
|
| 1151 |
+
" <th>TJX</th>\n",
|
| 1152 |
+
" <td>0.027513</td>\n",
|
| 1153 |
+
" <td>0.023498</td>\n",
|
| 1154 |
+
" <td>0.051975</td>\n",
|
| 1155 |
+
" <td>0.039865</td>\n",
|
| 1156 |
+
" <td>0.049788</td>\n",
|
| 1157 |
+
" <td>0.039930</td>\n",
|
| 1158 |
+
" <td>0.053697</td>\n",
|
| 1159 |
+
" <td>0.043328</td>\n",
|
| 1160 |
+
" <td>0.046442</td>\n",
|
| 1161 |
+
" <td>NaN</td>\n",
|
| 1162 |
+
" </tr>\n",
|
| 1163 |
+
" </tbody>\n",
|
| 1164 |
+
"</table>\n",
|
| 1165 |
+
"</div>"
|
| 1166 |
+
],
|
| 1167 |
+
"text/plain": [
|
| 1168 |
+
"calendar_year 2023 2022 2021 2020 2019 2018 \\\n",
|
| 1169 |
+
"COST 0.027922 0.014860 0.026582 0.039351 0.025906 0.027438 \n",
|
| 1170 |
+
"BJ 0.029338 0.044709 0.067213 0.113551 0.056631 0.091107 \n",
|
| 1171 |
+
"DLTR 0.018948 0.010756 0.013957 0.075627 0.040338 0.041252 \n",
|
| 1172 |
+
"DG 0.023149 0.008256 0.037507 0.058973 0.036922 0.046197 \n",
|
| 1173 |
+
"WMT 0.030577 0.028374 0.065467 0.044595 0.062030 0.057280 \n",
|
| 1174 |
+
"BIG -1.856996 -0.624151 0.025262 0.115757 0.069464 -0.111853 \n",
|
| 1175 |
+
"M 0.061077 0.050473 0.270980 0.039111 0.091301 0.101426 \n",
|
| 1176 |
+
"KSS 0.203512 -0.143961 0.189677 0.147968 0.119492 0.139799 \n",
|
| 1177 |
+
"TJX 0.027513 0.023498 0.051975 0.039865 0.049788 0.039930 \n",
|
| 1178 |
+
"\n",
|
| 1179 |
+
"calendar_year 2017 2016 2015 2014 \n",
|
| 1180 |
+
"COST 0.060884 0.008941 0.030741 0.037483 \n",
|
| 1181 |
+
"BJ 0.026186 0.065871 0.016947 NaN \n",
|
| 1182 |
+
"DLTR 0.034069 0.063465 0.016602 0.041047 \n",
|
| 1183 |
+
"DG 0.042609 0.050776 0.039524 0.046052 \n",
|
| 1184 |
+
"WMT 0.101023 0.073506 0.059705 NaN \n",
|
| 1185 |
+
"BIG 0.037219 0.100721 0.110443 0.089253 \n",
|
| 1186 |
+
"M 0.155761 0.098993 0.065634 0.072322 \n",
|
| 1187 |
+
"KSS 0.096137 0.198790 0.081652 0.110697 \n",
|
| 1188 |
+
"TJX 0.053697 0.043328 0.046442 NaN "
|
| 1189 |
+
]
|
| 1190 |
+
},
|
| 1191 |
+
"execution_count": 57,
|
| 1192 |
+
"metadata": {},
|
| 1193 |
+
"output_type": "execute_result"
|
| 1194 |
+
}
|
| 1195 |
+
],
|
| 1196 |
+
"source": [
|
| 1197 |
+
"# List of other retail chains\n",
|
| 1198 |
+
"tickers = [\"COST\", \"BJ\", \"DLTR\", \"DG\", \"WMT\", \"BIG\", \"M\", \"KSS\", \"TJX\"]\n",
|
| 1199 |
+
"\n",
|
| 1200 |
+
"# Create a column for each.\n",
|
| 1201 |
+
"fcf_yield = pd.DataFrame()\n",
|
| 1202 |
+
"for ticker in tickers:\n",
|
| 1203 |
+
" fcf_yield[ticker] = (\n",
|
| 1204 |
+
" obb.equity.fundamental.metrics(\n",
|
| 1205 |
+
" ticker, provider=\"fmp\", period=\"annual\", limit=10\n",
|
| 1206 |
+
" )\n",
|
| 1207 |
+
" .to_df()\n",
|
| 1208 |
+
" .reset_index()\n",
|
| 1209 |
+
" .set_index(\"calendar_year\")\n",
|
| 1210 |
+
" .sort_index(ascending=False)[\"free_cash_flow_yield\"]\n",
|
| 1211 |
+
" )\n",
|
| 1212 |
+
"fcf_yield.transpose()"
|
| 1213 |
+
]
|
| 1214 |
+
},
|
| 1215 |
+
{
|
| 1216 |
+
"cell_type": "markdown",
|
| 1217 |
+
"metadata": {},
|
| 1218 |
+
"source": [
|
| 1219 |
+
"There are more usage examples on our [website](https://docs.openbb.co/platform/user_guides)"
|
| 1220 |
+
]
|
| 1221 |
+
}
|
| 1222 |
+
],
|
| 1223 |
+
"metadata": {
|
| 1224 |
+
"kernelspec": {
|
| 1225 |
+
"display_name": "obb-sdk4",
|
| 1226 |
+
"language": "python",
|
| 1227 |
+
"name": "python3"
|
| 1228 |
+
},
|
| 1229 |
+
"language_info": {
|
| 1230 |
+
"codemirror_mode": {
|
| 1231 |
+
"name": "ipython",
|
| 1232 |
+
"version": 3
|
| 1233 |
+
},
|
| 1234 |
+
"file_extension": ".py",
|
| 1235 |
+
"mimetype": "text/x-python",
|
| 1236 |
+
"name": "python",
|
| 1237 |
+
"nbconvert_exporter": "python",
|
| 1238 |
+
"pygments_lexer": "ipython3",
|
| 1239 |
+
"version": "3.12.4"
|
| 1240 |
+
}
|
| 1241 |
+
},
|
| 1242 |
+
"nbformat": 4,
|
| 1243 |
+
"nbformat_minor": 2
|
| 1244 |
+
}
|
examples/financialStatements.webp
ADDED
|
examples/findSymbols.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/findSymbols.webp
ADDED
|
examples/googleColab.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/googleColab.webp
ADDED
|
examples/impliedEarningsMove.ipynb
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {
|
| 6 |
+
"id": "BzQ2PSUMb1O7"
|
| 7 |
+
},
|
| 8 |
+
"source": [
|
| 9 |
+
"# Calculating the Implied Earnings Move Using Options Prices\n",
|
| 10 |
+
"\n",
|
| 11 |
+
"Earnings day can be a pivotal moment for a company's share price. The confluence of expectations and reality is a tradable event, drawing crowds to the options market. Observing the surrounding action can provide insight into the consensus view on, and general sentiment of, the company.\n",
|
| 12 |
+
"\n",
|
| 13 |
+
"The cost of a straddle - the combined price of an at-the-money call and put - is a common way to gauge the near-term volatility. It's the market's expectation of the price band until expiration. While this includes time value, the isolated price of volatility will generally be higher for the expiry immediately following an earnings release.\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"Have a look at companies that trade weekly options and are reporting a on Thursday. If they report after the close, the price of the one-day straddle at the bell will be the purest sample of information.\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"The cells below will demonstrate how to get the data from free sources, using the OpenBB Platform."
|
| 18 |
+
]
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"cell_type": "code",
|
| 22 |
+
"execution_count": null,
|
| 23 |
+
"metadata": {
|
| 24 |
+
"id": "da3wLFHJaK1n"
|
| 25 |
+
},
|
| 26 |
+
"outputs": [],
|
| 27 |
+
"source": [
|
| 28 |
+
"# If using in Google Colab, install the OpenBB library.\n",
|
| 29 |
+
"\n",
|
| 30 |
+
"#!pip install openbb[\"all\"]\n",
|
| 31 |
+
"\n",
|
| 32 |
+
"# Restart the runtime before the next block"
|
| 33 |
+
]
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"cell_type": "code",
|
| 37 |
+
"execution_count": 7,
|
| 38 |
+
"metadata": {
|
| 39 |
+
"colab": {
|
| 40 |
+
"base_uri": "https://localhost:8080/"
|
| 41 |
+
},
|
| 42 |
+
"id": "7xcKh78TaTot",
|
| 43 |
+
"outputId": "1b00dbc7-21cd-421a-b191-b2e8685f491d"
|
| 44 |
+
},
|
| 45 |
+
"outputs": [],
|
| 46 |
+
"source": [
|
| 47 |
+
"from datetime import datetime, timedelta\n",
|
| 48 |
+
"\n",
|
| 49 |
+
"from openbb import obb\n",
|
| 50 |
+
"\n",
|
| 51 |
+
"obb.user.preferences.output_type = \"dataframe\""
|
| 52 |
+
]
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"cell_type": "markdown",
|
| 56 |
+
"metadata": {
|
| 57 |
+
"id": "WyKBFJg-R_r2"
|
| 58 |
+
},
|
| 59 |
+
"source": [
|
| 60 |
+
"If the earnings date falls on an option expiry, contracts expiring that day will not provide exposure to the after-market earnings reports."
|
| 61 |
+
]
|
| 62 |
+
},
|
| 63 |
+
{
|
| 64 |
+
"cell_type": "code",
|
| 65 |
+
"execution_count": 3,
|
| 66 |
+
"metadata": {
|
| 67 |
+
"colab": {
|
| 68 |
+
"base_uri": "https://localhost:8080/",
|
| 69 |
+
"height": 711
|
| 70 |
+
},
|
| 71 |
+
"id": "49D8bfFFPEwC",
|
| 72 |
+
"outputId": "b2eebaaa-ef2c-456a-fca2-96f6bee41b2d"
|
| 73 |
+
},
|
| 74 |
+
"outputs": [
|
| 75 |
+
{
|
| 76 |
+
"data": {
|
| 77 |
+
"text/html": [
|
| 78 |
+
"<div>\n",
|
| 79 |
+
"<style scoped>\n",
|
| 80 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 81 |
+
" vertical-align: middle;\n",
|
| 82 |
+
" }\n",
|
| 83 |
+
"\n",
|
| 84 |
+
" .dataframe tbody tr th {\n",
|
| 85 |
+
" vertical-align: top;\n",
|
| 86 |
+
" }\n",
|
| 87 |
+
"\n",
|
| 88 |
+
" .dataframe thead th {\n",
|
| 89 |
+
" text-align: right;\n",
|
| 90 |
+
" }\n",
|
| 91 |
+
"</style>\n",
|
| 92 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 93 |
+
" <thead>\n",
|
| 94 |
+
" <tr style=\"text-align: right;\">\n",
|
| 95 |
+
" <th></th>\n",
|
| 96 |
+
" <th>report_date</th>\n",
|
| 97 |
+
" <th>symbol</th>\n",
|
| 98 |
+
" <th>name</th>\n",
|
| 99 |
+
" <th>eps_previous</th>\n",
|
| 100 |
+
" <th>eps_consensus</th>\n",
|
| 101 |
+
" <th>num_estimates</th>\n",
|
| 102 |
+
" <th>period_ending</th>\n",
|
| 103 |
+
" <th>previous_report_date</th>\n",
|
| 104 |
+
" <th>reporting_time</th>\n",
|
| 105 |
+
" <th>market_cap</th>\n",
|
| 106 |
+
" </tr>\n",
|
| 107 |
+
" </thead>\n",
|
| 108 |
+
" <tbody>\n",
|
| 109 |
+
" <tr>\n",
|
| 110 |
+
" <th>166</th>\n",
|
| 111 |
+
" <td>2024-08-28</td>\n",
|
| 112 |
+
" <td>NVDA</td>\n",
|
| 113 |
+
" <td>NVIDIA Corporation</td>\n",
|
| 114 |
+
" <td>0.25</td>\n",
|
| 115 |
+
" <td>0.59</td>\n",
|
| 116 |
+
" <td>13.0</td>\n",
|
| 117 |
+
" <td>2024-07</td>\n",
|
| 118 |
+
" <td>2023-08-23</td>\n",
|
| 119 |
+
" <td>after-hours</td>\n",
|
| 120 |
+
" <td>3.160887e+12</td>\n",
|
| 121 |
+
" </tr>\n",
|
| 122 |
+
" <tr>\n",
|
| 123 |
+
" <th>0</th>\n",
|
| 124 |
+
" <td>2024-09-05</td>\n",
|
| 125 |
+
" <td>AVGO</td>\n",
|
| 126 |
+
" <td>Broadcom Inc.</td>\n",
|
| 127 |
+
" <td>0.95</td>\n",
|
| 128 |
+
" <td>0.95</td>\n",
|
| 129 |
+
" <td>10.0</td>\n",
|
| 130 |
+
" <td>2024-07</td>\n",
|
| 131 |
+
" <td>2023-08-31</td>\n",
|
| 132 |
+
" <td>after-hours</td>\n",
|
| 133 |
+
" <td>7.716866e+11</td>\n",
|
| 134 |
+
" </tr>\n",
|
| 135 |
+
" <tr>\n",
|
| 136 |
+
" <th>167</th>\n",
|
| 137 |
+
" <td>2024-08-28</td>\n",
|
| 138 |
+
" <td>CRM</td>\n",
|
| 139 |
+
" <td>Salesforce, Inc.</td>\n",
|
| 140 |
+
" <td>1.63</td>\n",
|
| 141 |
+
" <td>1.73</td>\n",
|
| 142 |
+
" <td>16.0</td>\n",
|
| 143 |
+
" <td>2024-07</td>\n",
|
| 144 |
+
" <td>2023-08-30</td>\n",
|
| 145 |
+
" <td>after-hours</td>\n",
|
| 146 |
+
" <td>2.529962e+11</td>\n",
|
| 147 |
+
" </tr>\n",
|
| 148 |
+
" <tr>\n",
|
| 149 |
+
" <th>261</th>\n",
|
| 150 |
+
" <td>2024-08-26</td>\n",
|
| 151 |
+
" <td>PDD</td>\n",
|
| 152 |
+
" <td>PDD Holdings Inc.</td>\n",
|
| 153 |
+
" <td>1.27</td>\n",
|
| 154 |
+
" <td>2.66</td>\n",
|
| 155 |
+
" <td>2.0</td>\n",
|
| 156 |
+
" <td>2024-06</td>\n",
|
| 157 |
+
" <td>2023-08-29</td>\n",
|
| 158 |
+
" <td>pre-market</td>\n",
|
| 159 |
+
" <td>2.007811e+11</td>\n",
|
| 160 |
+
" </tr>\n",
|
| 161 |
+
" <tr>\n",
|
| 162 |
+
" <th>168</th>\n",
|
| 163 |
+
" <td>2024-08-28</td>\n",
|
| 164 |
+
" <td>RY</td>\n",
|
| 165 |
+
" <td>Royal Bank Of Canada</td>\n",
|
| 166 |
+
" <td>2.13</td>\n",
|
| 167 |
+
" <td>2.14</td>\n",
|
| 168 |
+
" <td>3.0</td>\n",
|
| 169 |
+
" <td>2024-07</td>\n",
|
| 170 |
+
" <td>2023-08-24</td>\n",
|
| 171 |
+
" <td>pre-market</td>\n",
|
| 172 |
+
" <td>1.597315e+11</td>\n",
|
| 173 |
+
" </tr>\n",
|
| 174 |
+
" <tr>\n",
|
| 175 |
+
" <th>262</th>\n",
|
| 176 |
+
" <td>2024-08-26</td>\n",
|
| 177 |
+
" <td>BHP</td>\n",
|
| 178 |
+
" <td>BHP Group Limited</td>\n",
|
| 179 |
+
" <td>NaN</td>\n",
|
| 180 |
+
" <td>NaN</td>\n",
|
| 181 |
+
" <td>1.0</td>\n",
|
| 182 |
+
" <td>2024-06</td>\n",
|
| 183 |
+
" <td>NaN</td>\n",
|
| 184 |
+
" <td>after-hours</td>\n",
|
| 185 |
+
" <td>1.401966e+11</td>\n",
|
| 186 |
+
" </tr>\n",
|
| 187 |
+
" <tr>\n",
|
| 188 |
+
" <th>114</th>\n",
|
| 189 |
+
" <td>2024-08-29</td>\n",
|
| 190 |
+
" <td>DELL</td>\n",
|
| 191 |
+
" <td>Dell Technologies Inc.</td>\n",
|
| 192 |
+
" <td>1.44</td>\n",
|
| 193 |
+
" <td>1.49</td>\n",
|
| 194 |
+
" <td>4.0</td>\n",
|
| 195 |
+
" <td>2024-07</td>\n",
|
| 196 |
+
" <td>2023-08-31</td>\n",
|
| 197 |
+
" <td>after-hours</td>\n",
|
| 198 |
+
" <td>7.922927e+10</td>\n",
|
| 199 |
+
" </tr>\n",
|
| 200 |
+
" <tr>\n",
|
| 201 |
+
" <th>169</th>\n",
|
| 202 |
+
" <td>2024-08-28</td>\n",
|
| 203 |
+
" <td>CRWD</td>\n",
|
| 204 |
+
" <td>CrowdStrike Holdings, Inc.</td>\n",
|
| 205 |
+
" <td>0.06</td>\n",
|
| 206 |
+
" <td>0.23</td>\n",
|
| 207 |
+
" <td>14.0</td>\n",
|
| 208 |
+
" <td>2024-07</td>\n",
|
| 209 |
+
" <td>2023-08-30</td>\n",
|
| 210 |
+
" <td>after-hours</td>\n",
|
| 211 |
+
" <td>6.648856e+10</td>\n",
|
| 212 |
+
" </tr>\n",
|
| 213 |
+
" <tr>\n",
|
| 214 |
+
" <th>225</th>\n",
|
| 215 |
+
" <td>2024-08-27</td>\n",
|
| 216 |
+
" <td>BMO</td>\n",
|
| 217 |
+
" <td>Bank Of Montreal</td>\n",
|
| 218 |
+
" <td>2.08</td>\n",
|
| 219 |
+
" <td>1.98</td>\n",
|
| 220 |
+
" <td>3.0</td>\n",
|
| 221 |
+
" <td>2024-07</td>\n",
|
| 222 |
+
" <td>2023-08-29</td>\n",
|
| 223 |
+
" <td>pre-market</td>\n",
|
| 224 |
+
" <td>6.319707e+10</td>\n",
|
| 225 |
+
" </tr>\n",
|
| 226 |
+
" <tr>\n",
|
| 227 |
+
" <th>115</th>\n",
|
| 228 |
+
" <td>2024-08-29</td>\n",
|
| 229 |
+
" <td>MRVL</td>\n",
|
| 230 |
+
" <td>Marvell Technology, Inc.</td>\n",
|
| 231 |
+
" <td>0.18</td>\n",
|
| 232 |
+
" <td>0.13</td>\n",
|
| 233 |
+
" <td>13.0</td>\n",
|
| 234 |
+
" <td>2024-07</td>\n",
|
| 235 |
+
" <td>2023-08-24</td>\n",
|
| 236 |
+
" <td>after-hours</td>\n",
|
| 237 |
+
" <td>6.175190e+10</td>\n",
|
| 238 |
+
" </tr>\n",
|
| 239 |
+
" <tr>\n",
|
| 240 |
+
" <th>226</th>\n",
|
| 241 |
+
" <td>2024-08-27</td>\n",
|
| 242 |
+
" <td>BNS</td>\n",
|
| 243 |
+
" <td>Bank of Nova Scotia (The)</td>\n",
|
| 244 |
+
" <td>1.30</td>\n",
|
| 245 |
+
" <td>1.18</td>\n",
|
| 246 |
+
" <td>4.0</td>\n",
|
| 247 |
+
" <td>2024-07</td>\n",
|
| 248 |
+
" <td>2023-08-29</td>\n",
|
| 249 |
+
" <td>pre-market</td>\n",
|
| 250 |
+
" <td>5.855210e+10</td>\n",
|
| 251 |
+
" </tr>\n",
|
| 252 |
+
" <tr>\n",
|
| 253 |
+
" <th>116</th>\n",
|
| 254 |
+
" <td>2024-08-29</td>\n",
|
| 255 |
+
" <td>ADSK</td>\n",
|
| 256 |
+
" <td>Autodesk, Inc.</td>\n",
|
| 257 |
+
" <td>1.12</td>\n",
|
| 258 |
+
" <td>1.35</td>\n",
|
| 259 |
+
" <td>8.0</td>\n",
|
| 260 |
+
" <td>2024-07</td>\n",
|
| 261 |
+
" <td>2023-08-23</td>\n",
|
| 262 |
+
" <td>after-hours</td>\n",
|
| 263 |
+
" <td>5.444496e+10</td>\n",
|
| 264 |
+
" </tr>\n",
|
| 265 |
+
" <tr>\n",
|
| 266 |
+
" <th>117</th>\n",
|
| 267 |
+
" <td>2024-08-29</td>\n",
|
| 268 |
+
" <td>CM</td>\n",
|
| 269 |
+
" <td>Canadian Imperial Bank of Commerce</td>\n",
|
| 270 |
+
" <td>1.14</td>\n",
|
| 271 |
+
" <td>1.28</td>\n",
|
| 272 |
+
" <td>4.0</td>\n",
|
| 273 |
+
" <td>2024-07</td>\n",
|
| 274 |
+
" <td>2023-08-31</td>\n",
|
| 275 |
+
" <td>pre-market</td>\n",
|
| 276 |
+
" <td>5.042232e+10</td>\n",
|
| 277 |
+
" </tr>\n",
|
| 278 |
+
" <tr>\n",
|
| 279 |
+
" <th>170</th>\n",
|
| 280 |
+
" <td>2024-08-28</td>\n",
|
| 281 |
+
" <td>HPQ</td>\n",
|
| 282 |
+
" <td>HP Inc.</td>\n",
|
| 283 |
+
" <td>0.86</td>\n",
|
| 284 |
+
" <td>0.86</td>\n",
|
| 285 |
+
" <td>4.0</td>\n",
|
| 286 |
+
" <td>2024-07</td>\n",
|
| 287 |
+
" <td>2023-08-29</td>\n",
|
| 288 |
+
" <td>after-hours</td>\n",
|
| 289 |
+
" <td>3.451380e+10</td>\n",
|
| 290 |
+
" </tr>\n",
|
| 291 |
+
" <tr>\n",
|
| 292 |
+
" <th>227</th>\n",
|
| 293 |
+
" <td>2024-08-27</td>\n",
|
| 294 |
+
" <td>HEI</td>\n",
|
| 295 |
+
" <td>Heico Corporation</td>\n",
|
| 296 |
+
" <td>0.77</td>\n",
|
| 297 |
+
" <td>0.91</td>\n",
|
| 298 |
+
" <td>8.0</td>\n",
|
| 299 |
+
" <td>2024-07</td>\n",
|
| 300 |
+
" <td>2023-08-28</td>\n",
|
| 301 |
+
" <td>pre-market</td>\n",
|
| 302 |
+
" <td>3.387054e+10</td>\n",
|
| 303 |
+
" </tr>\n",
|
| 304 |
+
" <tr>\n",
|
| 305 |
+
" <th>171</th>\n",
|
| 306 |
+
" <td>2024-08-28</td>\n",
|
| 307 |
+
" <td>VEEV</td>\n",
|
| 308 |
+
" <td>Veeva Systems Inc.</td>\n",
|
| 309 |
+
" <td>0.70</td>\n",
|
| 310 |
+
" <td>1.04</td>\n",
|
| 311 |
+
" <td>10.0</td>\n",
|
| 312 |
+
" <td>2024-07</td>\n",
|
| 313 |
+
" <td>2023-08-30</td>\n",
|
| 314 |
+
" <td>after-hours</td>\n",
|
| 315 |
+
" <td>3.256312e+10</td>\n",
|
| 316 |
+
" </tr>\n",
|
| 317 |
+
" <tr>\n",
|
| 318 |
+
" <th>118</th>\n",
|
| 319 |
+
" <td>2024-08-29</td>\n",
|
| 320 |
+
" <td>LULU</td>\n",
|
| 321 |
+
" <td>lululemon athletica inc.</td>\n",
|
| 322 |
+
" <td>2.68</td>\n",
|
| 323 |
+
" <td>2.94</td>\n",
|
| 324 |
+
" <td>13.0</td>\n",
|
| 325 |
+
" <td>2024-07</td>\n",
|
| 326 |
+
" <td>2023-08-31</td>\n",
|
| 327 |
+
" <td>after-hours</td>\n",
|
| 328 |
+
" <td>3.184542e+10</td>\n",
|
| 329 |
+
" </tr>\n",
|
| 330 |
+
" <tr>\n",
|
| 331 |
+
" <th>88</th>\n",
|
| 332 |
+
" <td>2024-09-03</td>\n",
|
| 333 |
+
" <td>ZS</td>\n",
|
| 334 |
+
" <td>Zscaler, Inc.</td>\n",
|
| 335 |
+
" <td>-0.17</td>\n",
|
| 336 |
+
" <td>-0.14</td>\n",
|
| 337 |
+
" <td>12.0</td>\n",
|
| 338 |
+
" <td>2024-07</td>\n",
|
| 339 |
+
" <td>2023-09-05</td>\n",
|
| 340 |
+
" <td>after-hours</td>\n",
|
| 341 |
+
" <td>3.030086e+10</td>\n",
|
| 342 |
+
" </tr>\n",
|
| 343 |
+
" <tr>\n",
|
| 344 |
+
" <th>263</th>\n",
|
| 345 |
+
" <td>2024-08-26</td>\n",
|
| 346 |
+
" <td>TCOM</td>\n",
|
| 347 |
+
" <td>Trip.com Group Limited</td>\n",
|
| 348 |
+
" <td>0.60</td>\n",
|
| 349 |
+
" <td>0.65</td>\n",
|
| 350 |
+
" <td>2.0</td>\n",
|
| 351 |
+
" <td>2024-06</td>\n",
|
| 352 |
+
" <td>2023-09-04</td>\n",
|
| 353 |
+
" <td>after-hours</td>\n",
|
| 354 |
+
" <td>2.780128e+10</td>\n",
|
| 355 |
+
" </tr>\n",
|
| 356 |
+
" <tr>\n",
|
| 357 |
+
" <th>172</th>\n",
|
| 358 |
+
" <td>2024-08-28</td>\n",
|
| 359 |
+
" <td>NTAP</td>\n",
|
| 360 |
+
" <td>NetApp, Inc.</td>\n",
|
| 361 |
+
" <td>0.84</td>\n",
|
| 362 |
+
" <td>1.15</td>\n",
|
| 363 |
+
" <td>8.0</td>\n",
|
| 364 |
+
" <td>2024-07</td>\n",
|
| 365 |
+
" <td>2023-08-23</td>\n",
|
| 366 |
+
" <td>after-hours</td>\n",
|
| 367 |
+
" <td>2.745601e+10</td>\n",
|
| 368 |
+
" </tr>\n",
|
| 369 |
+
" </tbody>\n",
|
| 370 |
+
"</table>\n",
|
| 371 |
+
"</div>"
|
| 372 |
+
],
|
| 373 |
+
"text/plain": [
|
| 374 |
+
" report_date symbol name eps_previous \\\n",
|
| 375 |
+
"166 2024-08-28 NVDA NVIDIA Corporation 0.25 \n",
|
| 376 |
+
"0 2024-09-05 AVGO Broadcom Inc. 0.95 \n",
|
| 377 |
+
"167 2024-08-28 CRM Salesforce, Inc. 1.63 \n",
|
| 378 |
+
"261 2024-08-26 PDD PDD Holdings Inc. 1.27 \n",
|
| 379 |
+
"168 2024-08-28 RY Royal Bank Of Canada 2.13 \n",
|
| 380 |
+
"262 2024-08-26 BHP BHP Group Limited NaN \n",
|
| 381 |
+
"114 2024-08-29 DELL Dell Technologies Inc. 1.44 \n",
|
| 382 |
+
"169 2024-08-28 CRWD CrowdStrike Holdings, Inc. 0.06 \n",
|
| 383 |
+
"225 2024-08-27 BMO Bank Of Montreal 2.08 \n",
|
| 384 |
+
"115 2024-08-29 MRVL Marvell Technology, Inc. 0.18 \n",
|
| 385 |
+
"226 2024-08-27 BNS Bank of Nova Scotia (The) 1.30 \n",
|
| 386 |
+
"116 2024-08-29 ADSK Autodesk, Inc. 1.12 \n",
|
| 387 |
+
"117 2024-08-29 CM Canadian Imperial Bank of Commerce 1.14 \n",
|
| 388 |
+
"170 2024-08-28 HPQ HP Inc. 0.86 \n",
|
| 389 |
+
"227 2024-08-27 HEI Heico Corporation 0.77 \n",
|
| 390 |
+
"171 2024-08-28 VEEV Veeva Systems Inc. 0.70 \n",
|
| 391 |
+
"118 2024-08-29 LULU lululemon athletica inc. 2.68 \n",
|
| 392 |
+
"88 2024-09-03 ZS Zscaler, Inc. -0.17 \n",
|
| 393 |
+
"263 2024-08-26 TCOM Trip.com Group Limited 0.60 \n",
|
| 394 |
+
"172 2024-08-28 NTAP NetApp, Inc. 0.84 \n",
|
| 395 |
+
"\n",
|
| 396 |
+
" eps_consensus num_estimates period_ending previous_report_date \\\n",
|
| 397 |
+
"166 0.59 13.0 2024-07 2023-08-23 \n",
|
| 398 |
+
"0 0.95 10.0 2024-07 2023-08-31 \n",
|
| 399 |
+
"167 1.73 16.0 2024-07 2023-08-30 \n",
|
| 400 |
+
"261 2.66 2.0 2024-06 2023-08-29 \n",
|
| 401 |
+
"168 2.14 3.0 2024-07 2023-08-24 \n",
|
| 402 |
+
"262 NaN 1.0 2024-06 NaN \n",
|
| 403 |
+
"114 1.49 4.0 2024-07 2023-08-31 \n",
|
| 404 |
+
"169 0.23 14.0 2024-07 2023-08-30 \n",
|
| 405 |
+
"225 1.98 3.0 2024-07 2023-08-29 \n",
|
| 406 |
+
"115 0.13 13.0 2024-07 2023-08-24 \n",
|
| 407 |
+
"226 1.18 4.0 2024-07 2023-08-29 \n",
|
| 408 |
+
"116 1.35 8.0 2024-07 2023-08-23 \n",
|
| 409 |
+
"117 1.28 4.0 2024-07 2023-08-31 \n",
|
| 410 |
+
"170 0.86 4.0 2024-07 2023-08-29 \n",
|
| 411 |
+
"227 0.91 8.0 2024-07 2023-08-28 \n",
|
| 412 |
+
"171 1.04 10.0 2024-07 2023-08-30 \n",
|
| 413 |
+
"118 2.94 13.0 2024-07 2023-08-31 \n",
|
| 414 |
+
"88 -0.14 12.0 2024-07 2023-09-05 \n",
|
| 415 |
+
"263 0.65 2.0 2024-06 2023-09-04 \n",
|
| 416 |
+
"172 1.15 8.0 2024-07 2023-08-23 \n",
|
| 417 |
+
"\n",
|
| 418 |
+
" reporting_time market_cap \n",
|
| 419 |
+
"166 after-hours 3.160887e+12 \n",
|
| 420 |
+
"0 after-hours 7.716866e+11 \n",
|
| 421 |
+
"167 after-hours 2.529962e+11 \n",
|
| 422 |
+
"261 pre-market 2.007811e+11 \n",
|
| 423 |
+
"168 pre-market 1.597315e+11 \n",
|
| 424 |
+
"262 after-hours 1.401966e+11 \n",
|
| 425 |
+
"114 after-hours 7.922927e+10 \n",
|
| 426 |
+
"169 after-hours 6.648856e+10 \n",
|
| 427 |
+
"225 pre-market 6.319707e+10 \n",
|
| 428 |
+
"115 after-hours 6.175190e+10 \n",
|
| 429 |
+
"226 pre-market 5.855210e+10 \n",
|
| 430 |
+
"116 after-hours 5.444496e+10 \n",
|
| 431 |
+
"117 pre-market 5.042232e+10 \n",
|
| 432 |
+
"170 after-hours 3.451380e+10 \n",
|
| 433 |
+
"227 pre-market 3.387054e+10 \n",
|
| 434 |
+
"171 after-hours 3.256312e+10 \n",
|
| 435 |
+
"118 after-hours 3.184542e+10 \n",
|
| 436 |
+
"88 after-hours 3.030086e+10 \n",
|
| 437 |
+
"263 after-hours 2.780128e+10 \n",
|
| 438 |
+
"172 after-hours 2.745601e+10 "
|
| 439 |
+
]
|
| 440 |
+
},
|
| 441 |
+
"execution_count": 3,
|
| 442 |
+
"metadata": {},
|
| 443 |
+
"output_type": "execute_result"
|
| 444 |
+
}
|
| 445 |
+
],
|
| 446 |
+
"source": [
|
| 447 |
+
"# Lookup some upcoming earnings dates and sort them by market cap.\n",
|
| 448 |
+
"\n",
|
| 449 |
+
"earnings_calendar = obb.equity.calendar.earnings(\n",
|
| 450 |
+
" start_date=(datetime.now() + timedelta(days=1)).date(),\n",
|
| 451 |
+
" end_date=(datetime.now() + timedelta(days=14)).date(),\n",
|
| 452 |
+
" provider=\"nasdaq\",\n",
|
| 453 |
+
")\n",
|
| 454 |
+
"\n",
|
| 455 |
+
"earnings_calendar.sort_values(by=[\"market_cap\", \"num_estimates\"], ascending=False).head(\n",
|
| 456 |
+
" 20\n",
|
| 457 |
+
")"
|
| 458 |
+
]
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"cell_type": "code",
|
| 462 |
+
"execution_count": 27,
|
| 463 |
+
"metadata": {
|
| 464 |
+
"colab": {
|
| 465 |
+
"base_uri": "https://localhost:8080/"
|
| 466 |
+
},
|
| 467 |
+
"id": "IzmLloIfTQJo",
|
| 468 |
+
"outputId": "1c08fa80-eaf2-4548-8c27-70c82fac79ea"
|
| 469 |
+
},
|
| 470 |
+
"outputs": [
|
| 471 |
+
{
|
| 472 |
+
"data": {
|
| 473 |
+
"text/plain": [
|
| 474 |
+
"'Last Price: $124.7001'"
|
| 475 |
+
]
|
| 476 |
+
},
|
| 477 |
+
"metadata": {},
|
| 478 |
+
"output_type": "display_data"
|
| 479 |
+
},
|
| 480 |
+
{
|
| 481 |
+
"data": {
|
| 482 |
+
"text/plain": [
|
| 483 |
+
"['2024-08-23', '2024-08-30', '2024-09-06']"
|
| 484 |
+
]
|
| 485 |
+
},
|
| 486 |
+
"metadata": {},
|
| 487 |
+
"output_type": "display_data"
|
| 488 |
+
}
|
| 489 |
+
],
|
| 490 |
+
"source": [
|
| 491 |
+
"# Get the options chains data.\n",
|
| 492 |
+
"\n",
|
| 493 |
+
"symbol = \"NVDA\" # This will not be evergreen, change the symbol based on a stock above.\n",
|
| 494 |
+
"\n",
|
| 495 |
+
"obb.user.preferences.output_type = \"OBBject\" # To use the built-in options chains methods, we need to set the output type to OBBject.\n",
|
| 496 |
+
"\n",
|
| 497 |
+
"options = obb.derivatives.options.chains(symbol, provider=\"cboe\")\n",
|
| 498 |
+
"\n",
|
| 499 |
+
"last_price = options.results.underlying_price[0]\n",
|
| 500 |
+
"\n",
|
| 501 |
+
"display(f\"Last Price: ${last_price}\")\n",
|
| 502 |
+
"\n",
|
| 503 |
+
"display(options.results.expirations[:3])"
|
| 504 |
+
]
|
| 505 |
+
},
|
| 506 |
+
{
|
| 507 |
+
"cell_type": "code",
|
| 508 |
+
"execution_count": 40,
|
| 509 |
+
"metadata": {},
|
| 510 |
+
"outputs": [
|
| 511 |
+
{
|
| 512 |
+
"name": "stdout",
|
| 513 |
+
"output_type": "stream",
|
| 514 |
+
"text": [
|
| 515 |
+
"Cost of Straddle: $14.65\n",
|
| 516 |
+
"Cost as a % of Share Price: 11.7482%\n",
|
| 517 |
+
"Upper Breakeven Price: $139.65\n",
|
| 518 |
+
"Lower Breakeven Price: $109.35\n",
|
| 519 |
+
"Implied Daily Move: 1.3982%\n",
|
| 520 |
+
"\n"
|
| 521 |
+
]
|
| 522 |
+
},
|
| 523 |
+
{
|
| 524 |
+
"data": {
|
| 525 |
+
"text/html": [
|
| 526 |
+
"<div>\n",
|
| 527 |
+
"<style scoped>\n",
|
| 528 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 529 |
+
" vertical-align: middle;\n",
|
| 530 |
+
" }\n",
|
| 531 |
+
"\n",
|
| 532 |
+
" .dataframe tbody tr th {\n",
|
| 533 |
+
" vertical-align: top;\n",
|
| 534 |
+
" }\n",
|
| 535 |
+
"\n",
|
| 536 |
+
" .dataframe thead th {\n",
|
| 537 |
+
" text-align: right;\n",
|
| 538 |
+
" }\n",
|
| 539 |
+
"</style>\n",
|
| 540 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 541 |
+
" <thead>\n",
|
| 542 |
+
" <tr style=\"text-align: right;\">\n",
|
| 543 |
+
" <th></th>\n",
|
| 544 |
+
" <th>Long Straddle</th>\n",
|
| 545 |
+
" </tr>\n",
|
| 546 |
+
" </thead>\n",
|
| 547 |
+
" <tbody>\n",
|
| 548 |
+
" <tr>\n",
|
| 549 |
+
" <th>Symbol</th>\n",
|
| 550 |
+
" <td>NVDA</td>\n",
|
| 551 |
+
" </tr>\n",
|
| 552 |
+
" <tr>\n",
|
| 553 |
+
" <th>Underlying Price</th>\n",
|
| 554 |
+
" <td>124.7001</td>\n",
|
| 555 |
+
" </tr>\n",
|
| 556 |
+
" <tr>\n",
|
| 557 |
+
" <th>Expiration</th>\n",
|
| 558 |
+
" <td>2024-08-30</td>\n",
|
| 559 |
+
" </tr>\n",
|
| 560 |
+
" <tr>\n",
|
| 561 |
+
" <th>DTE</th>\n",
|
| 562 |
+
" <td>8</td>\n",
|
| 563 |
+
" </tr>\n",
|
| 564 |
+
" <tr>\n",
|
| 565 |
+
" <th>Strike 1</th>\n",
|
| 566 |
+
" <td>125.0</td>\n",
|
| 567 |
+
" </tr>\n",
|
| 568 |
+
" <tr>\n",
|
| 569 |
+
" <th>Strike 2</th>\n",
|
| 570 |
+
" <td>124.0</td>\n",
|
| 571 |
+
" </tr>\n",
|
| 572 |
+
" <tr>\n",
|
| 573 |
+
" <th>Strike 1 Premium</th>\n",
|
| 574 |
+
" <td>7.55</td>\n",
|
| 575 |
+
" </tr>\n",
|
| 576 |
+
" <tr>\n",
|
| 577 |
+
" <th>Strike 2 Premium</th>\n",
|
| 578 |
+
" <td>7.1</td>\n",
|
| 579 |
+
" </tr>\n",
|
| 580 |
+
" <tr>\n",
|
| 581 |
+
" <th>Cost</th>\n",
|
| 582 |
+
" <td>14.65</td>\n",
|
| 583 |
+
" </tr>\n",
|
| 584 |
+
" <tr>\n",
|
| 585 |
+
" <th>Cost Percent</th>\n",
|
| 586 |
+
" <td>11.7482</td>\n",
|
| 587 |
+
" </tr>\n",
|
| 588 |
+
" <tr>\n",
|
| 589 |
+
" <th>Breakeven Upper</th>\n",
|
| 590 |
+
" <td>139.65</td>\n",
|
| 591 |
+
" </tr>\n",
|
| 592 |
+
" <tr>\n",
|
| 593 |
+
" <th>Breakeven Upper Percent</th>\n",
|
| 594 |
+
" <td>11.9887</td>\n",
|
| 595 |
+
" </tr>\n",
|
| 596 |
+
" <tr>\n",
|
| 597 |
+
" <th>Breakeven Lower</th>\n",
|
| 598 |
+
" <td>109.35</td>\n",
|
| 599 |
+
" </tr>\n",
|
| 600 |
+
" <tr>\n",
|
| 601 |
+
" <th>Breakeven Lower Percent</th>\n",
|
| 602 |
+
" <td>-12.3096</td>\n",
|
| 603 |
+
" </tr>\n",
|
| 604 |
+
" <tr>\n",
|
| 605 |
+
" <th>Max Profit</th>\n",
|
| 606 |
+
" <td>inf</td>\n",
|
| 607 |
+
" </tr>\n",
|
| 608 |
+
" <tr>\n",
|
| 609 |
+
" <th>Max Loss</th>\n",
|
| 610 |
+
" <td>-14.65</td>\n",
|
| 611 |
+
" </tr>\n",
|
| 612 |
+
" <tr>\n",
|
| 613 |
+
" <th>Payoff Ratio</th>\n",
|
| 614 |
+
" <td>inf</td>\n",
|
| 615 |
+
" </tr>\n",
|
| 616 |
+
" </tbody>\n",
|
| 617 |
+
"</table>\n",
|
| 618 |
+
"</div>"
|
| 619 |
+
],
|
| 620 |
+
"text/plain": [
|
| 621 |
+
" Long Straddle\n",
|
| 622 |
+
"Symbol NVDA\n",
|
| 623 |
+
"Underlying Price 124.7001\n",
|
| 624 |
+
"Expiration 2024-08-30\n",
|
| 625 |
+
"DTE 8\n",
|
| 626 |
+
"Strike 1 125.0\n",
|
| 627 |
+
"Strike 2 124.0\n",
|
| 628 |
+
"Strike 1 Premium 7.55\n",
|
| 629 |
+
"Strike 2 Premium 7.1\n",
|
| 630 |
+
"Cost 14.65\n",
|
| 631 |
+
"Cost Percent 11.7482\n",
|
| 632 |
+
"Breakeven Upper 139.65\n",
|
| 633 |
+
"Breakeven Upper Percent 11.9887\n",
|
| 634 |
+
"Breakeven Lower 109.35\n",
|
| 635 |
+
"Breakeven Lower Percent -12.3096\n",
|
| 636 |
+
"Max Profit inf\n",
|
| 637 |
+
"Max Loss -14.65\n",
|
| 638 |
+
"Payoff Ratio inf"
|
| 639 |
+
]
|
| 640 |
+
},
|
| 641 |
+
"metadata": {},
|
| 642 |
+
"output_type": "display_data"
|
| 643 |
+
}
|
| 644 |
+
],
|
| 645 |
+
"source": [
|
| 646 |
+
"# Use the straddle method of the results object to get the straddle data and then calculate the implied move.\n",
|
| 647 |
+
"\n",
|
| 648 |
+
"straddle = options.results.straddle(days=options.results.expirations[1])\n",
|
| 649 |
+
"straddle_price = straddle.loc[\"Cost\"].values[0]\n",
|
| 650 |
+
"days = straddle.loc[\"DTE\"].values[0]\n",
|
| 651 |
+
"upper_price = straddle.loc[\"Breakeven Upper\"].values[0]\n",
|
| 652 |
+
"lower_price = straddle.loc[\"Breakeven Lower\"].values[0]\n",
|
| 653 |
+
"\n",
|
| 654 |
+
"implied_move = ((1 + straddle_price / last_price) ** (1 / days) - 1) * 100\n",
|
| 655 |
+
"\n",
|
| 656 |
+
"display(\n",
|
| 657 |
+
" f\"Cost of Straddle: ${round(straddle_price, 2)}\"\n",
|
| 658 |
+
" f\"\\nCost as a % of Share Price: {round((straddle_price/last_price) * 100, 4)}%\"\n",
|
| 659 |
+
" f\"\\nUpper Breakeven Price: ${upper_price}\"\n",
|
| 660 |
+
" f\"\\nLower Breakeven Price: ${lower_price}\"\n",
|
| 661 |
+
" f\"\\nImplied Daily Move: {round(implied_move, 4)}%\\n\"\n",
|
| 662 |
+
")\n",
|
| 663 |
+
"\n",
|
| 664 |
+
"display(straddle)"
|
| 665 |
+
]
|
| 666 |
+
}
|
| 667 |
+
],
|
| 668 |
+
"metadata": {
|
| 669 |
+
"colab": {
|
| 670 |
+
"provenance": []
|
| 671 |
+
},
|
| 672 |
+
"kernelspec": {
|
| 673 |
+
"display_name": "Python 3",
|
| 674 |
+
"name": "python3"
|
| 675 |
+
},
|
| 676 |
+
"language_info": {
|
| 677 |
+
"codemirror_mode": {
|
| 678 |
+
"name": "ipython",
|
| 679 |
+
"version": 3
|
| 680 |
+
},
|
| 681 |
+
"file_extension": ".py",
|
| 682 |
+
"mimetype": "text/x-python",
|
| 683 |
+
"name": "python",
|
| 684 |
+
"nbconvert_exporter": "python",
|
| 685 |
+
"pygments_lexer": "ipython3",
|
| 686 |
+
"version": "3.12.4"
|
| 687 |
+
}
|
| 688 |
+
},
|
| 689 |
+
"nbformat": 4,
|
| 690 |
+
"nbformat_minor": 0
|
| 691 |
+
}
|
examples/impliedEarningsMove.webp
ADDED
|
examples/loadHistoricalPriceData.ipynb
ADDED
|
@@ -0,0 +1,2514 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"attachments": {},
|
| 5 |
+
"cell_type": "markdown",
|
| 6 |
+
"metadata": {},
|
| 7 |
+
"source": [
|
| 8 |
+
"# Historical Prices With the OpenBB Platform\n",
|
| 9 |
+
"\n",
|
| 10 |
+
"This notebook demonstrates some of the ways to approach loading historical price data using the OpenBB Platform. The action is in the Equity module; but first, we need to initialize the notebook with the import statements block.\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"## Import Statements"
|
| 13 |
+
]
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"cell_type": "code",
|
| 17 |
+
"execution_count": 1,
|
| 18 |
+
"metadata": {},
|
| 19 |
+
"outputs": [],
|
| 20 |
+
"source": [
|
| 21 |
+
"from datetime import datetime, timedelta\n",
|
| 22 |
+
"\n",
|
| 23 |
+
"import pandas as pd\n",
|
| 24 |
+
"from openbb import obb"
|
| 25 |
+
]
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"attachments": {},
|
| 29 |
+
"cell_type": "markdown",
|
| 30 |
+
"metadata": {},
|
| 31 |
+
"source": [
|
| 32 |
+
"## The Equity Module\n",
|
| 33 |
+
"\n",
|
| 34 |
+
"Historical market prices typically come in the form of OHLC+V - open, high, low, close, volume. There may be additional fields returned by a provider, but those are the expected columns. Granularity and amount of historical data will vary by provider and subscription status. Visit their websites to understand what your entitlements are.\n",
|
| 35 |
+
"\n",
|
| 36 |
+
"### openbb.equity.price.historical()\n",
|
| 37 |
+
"\n",
|
| 38 |
+
"- This endpoint has the most number of providers out of any function. At the time of writing, choices are:\n",
|
| 39 |
+
"\n",
|
| 40 |
+
"['alpha_vantage', 'cboe', 'fmp', 'intrinio', 'polygon', 'tiingo', 'yfinance']\n",
|
| 41 |
+
"\n",
|
| 42 |
+
"- Common parameters have been standardized across all souces, `start_date`, `end_date`, `interval`.\n",
|
| 43 |
+
"\n",
|
| 44 |
+
"- The default interval will be `1d`.\n",
|
| 45 |
+
"\n",
|
| 46 |
+
"- The depth of historical data and choices for granularity will vary by provider and subscription status. Refer to the website and documentation of each source understand your specific entitlements.\n",
|
| 47 |
+
"\n",
|
| 48 |
+
"- For demonstration purposes, we will use the `openbb-yfinance` data extension."
|
| 49 |
+
]
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"cell_type": "code",
|
| 53 |
+
"execution_count": 2,
|
| 54 |
+
"metadata": {},
|
| 55 |
+
"outputs": [
|
| 56 |
+
{
|
| 57 |
+
"data": {
|
| 58 |
+
"text/html": [
|
| 59 |
+
"<div>\n",
|
| 60 |
+
"<style scoped>\n",
|
| 61 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 62 |
+
" vertical-align: middle;\n",
|
| 63 |
+
" }\n",
|
| 64 |
+
"\n",
|
| 65 |
+
" .dataframe tbody tr th {\n",
|
| 66 |
+
" vertical-align: top;\n",
|
| 67 |
+
" }\n",
|
| 68 |
+
"\n",
|
| 69 |
+
" .dataframe thead th {\n",
|
| 70 |
+
" text-align: right;\n",
|
| 71 |
+
" }\n",
|
| 72 |
+
"</style>\n",
|
| 73 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 74 |
+
" <thead>\n",
|
| 75 |
+
" <tr style=\"text-align: right;\">\n",
|
| 76 |
+
" <th></th>\n",
|
| 77 |
+
" <th>open</th>\n",
|
| 78 |
+
" <th>high</th>\n",
|
| 79 |
+
" <th>low</th>\n",
|
| 80 |
+
" <th>close</th>\n",
|
| 81 |
+
" <th>volume</th>\n",
|
| 82 |
+
" <th>split_ratio</th>\n",
|
| 83 |
+
" <th>dividend</th>\n",
|
| 84 |
+
" <th>capital_gains</th>\n",
|
| 85 |
+
" </tr>\n",
|
| 86 |
+
" <tr>\n",
|
| 87 |
+
" <th>date</th>\n",
|
| 88 |
+
" <th></th>\n",
|
| 89 |
+
" <th></th>\n",
|
| 90 |
+
" <th></th>\n",
|
| 91 |
+
" <th></th>\n",
|
| 92 |
+
" <th></th>\n",
|
| 93 |
+
" <th></th>\n",
|
| 94 |
+
" <th></th>\n",
|
| 95 |
+
" <th></th>\n",
|
| 96 |
+
" </tr>\n",
|
| 97 |
+
" </thead>\n",
|
| 98 |
+
" <tbody>\n",
|
| 99 |
+
" <tr>\n",
|
| 100 |
+
" <th>2023-08-22</th>\n",
|
| 101 |
+
" <td>441.179993</td>\n",
|
| 102 |
+
" <td>441.179993</td>\n",
|
| 103 |
+
" <td>437.570007</td>\n",
|
| 104 |
+
" <td>438.149994</td>\n",
|
| 105 |
+
" <td>65062900</td>\n",
|
| 106 |
+
" <td>0.0</td>\n",
|
| 107 |
+
" <td>0.0</td>\n",
|
| 108 |
+
" <td>0.0</td>\n",
|
| 109 |
+
" </tr>\n",
|
| 110 |
+
" </tbody>\n",
|
| 111 |
+
"</table>\n",
|
| 112 |
+
"</div>"
|
| 113 |
+
],
|
| 114 |
+
"text/plain": [
|
| 115 |
+
" open high low close volume \\\n",
|
| 116 |
+
"date \n",
|
| 117 |
+
"2023-08-22 441.179993 441.179993 437.570007 438.149994 65062900 \n",
|
| 118 |
+
"\n",
|
| 119 |
+
" split_ratio dividend capital_gains \n",
|
| 120 |
+
"date \n",
|
| 121 |
+
"2023-08-22 0.0 0.0 0.0 "
|
| 122 |
+
]
|
| 123 |
+
},
|
| 124 |
+
"execution_count": 2,
|
| 125 |
+
"metadata": {},
|
| 126 |
+
"output_type": "execute_result"
|
| 127 |
+
}
|
| 128 |
+
],
|
| 129 |
+
"source": [
|
| 130 |
+
"df_daily = obb.equity.price.historical(symbol=\"spy\", provider=\"yfinance\")\n",
|
| 131 |
+
"df_daily.to_df().head(1)"
|
| 132 |
+
]
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"attachments": {},
|
| 136 |
+
"cell_type": "markdown",
|
| 137 |
+
"metadata": {},
|
| 138 |
+
"source": [
|
| 139 |
+
"To load the entire history available from a source, pick a starting date well beyond what it might be. For example, `1900-01-01`"
|
| 140 |
+
]
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"cell_type": "code",
|
| 144 |
+
"execution_count": 3,
|
| 145 |
+
"metadata": {},
|
| 146 |
+
"outputs": [
|
| 147 |
+
{
|
| 148 |
+
"data": {
|
| 149 |
+
"text/html": [
|
| 150 |
+
"<div>\n",
|
| 151 |
+
"<style scoped>\n",
|
| 152 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 153 |
+
" vertical-align: middle;\n",
|
| 154 |
+
" }\n",
|
| 155 |
+
"\n",
|
| 156 |
+
" .dataframe tbody tr th {\n",
|
| 157 |
+
" vertical-align: top;\n",
|
| 158 |
+
" }\n",
|
| 159 |
+
"\n",
|
| 160 |
+
" .dataframe thead th {\n",
|
| 161 |
+
" text-align: right;\n",
|
| 162 |
+
" }\n",
|
| 163 |
+
"</style>\n",
|
| 164 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 165 |
+
" <thead>\n",
|
| 166 |
+
" <tr style=\"text-align: right;\">\n",
|
| 167 |
+
" <th></th>\n",
|
| 168 |
+
" <th>open</th>\n",
|
| 169 |
+
" <th>high</th>\n",
|
| 170 |
+
" <th>low</th>\n",
|
| 171 |
+
" <th>close</th>\n",
|
| 172 |
+
" <th>volume</th>\n",
|
| 173 |
+
" <th>split_ratio</th>\n",
|
| 174 |
+
" <th>dividend</th>\n",
|
| 175 |
+
" <th>capital_gains</th>\n",
|
| 176 |
+
" </tr>\n",
|
| 177 |
+
" <tr>\n",
|
| 178 |
+
" <th>date</th>\n",
|
| 179 |
+
" <th></th>\n",
|
| 180 |
+
" <th></th>\n",
|
| 181 |
+
" <th></th>\n",
|
| 182 |
+
" <th></th>\n",
|
| 183 |
+
" <th></th>\n",
|
| 184 |
+
" <th></th>\n",
|
| 185 |
+
" <th></th>\n",
|
| 186 |
+
" <th></th>\n",
|
| 187 |
+
" </tr>\n",
|
| 188 |
+
" </thead>\n",
|
| 189 |
+
" <tbody>\n",
|
| 190 |
+
" <tr>\n",
|
| 191 |
+
" <th>1993-01-29</th>\n",
|
| 192 |
+
" <td>43.96875</td>\n",
|
| 193 |
+
" <td>43.96875</td>\n",
|
| 194 |
+
" <td>43.75</td>\n",
|
| 195 |
+
" <td>43.9375</td>\n",
|
| 196 |
+
" <td>1003200</td>\n",
|
| 197 |
+
" <td>0.0</td>\n",
|
| 198 |
+
" <td>0.0</td>\n",
|
| 199 |
+
" <td>0.0</td>\n",
|
| 200 |
+
" </tr>\n",
|
| 201 |
+
" </tbody>\n",
|
| 202 |
+
"</table>\n",
|
| 203 |
+
"</div>"
|
| 204 |
+
],
|
| 205 |
+
"text/plain": [
|
| 206 |
+
" open high low close volume split_ratio \\\n",
|
| 207 |
+
"date \n",
|
| 208 |
+
"1993-01-29 43.96875 43.96875 43.75 43.9375 1003200 0.0 \n",
|
| 209 |
+
"\n",
|
| 210 |
+
" dividend capital_gains \n",
|
| 211 |
+
"date \n",
|
| 212 |
+
"1993-01-29 0.0 0.0 "
|
| 213 |
+
]
|
| 214 |
+
},
|
| 215 |
+
"execution_count": 3,
|
| 216 |
+
"metadata": {},
|
| 217 |
+
"output_type": "execute_result"
|
| 218 |
+
}
|
| 219 |
+
],
|
| 220 |
+
"source": [
|
| 221 |
+
"df_daily = obb.equity.price.historical(\n",
|
| 222 |
+
" symbol=\"spy\", start_date=\"1990-01-01\", provider=\"yfinance\"\n",
|
| 223 |
+
").to_df()\n",
|
| 224 |
+
"df_daily.head(1)"
|
| 225 |
+
]
|
| 226 |
+
},
|
| 227 |
+
{
|
| 228 |
+
"cell_type": "markdown",
|
| 229 |
+
"metadata": {},
|
| 230 |
+
"source": [
|
| 231 |
+
"#### Intervals\n",
|
| 232 |
+
"\n",
|
| 233 |
+
"The intervals are entered according to this pattern:\n",
|
| 234 |
+
"\n",
|
| 235 |
+
"- `1m` = One Minute\n",
|
| 236 |
+
"- `1h` = One Hour\n",
|
| 237 |
+
"- `1d` = One Day\n",
|
| 238 |
+
"- `1W` = One Week\n",
|
| 239 |
+
"- `1M` = One Month\n",
|
| 240 |
+
"\n",
|
| 241 |
+
"The date for monthly value is the first or last, depending on the provider. This can be easily resampled from daily data."
|
| 242 |
+
]
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
"cell_type": "code",
|
| 246 |
+
"execution_count": 4,
|
| 247 |
+
"metadata": {},
|
| 248 |
+
"outputs": [
|
| 249 |
+
{
|
| 250 |
+
"data": {
|
| 251 |
+
"text/html": [
|
| 252 |
+
"<div>\n",
|
| 253 |
+
"<style scoped>\n",
|
| 254 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 255 |
+
" vertical-align: middle;\n",
|
| 256 |
+
" }\n",
|
| 257 |
+
"\n",
|
| 258 |
+
" .dataframe tbody tr th {\n",
|
| 259 |
+
" vertical-align: top;\n",
|
| 260 |
+
" }\n",
|
| 261 |
+
"\n",
|
| 262 |
+
" .dataframe thead th {\n",
|
| 263 |
+
" text-align: right;\n",
|
| 264 |
+
" }\n",
|
| 265 |
+
"</style>\n",
|
| 266 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 267 |
+
" <thead>\n",
|
| 268 |
+
" <tr style=\"text-align: right;\">\n",
|
| 269 |
+
" <th></th>\n",
|
| 270 |
+
" <th>open</th>\n",
|
| 271 |
+
" <th>high</th>\n",
|
| 272 |
+
" <th>low</th>\n",
|
| 273 |
+
" <th>close</th>\n",
|
| 274 |
+
" <th>volume</th>\n",
|
| 275 |
+
" <th>split_ratio</th>\n",
|
| 276 |
+
" <th>dividend</th>\n",
|
| 277 |
+
" <th>capital_gains</th>\n",
|
| 278 |
+
" </tr>\n",
|
| 279 |
+
" <tr>\n",
|
| 280 |
+
" <th>date</th>\n",
|
| 281 |
+
" <th></th>\n",
|
| 282 |
+
" <th></th>\n",
|
| 283 |
+
" <th></th>\n",
|
| 284 |
+
" <th></th>\n",
|
| 285 |
+
" <th></th>\n",
|
| 286 |
+
" <th></th>\n",
|
| 287 |
+
" <th></th>\n",
|
| 288 |
+
" <th></th>\n",
|
| 289 |
+
" </tr>\n",
|
| 290 |
+
" </thead>\n",
|
| 291 |
+
" <tbody>\n",
|
| 292 |
+
" <tr>\n",
|
| 293 |
+
" <th>2024-07-01</th>\n",
|
| 294 |
+
" <td>545.630005</td>\n",
|
| 295 |
+
" <td>565.159973</td>\n",
|
| 296 |
+
" <td>537.450012</td>\n",
|
| 297 |
+
" <td>550.809998</td>\n",
|
| 298 |
+
" <td>1038465500</td>\n",
|
| 299 |
+
" <td>0.0</td>\n",
|
| 300 |
+
" <td>0.0</td>\n",
|
| 301 |
+
" <td>0.0</td>\n",
|
| 302 |
+
" </tr>\n",
|
| 303 |
+
" <tr>\n",
|
| 304 |
+
" <th>2024-08-01</th>\n",
|
| 305 |
+
" <td>552.570007</td>\n",
|
| 306 |
+
" <td>563.150024</td>\n",
|
| 307 |
+
" <td>510.269989</td>\n",
|
| 308 |
+
" <td>556.570007</td>\n",
|
| 309 |
+
" <td>954486073</td>\n",
|
| 310 |
+
" <td>0.0</td>\n",
|
| 311 |
+
" <td>0.0</td>\n",
|
| 312 |
+
" <td>0.0</td>\n",
|
| 313 |
+
" </tr>\n",
|
| 314 |
+
" </tbody>\n",
|
| 315 |
+
"</table>\n",
|
| 316 |
+
"</div>"
|
| 317 |
+
],
|
| 318 |
+
"text/plain": [
|
| 319 |
+
" open high low close volume \\\n",
|
| 320 |
+
"date \n",
|
| 321 |
+
"2024-07-01 545.630005 565.159973 537.450012 550.809998 1038465500 \n",
|
| 322 |
+
"2024-08-01 552.570007 563.150024 510.269989 556.570007 954486073 \n",
|
| 323 |
+
"\n",
|
| 324 |
+
" split_ratio dividend capital_gains \n",
|
| 325 |
+
"date \n",
|
| 326 |
+
"2024-07-01 0.0 0.0 0.0 \n",
|
| 327 |
+
"2024-08-01 0.0 0.0 0.0 "
|
| 328 |
+
]
|
| 329 |
+
},
|
| 330 |
+
"execution_count": 4,
|
| 331 |
+
"metadata": {},
|
| 332 |
+
"output_type": "execute_result"
|
| 333 |
+
}
|
| 334 |
+
],
|
| 335 |
+
"source": [
|
| 336 |
+
"df_monthly = obb.equity.price.historical(\n",
|
| 337 |
+
" \"spy\", start_date=\"1990-01-01\", interval=\"1M\", provider=\"yfinance\"\n",
|
| 338 |
+
").to_df()\n",
|
| 339 |
+
"df_monthly.tail(2)"
|
| 340 |
+
]
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"cell_type": "markdown",
|
| 344 |
+
"metadata": {},
|
| 345 |
+
"source": [
|
| 346 |
+
"#### Resample a Time Series\n",
|
| 347 |
+
"\n",
|
| 348 |
+
"`yfinance` returns the monthly data for the first day of each month. Let's resample it to take from the last, using the daily information captured in the previous cells."
|
| 349 |
+
]
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"cell_type": "code",
|
| 353 |
+
"execution_count": 6,
|
| 354 |
+
"metadata": {},
|
| 355 |
+
"outputs": [
|
| 356 |
+
{
|
| 357 |
+
"data": {
|
| 358 |
+
"text/html": [
|
| 359 |
+
"<div>\n",
|
| 360 |
+
"<style scoped>\n",
|
| 361 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 362 |
+
" vertical-align: middle;\n",
|
| 363 |
+
" }\n",
|
| 364 |
+
"\n",
|
| 365 |
+
" .dataframe tbody tr th {\n",
|
| 366 |
+
" vertical-align: top;\n",
|
| 367 |
+
" }\n",
|
| 368 |
+
"\n",
|
| 369 |
+
" .dataframe thead th {\n",
|
| 370 |
+
" text-align: right;\n",
|
| 371 |
+
" }\n",
|
| 372 |
+
"</style>\n",
|
| 373 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 374 |
+
" <thead>\n",
|
| 375 |
+
" <tr style=\"text-align: right;\">\n",
|
| 376 |
+
" <th></th>\n",
|
| 377 |
+
" <th>open</th>\n",
|
| 378 |
+
" <th>high</th>\n",
|
| 379 |
+
" <th>low</th>\n",
|
| 380 |
+
" <th>close</th>\n",
|
| 381 |
+
" <th>volume</th>\n",
|
| 382 |
+
" </tr>\n",
|
| 383 |
+
" <tr>\n",
|
| 384 |
+
" <th>date</th>\n",
|
| 385 |
+
" <th></th>\n",
|
| 386 |
+
" <th></th>\n",
|
| 387 |
+
" <th></th>\n",
|
| 388 |
+
" <th></th>\n",
|
| 389 |
+
" <th></th>\n",
|
| 390 |
+
" </tr>\n",
|
| 391 |
+
" </thead>\n",
|
| 392 |
+
" <tbody>\n",
|
| 393 |
+
" <tr>\n",
|
| 394 |
+
" <th>1993-01-31</th>\n",
|
| 395 |
+
" <td>43.968750</td>\n",
|
| 396 |
+
" <td>43.968750</td>\n",
|
| 397 |
+
" <td>43.750000</td>\n",
|
| 398 |
+
" <td>43.937500</td>\n",
|
| 399 |
+
" <td>1003200</td>\n",
|
| 400 |
+
" </tr>\n",
|
| 401 |
+
" <tr>\n",
|
| 402 |
+
" <th>1993-02-28</th>\n",
|
| 403 |
+
" <td>43.968750</td>\n",
|
| 404 |
+
" <td>45.125000</td>\n",
|
| 405 |
+
" <td>42.812500</td>\n",
|
| 406 |
+
" <td>44.406250</td>\n",
|
| 407 |
+
" <td>5417600</td>\n",
|
| 408 |
+
" </tr>\n",
|
| 409 |
+
" <tr>\n",
|
| 410 |
+
" <th>1993-03-31</th>\n",
|
| 411 |
+
" <td>44.562500</td>\n",
|
| 412 |
+
" <td>45.843750</td>\n",
|
| 413 |
+
" <td>44.218750</td>\n",
|
| 414 |
+
" <td>45.187500</td>\n",
|
| 415 |
+
" <td>3019200</td>\n",
|
| 416 |
+
" </tr>\n",
|
| 417 |
+
" <tr>\n",
|
| 418 |
+
" <th>1993-04-30</th>\n",
|
| 419 |
+
" <td>45.250000</td>\n",
|
| 420 |
+
" <td>45.250000</td>\n",
|
| 421 |
+
" <td>43.281250</td>\n",
|
| 422 |
+
" <td>44.031250</td>\n",
|
| 423 |
+
" <td>2697200</td>\n",
|
| 424 |
+
" </tr>\n",
|
| 425 |
+
" <tr>\n",
|
| 426 |
+
" <th>1993-05-31</th>\n",
|
| 427 |
+
" <td>44.093750</td>\n",
|
| 428 |
+
" <td>45.656250</td>\n",
|
| 429 |
+
" <td>43.843750</td>\n",
|
| 430 |
+
" <td>45.218750</td>\n",
|
| 431 |
+
" <td>1808000</td>\n",
|
| 432 |
+
" </tr>\n",
|
| 433 |
+
" <tr>\n",
|
| 434 |
+
" <th>...</th>\n",
|
| 435 |
+
" <td>...</td>\n",
|
| 436 |
+
" <td>...</td>\n",
|
| 437 |
+
" <td>...</td>\n",
|
| 438 |
+
" <td>...</td>\n",
|
| 439 |
+
" <td>...</td>\n",
|
| 440 |
+
" </tr>\n",
|
| 441 |
+
" <tr>\n",
|
| 442 |
+
" <th>2024-04-30</th>\n",
|
| 443 |
+
" <td>523.830017</td>\n",
|
| 444 |
+
" <td>524.380005</td>\n",
|
| 445 |
+
" <td>493.859985</td>\n",
|
| 446 |
+
" <td>501.980011</td>\n",
|
| 447 |
+
" <td>1592974000</td>\n",
|
| 448 |
+
" </tr>\n",
|
| 449 |
+
" <tr>\n",
|
| 450 |
+
" <th>2024-05-31</th>\n",
|
| 451 |
+
" <td>501.380005</td>\n",
|
| 452 |
+
" <td>533.070007</td>\n",
|
| 453 |
+
" <td>499.549988</td>\n",
|
| 454 |
+
" <td>527.369995</td>\n",
|
| 455 |
+
" <td>1153264400</td>\n",
|
| 456 |
+
" </tr>\n",
|
| 457 |
+
" <tr>\n",
|
| 458 |
+
" <th>2024-06-30</th>\n",
|
| 459 |
+
" <td>529.020020</td>\n",
|
| 460 |
+
" <td>550.280029</td>\n",
|
| 461 |
+
" <td>522.599976</td>\n",
|
| 462 |
+
" <td>544.219971</td>\n",
|
| 463 |
+
" <td>888923200</td>\n",
|
| 464 |
+
" </tr>\n",
|
| 465 |
+
" <tr>\n",
|
| 466 |
+
" <th>2024-07-31</th>\n",
|
| 467 |
+
" <td>545.630005</td>\n",
|
| 468 |
+
" <td>565.159973</td>\n",
|
| 469 |
+
" <td>537.450012</td>\n",
|
| 470 |
+
" <td>550.809998</td>\n",
|
| 471 |
+
" <td>1038465500</td>\n",
|
| 472 |
+
" </tr>\n",
|
| 473 |
+
" <tr>\n",
|
| 474 |
+
" <th>2024-08-31</th>\n",
|
| 475 |
+
" <td>552.570007</td>\n",
|
| 476 |
+
" <td>563.150024</td>\n",
|
| 477 |
+
" <td>510.269989</td>\n",
|
| 478 |
+
" <td>556.565002</td>\n",
|
| 479 |
+
" <td>954484078</td>\n",
|
| 480 |
+
" </tr>\n",
|
| 481 |
+
" </tbody>\n",
|
| 482 |
+
"</table>\n",
|
| 483 |
+
"<p>380 rows × 5 columns</p>\n",
|
| 484 |
+
"</div>"
|
| 485 |
+
],
|
| 486 |
+
"text/plain": [
|
| 487 |
+
" open high low close volume\n",
|
| 488 |
+
"date \n",
|
| 489 |
+
"1993-01-31 43.968750 43.968750 43.750000 43.937500 1003200\n",
|
| 490 |
+
"1993-02-28 43.968750 45.125000 42.812500 44.406250 5417600\n",
|
| 491 |
+
"1993-03-31 44.562500 45.843750 44.218750 45.187500 3019200\n",
|
| 492 |
+
"1993-04-30 45.250000 45.250000 43.281250 44.031250 2697200\n",
|
| 493 |
+
"1993-05-31 44.093750 45.656250 43.843750 45.218750 1808000\n",
|
| 494 |
+
"... ... ... ... ... ...\n",
|
| 495 |
+
"2024-04-30 523.830017 524.380005 493.859985 501.980011 1592974000\n",
|
| 496 |
+
"2024-05-31 501.380005 533.070007 499.549988 527.369995 1153264400\n",
|
| 497 |
+
"2024-06-30 529.020020 550.280029 522.599976 544.219971 888923200\n",
|
| 498 |
+
"2024-07-31 545.630005 565.159973 537.450012 550.809998 1038465500\n",
|
| 499 |
+
"2024-08-31 552.570007 563.150024 510.269989 556.565002 954484078\n",
|
| 500 |
+
"\n",
|
| 501 |
+
"[380 rows x 5 columns]"
|
| 502 |
+
]
|
| 503 |
+
},
|
| 504 |
+
"execution_count": 6,
|
| 505 |
+
"metadata": {},
|
| 506 |
+
"output_type": "execute_result"
|
| 507 |
+
}
|
| 508 |
+
],
|
| 509 |
+
"source": [
|
| 510 |
+
"df_daily.index = pd.to_datetime(df_daily.index)\n",
|
| 511 |
+
"(\n",
|
| 512 |
+
" df_daily[[\"open\", \"high\", \"low\", \"close\", \"volume\"]]\n",
|
| 513 |
+
" .resample(\"ME\")\n",
|
| 514 |
+
" .agg(\n",
|
| 515 |
+
" {\"open\": \"first\", \"high\": \"max\", \"low\": \"min\", \"close\": \"last\", \"volume\": \"sum\"}\n",
|
| 516 |
+
" )\n",
|
| 517 |
+
")"
|
| 518 |
+
]
|
| 519 |
+
},
|
| 520 |
+
{
|
| 521 |
+
"attachments": {},
|
| 522 |
+
"cell_type": "markdown",
|
| 523 |
+
"metadata": {},
|
| 524 |
+
"source": [
|
| 525 |
+
"The block below packs an object with most intervals."
|
| 526 |
+
]
|
| 527 |
+
},
|
| 528 |
+
{
|
| 529 |
+
"cell_type": "code",
|
| 530 |
+
"execution_count": 8,
|
| 531 |
+
"metadata": {},
|
| 532 |
+
"outputs": [
|
| 533 |
+
{
|
| 534 |
+
"data": {
|
| 535 |
+
"text/plain": [
|
| 536 |
+
"dict_keys(['one', 'five', 'fifteen', 'thirty', 'sixty', 'daily', 'weekly', 'monthly'])"
|
| 537 |
+
]
|
| 538 |
+
},
|
| 539 |
+
"metadata": {},
|
| 540 |
+
"output_type": "display_data"
|
| 541 |
+
},
|
| 542 |
+
{
|
| 543 |
+
"data": {
|
| 544 |
+
"text/html": [
|
| 545 |
+
"<div>\n",
|
| 546 |
+
"<style scoped>\n",
|
| 547 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 548 |
+
" vertical-align: middle;\n",
|
| 549 |
+
" }\n",
|
| 550 |
+
"\n",
|
| 551 |
+
" .dataframe tbody tr th {\n",
|
| 552 |
+
" vertical-align: top;\n",
|
| 553 |
+
" }\n",
|
| 554 |
+
"\n",
|
| 555 |
+
" .dataframe thead th {\n",
|
| 556 |
+
" text-align: right;\n",
|
| 557 |
+
" }\n",
|
| 558 |
+
"</style>\n",
|
| 559 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 560 |
+
" <thead>\n",
|
| 561 |
+
" <tr style=\"text-align: right;\">\n",
|
| 562 |
+
" <th></th>\n",
|
| 563 |
+
" <th>open</th>\n",
|
| 564 |
+
" <th>high</th>\n",
|
| 565 |
+
" <th>low</th>\n",
|
| 566 |
+
" <th>close</th>\n",
|
| 567 |
+
" <th>volume</th>\n",
|
| 568 |
+
" <th>split_ratio</th>\n",
|
| 569 |
+
" <th>dividend</th>\n",
|
| 570 |
+
" <th>capital_gains</th>\n",
|
| 571 |
+
" </tr>\n",
|
| 572 |
+
" <tr>\n",
|
| 573 |
+
" <th>date</th>\n",
|
| 574 |
+
" <th></th>\n",
|
| 575 |
+
" <th></th>\n",
|
| 576 |
+
" <th></th>\n",
|
| 577 |
+
" <th></th>\n",
|
| 578 |
+
" <th></th>\n",
|
| 579 |
+
" <th></th>\n",
|
| 580 |
+
" <th></th>\n",
|
| 581 |
+
" <th></th>\n",
|
| 582 |
+
" </tr>\n",
|
| 583 |
+
" </thead>\n",
|
| 584 |
+
" <tbody>\n",
|
| 585 |
+
" <tr>\n",
|
| 586 |
+
" <th>2024-08-12</th>\n",
|
| 587 |
+
" <td>534.210022</td>\n",
|
| 588 |
+
" <td>555.02002</td>\n",
|
| 589 |
+
" <td>530.950012</td>\n",
|
| 590 |
+
" <td>554.309998</td>\n",
|
| 591 |
+
" <td>242599600</td>\n",
|
| 592 |
+
" <td>0</td>\n",
|
| 593 |
+
" <td>0.0</td>\n",
|
| 594 |
+
" <td>0</td>\n",
|
| 595 |
+
" </tr>\n",
|
| 596 |
+
" <tr>\n",
|
| 597 |
+
" <th>2024-08-19</th>\n",
|
| 598 |
+
" <td>554.72998</td>\n",
|
| 599 |
+
" <td>563.150024</td>\n",
|
| 600 |
+
" <td>553.859985</td>\n",
|
| 601 |
+
" <td>557.031006</td>\n",
|
| 602 |
+
" <td>142159243</td>\n",
|
| 603 |
+
" <td>0</td>\n",
|
| 604 |
+
" <td>0.0</td>\n",
|
| 605 |
+
" <td>0</td>\n",
|
| 606 |
+
" </tr>\n",
|
| 607 |
+
" </tbody>\n",
|
| 608 |
+
"</table>\n",
|
| 609 |
+
"</div>"
|
| 610 |
+
],
|
| 611 |
+
"text/plain": [
|
| 612 |
+
" open high low close volume \\\n",
|
| 613 |
+
"date \n",
|
| 614 |
+
"2024-08-12 534.210022 555.02002 530.950012 554.309998 242599600 \n",
|
| 615 |
+
"2024-08-19 554.72998 563.150024 553.859985 557.031006 142159243 \n",
|
| 616 |
+
"\n",
|
| 617 |
+
" split_ratio dividend capital_gains \n",
|
| 618 |
+
"date \n",
|
| 619 |
+
"2024-08-12 0 0.0 0 \n",
|
| 620 |
+
"2024-08-19 0 0.0 0 "
|
| 621 |
+
]
|
| 622 |
+
},
|
| 623 |
+
"metadata": {},
|
| 624 |
+
"output_type": "display_data"
|
| 625 |
+
},
|
| 626 |
+
{
|
| 627 |
+
"data": {
|
| 628 |
+
"text/html": [
|
| 629 |
+
"<div>\n",
|
| 630 |
+
"<style scoped>\n",
|
| 631 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 632 |
+
" vertical-align: middle;\n",
|
| 633 |
+
" }\n",
|
| 634 |
+
"\n",
|
| 635 |
+
" .dataframe tbody tr th {\n",
|
| 636 |
+
" vertical-align: top;\n",
|
| 637 |
+
" }\n",
|
| 638 |
+
"\n",
|
| 639 |
+
" .dataframe thead th {\n",
|
| 640 |
+
" text-align: right;\n",
|
| 641 |
+
" }\n",
|
| 642 |
+
"</style>\n",
|
| 643 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 644 |
+
" <thead>\n",
|
| 645 |
+
" <tr style=\"text-align: right;\">\n",
|
| 646 |
+
" <th></th>\n",
|
| 647 |
+
" <th>open</th>\n",
|
| 648 |
+
" <th>high</th>\n",
|
| 649 |
+
" <th>low</th>\n",
|
| 650 |
+
" <th>close</th>\n",
|
| 651 |
+
" <th>volume</th>\n",
|
| 652 |
+
" <th>split_ratio</th>\n",
|
| 653 |
+
" <th>dividend</th>\n",
|
| 654 |
+
" <th>capital_gains</th>\n",
|
| 655 |
+
" </tr>\n",
|
| 656 |
+
" <tr>\n",
|
| 657 |
+
" <th>date</th>\n",
|
| 658 |
+
" <th></th>\n",
|
| 659 |
+
" <th></th>\n",
|
| 660 |
+
" <th></th>\n",
|
| 661 |
+
" <th></th>\n",
|
| 662 |
+
" <th></th>\n",
|
| 663 |
+
" <th></th>\n",
|
| 664 |
+
" <th></th>\n",
|
| 665 |
+
" <th></th>\n",
|
| 666 |
+
" </tr>\n",
|
| 667 |
+
" </thead>\n",
|
| 668 |
+
" <tbody>\n",
|
| 669 |
+
" <tr>\n",
|
| 670 |
+
" <th>2024-08-16 09:30:00</th>\n",
|
| 671 |
+
" <td>551.419983</td>\n",
|
| 672 |
+
" <td>551.929993</td>\n",
|
| 673 |
+
" <td>551.289978</td>\n",
|
| 674 |
+
" <td>551.349976</td>\n",
|
| 675 |
+
" <td>1881026</td>\n",
|
| 676 |
+
" <td>0</td>\n",
|
| 677 |
+
" <td>0</td>\n",
|
| 678 |
+
" <td>0</td>\n",
|
| 679 |
+
" </tr>\n",
|
| 680 |
+
" <tr>\n",
|
| 681 |
+
" <th>2024-08-16 09:31:00</th>\n",
|
| 682 |
+
" <td>551.349976</td>\n",
|
| 683 |
+
" <td>551.77002</td>\n",
|
| 684 |
+
" <td>551.26001</td>\n",
|
| 685 |
+
" <td>551.630005</td>\n",
|
| 686 |
+
" <td>230595</td>\n",
|
| 687 |
+
" <td>0</td>\n",
|
| 688 |
+
" <td>0</td>\n",
|
| 689 |
+
" <td>0</td>\n",
|
| 690 |
+
" </tr>\n",
|
| 691 |
+
" </tbody>\n",
|
| 692 |
+
"</table>\n",
|
| 693 |
+
"</div>"
|
| 694 |
+
],
|
| 695 |
+
"text/plain": [
|
| 696 |
+
" open high low close volume \\\n",
|
| 697 |
+
"date \n",
|
| 698 |
+
"2024-08-16 09:30:00 551.419983 551.929993 551.289978 551.349976 1881026 \n",
|
| 699 |
+
"2024-08-16 09:31:00 551.349976 551.77002 551.26001 551.630005 230595 \n",
|
| 700 |
+
"\n",
|
| 701 |
+
" split_ratio dividend capital_gains \n",
|
| 702 |
+
"date \n",
|
| 703 |
+
"2024-08-16 09:30:00 0 0 0 \n",
|
| 704 |
+
"2024-08-16 09:31:00 0 0 0 "
|
| 705 |
+
]
|
| 706 |
+
},
|
| 707 |
+
"metadata": {},
|
| 708 |
+
"output_type": "display_data"
|
| 709 |
+
}
|
| 710 |
+
],
|
| 711 |
+
"source": [
|
| 712 |
+
"class HistoricalPrices:\n",
|
| 713 |
+
" def __init__(self, symbol, start_date, end_date, provider, **kwargs) -> None:\n",
|
| 714 |
+
" self.one: pd.DataFrame = (\n",
|
| 715 |
+
" obb.equity.price.historical(\n",
|
| 716 |
+
" symbol=symbol,\n",
|
| 717 |
+
" start_date=start_date,\n",
|
| 718 |
+
" end_date=end_date,\n",
|
| 719 |
+
" interval=\"1m\",\n",
|
| 720 |
+
" provider=provider,\n",
|
| 721 |
+
" **kwargs\n",
|
| 722 |
+
" )\n",
|
| 723 |
+
" .to_df()\n",
|
| 724 |
+
" .convert_dtypes()\n",
|
| 725 |
+
" )\n",
|
| 726 |
+
" self.five: pd.DataFrame = (\n",
|
| 727 |
+
" obb.equity.price.historical(\n",
|
| 728 |
+
" symbol=symbol,\n",
|
| 729 |
+
" start_date=start_date,\n",
|
| 730 |
+
" end_date=end_date,\n",
|
| 731 |
+
" interval=\"5m\",\n",
|
| 732 |
+
" provider=provider,\n",
|
| 733 |
+
" **kwargs\n",
|
| 734 |
+
" )\n",
|
| 735 |
+
" .to_df()\n",
|
| 736 |
+
" .convert_dtypes()\n",
|
| 737 |
+
" )\n",
|
| 738 |
+
" self.fifteen: pd.DataFrame = (\n",
|
| 739 |
+
" obb.equity.price.historical(\n",
|
| 740 |
+
" symbol=symbol,\n",
|
| 741 |
+
" start_date=start_date,\n",
|
| 742 |
+
" end_date=end_date,\n",
|
| 743 |
+
" interval=\"15m\",\n",
|
| 744 |
+
" provider=provider,\n",
|
| 745 |
+
" **kwargs\n",
|
| 746 |
+
" )\n",
|
| 747 |
+
" .to_df()\n",
|
| 748 |
+
" .convert_dtypes()\n",
|
| 749 |
+
" )\n",
|
| 750 |
+
" self.thirty: pd.DataFrame = (\n",
|
| 751 |
+
" obb.equity.price.historical(\n",
|
| 752 |
+
" symbol=symbol,\n",
|
| 753 |
+
" start_date=start_date,\n",
|
| 754 |
+
" end_date=end_date,\n",
|
| 755 |
+
" interval=\"30m\",\n",
|
| 756 |
+
" provider=provider,\n",
|
| 757 |
+
" **kwargs\n",
|
| 758 |
+
" )\n",
|
| 759 |
+
" .to_df()\n",
|
| 760 |
+
" .convert_dtypes()\n",
|
| 761 |
+
" )\n",
|
| 762 |
+
" self.sixty: pd.DataFrame = (\n",
|
| 763 |
+
" obb.equity.price.historical(\n",
|
| 764 |
+
" symbol=symbol,\n",
|
| 765 |
+
" start_date=start_date,\n",
|
| 766 |
+
" end_date=end_date,\n",
|
| 767 |
+
" interval=\"60m\",\n",
|
| 768 |
+
" provider=provider,\n",
|
| 769 |
+
" **kwargs\n",
|
| 770 |
+
" )\n",
|
| 771 |
+
" .to_df()\n",
|
| 772 |
+
" .convert_dtypes()\n",
|
| 773 |
+
" )\n",
|
| 774 |
+
" self.daily: pd.DataFrame = (\n",
|
| 775 |
+
" obb.equity.price.historical(\n",
|
| 776 |
+
" symbol=symbol,\n",
|
| 777 |
+
" start_date=start_date,\n",
|
| 778 |
+
" end_date=end_date,\n",
|
| 779 |
+
" interval=\"1d\",\n",
|
| 780 |
+
" provider=provider,\n",
|
| 781 |
+
" **kwargs\n",
|
| 782 |
+
" )\n",
|
| 783 |
+
" .to_df()\n",
|
| 784 |
+
" .convert_dtypes()\n",
|
| 785 |
+
" )\n",
|
| 786 |
+
" self.weekly: pd.DataFrame = (\n",
|
| 787 |
+
" obb.equity.price.historical(\n",
|
| 788 |
+
" symbol=symbol,\n",
|
| 789 |
+
" start_date=start_date,\n",
|
| 790 |
+
" end_date=end_date,\n",
|
| 791 |
+
" interval=\"1W\",\n",
|
| 792 |
+
" provider=provider,\n",
|
| 793 |
+
" **kwargs\n",
|
| 794 |
+
" )\n",
|
| 795 |
+
" .to_df()\n",
|
| 796 |
+
" .convert_dtypes()\n",
|
| 797 |
+
" )\n",
|
| 798 |
+
" self.monthly: pd.DataFrame = (\n",
|
| 799 |
+
" obb.equity.price.historical(\n",
|
| 800 |
+
" symbol=symbol,\n",
|
| 801 |
+
" start_date=start_date,\n",
|
| 802 |
+
" end_date=end_date,\n",
|
| 803 |
+
" interval=\"1M\",\n",
|
| 804 |
+
" provider=provider,\n",
|
| 805 |
+
" **kwargs\n",
|
| 806 |
+
" )\n",
|
| 807 |
+
" .to_df()\n",
|
| 808 |
+
" .convert_dtypes()\n",
|
| 809 |
+
" )\n",
|
| 810 |
+
"\n",
|
| 811 |
+
"\n",
|
| 812 |
+
"def load_historical(\n",
|
| 813 |
+
" symbol: str = \"\", start_date=None, end_date=None, provider=None, **kwargs\n",
|
| 814 |
+
") -> HistoricalPrices:\n",
|
| 815 |
+
"\n",
|
| 816 |
+
" if symbol == \"\":\n",
|
| 817 |
+
" display(\"Please enter a ticker symbol\")\n",
|
| 818 |
+
" if provider is None:\n",
|
| 819 |
+
" provider = \"yfinance\"\n",
|
| 820 |
+
" prices = HistoricalPrices(symbol, start_date, end_date, provider, **kwargs)\n",
|
| 821 |
+
"\n",
|
| 822 |
+
" return prices\n",
|
| 823 |
+
"\n",
|
| 824 |
+
"\n",
|
| 825 |
+
"prices = load_historical(\"spy\")\n",
|
| 826 |
+
"display(prices.__dict__.keys())\n",
|
| 827 |
+
"display(prices.weekly.tail(2))\n",
|
| 828 |
+
"\n",
|
| 829 |
+
"display(prices.one.head(2))"
|
| 830 |
+
]
|
| 831 |
+
},
|
| 832 |
+
{
|
| 833 |
+
"attachments": {},
|
| 834 |
+
"cell_type": "markdown",
|
| 835 |
+
"metadata": {},
|
| 836 |
+
"source": [
|
| 837 |
+
"To demonstrate the difference between sources, let's compare values for daily volume from several sources."
|
| 838 |
+
]
|
| 839 |
+
},
|
| 840 |
+
{
|
| 841 |
+
"cell_type": "code",
|
| 842 |
+
"execution_count": 11,
|
| 843 |
+
"metadata": {},
|
| 844 |
+
"outputs": [
|
| 845 |
+
{
|
| 846 |
+
"data": {
|
| 847 |
+
"text/html": [
|
| 848 |
+
"<div>\n",
|
| 849 |
+
"<style scoped>\n",
|
| 850 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 851 |
+
" vertical-align: middle;\n",
|
| 852 |
+
" }\n",
|
| 853 |
+
"\n",
|
| 854 |
+
" .dataframe tbody tr th {\n",
|
| 855 |
+
" vertical-align: top;\n",
|
| 856 |
+
" }\n",
|
| 857 |
+
"\n",
|
| 858 |
+
" .dataframe thead th {\n",
|
| 859 |
+
" text-align: right;\n",
|
| 860 |
+
" }\n",
|
| 861 |
+
"</style>\n",
|
| 862 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 863 |
+
" <thead>\n",
|
| 864 |
+
" <tr style=\"text-align: right;\">\n",
|
| 865 |
+
" <th></th>\n",
|
| 866 |
+
" <th>AV Volume</th>\n",
|
| 867 |
+
" <th>FMP Volume</th>\n",
|
| 868 |
+
" <th>Intrinio Volume</th>\n",
|
| 869 |
+
" <th>Yahoo Volume</th>\n",
|
| 870 |
+
" <th>Polygon Volume</th>\n",
|
| 871 |
+
" </tr>\n",
|
| 872 |
+
" <tr>\n",
|
| 873 |
+
" <th>date</th>\n",
|
| 874 |
+
" <th></th>\n",
|
| 875 |
+
" <th></th>\n",
|
| 876 |
+
" <th></th>\n",
|
| 877 |
+
" <th></th>\n",
|
| 878 |
+
" <th></th>\n",
|
| 879 |
+
" </tr>\n",
|
| 880 |
+
" </thead>\n",
|
| 881 |
+
" <tbody>\n",
|
| 882 |
+
" <tr>\n",
|
| 883 |
+
" <th>2024-08-09</th>\n",
|
| 884 |
+
" <td>45619558</td>\n",
|
| 885 |
+
" <td>45619558.0</td>\n",
|
| 886 |
+
" <td>45619558.0</td>\n",
|
| 887 |
+
" <td>45619600.0</td>\n",
|
| 888 |
+
" <td>45425963.0</td>\n",
|
| 889 |
+
" </tr>\n",
|
| 890 |
+
" <tr>\n",
|
| 891 |
+
" <th>2024-08-12</th>\n",
|
| 892 |
+
" <td>42542069</td>\n",
|
| 893 |
+
" <td>42542069.0</td>\n",
|
| 894 |
+
" <td>42542069.0</td>\n",
|
| 895 |
+
" <td>42542100.0</td>\n",
|
| 896 |
+
" <td>42533175.0</td>\n",
|
| 897 |
+
" </tr>\n",
|
| 898 |
+
" <tr>\n",
|
| 899 |
+
" <th>2024-08-13</th>\n",
|
| 900 |
+
" <td>52333073</td>\n",
|
| 901 |
+
" <td>52333073.0</td>\n",
|
| 902 |
+
" <td>52333073.0</td>\n",
|
| 903 |
+
" <td>52333100.0</td>\n",
|
| 904 |
+
" <td>50110167.0</td>\n",
|
| 905 |
+
" </tr>\n",
|
| 906 |
+
" <tr>\n",
|
| 907 |
+
" <th>2024-08-14</th>\n",
|
| 908 |
+
" <td>42446929</td>\n",
|
| 909 |
+
" <td>42446929.0</td>\n",
|
| 910 |
+
" <td>42446929.0</td>\n",
|
| 911 |
+
" <td>42446900.0</td>\n",
|
| 912 |
+
" <td>42362522.0</td>\n",
|
| 913 |
+
" </tr>\n",
|
| 914 |
+
" <tr>\n",
|
| 915 |
+
" <th>2024-08-15</th>\n",
|
| 916 |
+
" <td>60846812</td>\n",
|
| 917 |
+
" <td>60846812.0</td>\n",
|
| 918 |
+
" <td>60846812.0</td>\n",
|
| 919 |
+
" <td>60846800.0</td>\n",
|
| 920 |
+
" <td>60762738.0</td>\n",
|
| 921 |
+
" </tr>\n",
|
| 922 |
+
" <tr>\n",
|
| 923 |
+
" <th>2024-08-16</th>\n",
|
| 924 |
+
" <td>44430728</td>\n",
|
| 925 |
+
" <td>44430728.0</td>\n",
|
| 926 |
+
" <td>44430728.0</td>\n",
|
| 927 |
+
" <td>44430700.0</td>\n",
|
| 928 |
+
" <td>44368969.0</td>\n",
|
| 929 |
+
" </tr>\n",
|
| 930 |
+
" <tr>\n",
|
| 931 |
+
" <th>2024-08-19</th>\n",
|
| 932 |
+
" <td>39121793</td>\n",
|
| 933 |
+
" <td>39121793.0</td>\n",
|
| 934 |
+
" <td>39121793.0</td>\n",
|
| 935 |
+
" <td>39121800.0</td>\n",
|
| 936 |
+
" <td>38648958.0</td>\n",
|
| 937 |
+
" </tr>\n",
|
| 938 |
+
" <tr>\n",
|
| 939 |
+
" <th>2024-08-20</th>\n",
|
| 940 |
+
" <td>33732264</td>\n",
|
| 941 |
+
" <td>33732264.0</td>\n",
|
| 942 |
+
" <td>33732264.0</td>\n",
|
| 943 |
+
" <td>33732300.0</td>\n",
|
| 944 |
+
" <td>33693989.0</td>\n",
|
| 945 |
+
" </tr>\n",
|
| 946 |
+
" <tr>\n",
|
| 947 |
+
" <th>2024-08-21</th>\n",
|
| 948 |
+
" <td>41514600</td>\n",
|
| 949 |
+
" <td>38682509.0</td>\n",
|
| 950 |
+
" <td>41514600.0</td>\n",
|
| 951 |
+
" <td>41467000.0</td>\n",
|
| 952 |
+
" <td>41532360.0</td>\n",
|
| 953 |
+
" </tr>\n",
|
| 954 |
+
" </tbody>\n",
|
| 955 |
+
"</table>\n",
|
| 956 |
+
"</div>"
|
| 957 |
+
],
|
| 958 |
+
"text/plain": [
|
| 959 |
+
" AV Volume FMP Volume Intrinio Volume Yahoo Volume \\\n",
|
| 960 |
+
"date \n",
|
| 961 |
+
"2024-08-09 45619558 45619558.0 45619558.0 45619600.0 \n",
|
| 962 |
+
"2024-08-12 42542069 42542069.0 42542069.0 42542100.0 \n",
|
| 963 |
+
"2024-08-13 52333073 52333073.0 52333073.0 52333100.0 \n",
|
| 964 |
+
"2024-08-14 42446929 42446929.0 42446929.0 42446900.0 \n",
|
| 965 |
+
"2024-08-15 60846812 60846812.0 60846812.0 60846800.0 \n",
|
| 966 |
+
"2024-08-16 44430728 44430728.0 44430728.0 44430700.0 \n",
|
| 967 |
+
"2024-08-19 39121793 39121793.0 39121793.0 39121800.0 \n",
|
| 968 |
+
"2024-08-20 33732264 33732264.0 33732264.0 33732300.0 \n",
|
| 969 |
+
"2024-08-21 41514600 38682509.0 41514600.0 41467000.0 \n",
|
| 970 |
+
"\n",
|
| 971 |
+
" Polygon Volume \n",
|
| 972 |
+
"date \n",
|
| 973 |
+
"2024-08-09 45425963.0 \n",
|
| 974 |
+
"2024-08-12 42533175.0 \n",
|
| 975 |
+
"2024-08-13 50110167.0 \n",
|
| 976 |
+
"2024-08-14 42362522.0 \n",
|
| 977 |
+
"2024-08-15 60762738.0 \n",
|
| 978 |
+
"2024-08-16 44368969.0 \n",
|
| 979 |
+
"2024-08-19 38648958.0 \n",
|
| 980 |
+
"2024-08-20 33693989.0 \n",
|
| 981 |
+
"2024-08-21 41532360.0 "
|
| 982 |
+
]
|
| 983 |
+
},
|
| 984 |
+
"execution_count": 11,
|
| 985 |
+
"metadata": {},
|
| 986 |
+
"output_type": "execute_result"
|
| 987 |
+
}
|
| 988 |
+
],
|
| 989 |
+
"source": [
|
| 990 |
+
"# Collect the data\n",
|
| 991 |
+
"\n",
|
| 992 |
+
"yahoo = obb.equity.price.historical(\"spy\", provider=\"yfinance\").to_df()\n",
|
| 993 |
+
"alphavantage = obb.equity.price.historical(\"spy\", provider=\"alpha_vantage\").to_df()\n",
|
| 994 |
+
"intrinio = obb.equity.price.historical(\"spy\", provider=\"intrinio\").to_df()\n",
|
| 995 |
+
"fmp = obb.equity.price.historical(\"spy\", provider=\"fmp\").to_df()\n",
|
| 996 |
+
"polygon = obb.equity.price.historical(\"spy\", provider=\"polygon\").to_df()\n",
|
| 997 |
+
"\n",
|
| 998 |
+
"# Make a new DataFrame with just the volume columns\n",
|
| 999 |
+
"compare = pd.DataFrame()\n",
|
| 1000 |
+
"compare[\"AV Volume\"] = alphavantage[\"volume\"].tail(10)\n",
|
| 1001 |
+
"compare[\"FMP Volume\"] = fmp[\"volume\"].tail(10)\n",
|
| 1002 |
+
"compare[\"Intrinio Volume\"] = intrinio[\"volume\"].tail(10)\n",
|
| 1003 |
+
"compare[\"Yahoo Volume\"] = yahoo[\"volume\"].tail(10)\n",
|
| 1004 |
+
"compare[\"Polygon Volume\"] = polygon[\"volume\"].tail(10)\n",
|
| 1005 |
+
"\n",
|
| 1006 |
+
"compare.dropna(how=\"any\")"
|
| 1007 |
+
]
|
| 1008 |
+
},
|
| 1009 |
+
{
|
| 1010 |
+
"attachments": {},
|
| 1011 |
+
"cell_type": "markdown",
|
| 1012 |
+
"metadata": {},
|
| 1013 |
+
"source": [
|
| 1014 |
+
"## Other Types of Symbols\n",
|
| 1015 |
+
"\n",
|
| 1016 |
+
"Other types of assets and ticker symbols can be loaded from `obb.equity.price.historical()`, below are some examples but not an exhaustive list.\n",
|
| 1017 |
+
"\n",
|
| 1018 |
+
"### Share Classes\n",
|
| 1019 |
+
"\n",
|
| 1020 |
+
"Some sources use `-` as the distinction between a share class, e.g., `BRK-A` and `BRK-B`. Other formats include:\n",
|
| 1021 |
+
"\n",
|
| 1022 |
+
"- A period: `BRK.A`\n",
|
| 1023 |
+
"- A slash: `BRK/A`\n",
|
| 1024 |
+
"- No separator, the share class becomes the fourth or fifth letter.\n",
|
| 1025 |
+
"\n",
|
| 1026 |
+
"```python\n",
|
| 1027 |
+
"obb.equity.price.historical(\"brk.b\", provider=\"polygon\")\n",
|
| 1028 |
+
"```\n",
|
| 1029 |
+
"\n",
|
| 1030 |
+
"```python\n",
|
| 1031 |
+
"obb.equity.price.historical(\"brk-b\", provider=\"fmp\")\n",
|
| 1032 |
+
"```\n",
|
| 1033 |
+
"\n",
|
| 1034 |
+
"While some providers handle the different formats on their end, others do not. This is something to consider when no results are returned from one source. Some may even use a combination, or accept multiple variations. Sometimes there is no real logic behind the additional characters, `GOOGL` vs. `GOOG`. These are known unknown variables of ticker symbology, what's good for one source may return errors from another. \n",
|
| 1035 |
+
"\n",
|
| 1036 |
+
"### Regional Identifiers\n",
|
| 1037 |
+
"\n",
|
| 1038 |
+
"With providers supporting market data from multiple jurisdictions, the most common method for requesting data outside of US-listings is to append a suffix to the ticker symbol (e.g., `RELIANCE.NS` for Indian equities). Formats may be unique to a provider, so it is best to review the source's documentation for an overview of their specific conventions. [This page](https://help.yahoo.com/kb/SLN2310.html) on Yahoo describes how they format symbols, which many others follow to some degree.\n",
|
| 1039 |
+
"\n",
|
| 1040 |
+
"### Indexes\n",
|
| 1041 |
+
"\n",
|
| 1042 |
+
"Sources will have their own treatment of these symbols, some examples are:\n",
|
| 1043 |
+
"\n",
|
| 1044 |
+
"- YahooFinance/FMP/CBOE: ^RUT\n",
|
| 1045 |
+
"- Polygon: I:NDX\n",
|
| 1046 |
+
"\n",
|
| 1047 |
+
"### Currencies\n",
|
| 1048 |
+
"\n",
|
| 1049 |
+
"FX symbols face the same dilemna as share classes, there are several variations of the same symbol.\n",
|
| 1050 |
+
"\n",
|
| 1051 |
+
"- YahooFinance: `EURUSD=X`\n",
|
| 1052 |
+
"- Polygon: `C:EURUSD`\n",
|
| 1053 |
+
"- AlphaVantage/FMP: `EURUSD`\n",
|
| 1054 |
+
"\n",
|
| 1055 |
+
"**The symbol prefixes are handled internally when `obb.currency.price.historical()` is used to enter a pair with no extra characters.**\n",
|
| 1056 |
+
"\n",
|
| 1057 |
+
"### Crypto\n",
|
| 1058 |
+
"\n",
|
| 1059 |
+
"Similar, but different to FX tickers.\n",
|
| 1060 |
+
"\n",
|
| 1061 |
+
"- YahooFinance: `BTC-USD`\n",
|
| 1062 |
+
"- Polygon: `X:BTCUSD`\n",
|
| 1063 |
+
"- AlphaVantage/FMP: `BTCUSD`\n",
|
| 1064 |
+
"\n",
|
| 1065 |
+
"**The symbol prefixes are handled internally when `obb.crypto.price.historical()` is used to enter a pair with no extra characters and placing the fiat currency second.**\n",
|
| 1066 |
+
"\n",
|
| 1067 |
+
"### Futures\n",
|
| 1068 |
+
"\n",
|
| 1069 |
+
"Historical prices for active contracts, and the continuation chart, can be fetched via `yfinance`.\n",
|
| 1070 |
+
"\n",
|
| 1071 |
+
"- Continuous front-month: `CL=F`\n",
|
| 1072 |
+
"- December 2023 contract: `CLZ24.NYM`\n",
|
| 1073 |
+
"- March 2024 contract: `CLH24.NYM`\n",
|
| 1074 |
+
"\n",
|
| 1075 |
+
"Individual contracts will require knowing which of the CME venues the future is listed on. `[\"NYM\", \"NYB\", \"CME\", \"CBT\"]`.\n",
|
| 1076 |
+
"\n",
|
| 1077 |
+
"### Options\n",
|
| 1078 |
+
"\n",
|
| 1079 |
+
"Individual options contracts are also loadable from `openbb.equity.price.historical()`.\n",
|
| 1080 |
+
"\n",
|
| 1081 |
+
"- YahooFinance: `SPY241220P00400000`\n",
|
| 1082 |
+
"- Polygon: `O:SPY241220P00400000`"
|
| 1083 |
+
]
|
| 1084 |
+
},
|
| 1085 |
+
{
|
| 1086 |
+
"attachments": {},
|
| 1087 |
+
"cell_type": "markdown",
|
| 1088 |
+
"metadata": {},
|
| 1089 |
+
"source": [
|
| 1090 |
+
"These examples represent only a few methods for fetching historical price data. Explore the contents of each module to find more!"
|
| 1091 |
+
]
|
| 1092 |
+
},
|
| 1093 |
+
{
|
| 1094 |
+
"cell_type": "code",
|
| 1095 |
+
"execution_count": 13,
|
| 1096 |
+
"metadata": {},
|
| 1097 |
+
"outputs": [
|
| 1098 |
+
{
|
| 1099 |
+
"data": {
|
| 1100 |
+
"text/html": [
|
| 1101 |
+
"<div>\n",
|
| 1102 |
+
"<style scoped>\n",
|
| 1103 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1104 |
+
" vertical-align: middle;\n",
|
| 1105 |
+
" }\n",
|
| 1106 |
+
"\n",
|
| 1107 |
+
" .dataframe tbody tr th {\n",
|
| 1108 |
+
" vertical-align: top;\n",
|
| 1109 |
+
" }\n",
|
| 1110 |
+
"\n",
|
| 1111 |
+
" .dataframe thead th {\n",
|
| 1112 |
+
" text-align: right;\n",
|
| 1113 |
+
" }\n",
|
| 1114 |
+
"</style>\n",
|
| 1115 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1116 |
+
" <thead>\n",
|
| 1117 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1118 |
+
" <th></th>\n",
|
| 1119 |
+
" <th>open</th>\n",
|
| 1120 |
+
" <th>high</th>\n",
|
| 1121 |
+
" <th>low</th>\n",
|
| 1122 |
+
" <th>close</th>\n",
|
| 1123 |
+
" <th>volume</th>\n",
|
| 1124 |
+
" <th>split_ratio</th>\n",
|
| 1125 |
+
" <th>dividend</th>\n",
|
| 1126 |
+
" </tr>\n",
|
| 1127 |
+
" <tr>\n",
|
| 1128 |
+
" <th>date</th>\n",
|
| 1129 |
+
" <th></th>\n",
|
| 1130 |
+
" <th></th>\n",
|
| 1131 |
+
" <th></th>\n",
|
| 1132 |
+
" <th></th>\n",
|
| 1133 |
+
" <th></th>\n",
|
| 1134 |
+
" <th></th>\n",
|
| 1135 |
+
" <th></th>\n",
|
| 1136 |
+
" </tr>\n",
|
| 1137 |
+
" </thead>\n",
|
| 1138 |
+
" <tbody>\n",
|
| 1139 |
+
" <tr>\n",
|
| 1140 |
+
" <th>2023-08-22</th>\n",
|
| 1141 |
+
" <td>25.10</td>\n",
|
| 1142 |
+
" <td>25.100000</td>\n",
|
| 1143 |
+
" <td>25.10</td>\n",
|
| 1144 |
+
" <td>25.100000</td>\n",
|
| 1145 |
+
" <td>11</td>\n",
|
| 1146 |
+
" <td>0.0</td>\n",
|
| 1147 |
+
" <td>0.0</td>\n",
|
| 1148 |
+
" </tr>\n",
|
| 1149 |
+
" <tr>\n",
|
| 1150 |
+
" <th>2023-08-23</th>\n",
|
| 1151 |
+
" <td>25.00</td>\n",
|
| 1152 |
+
" <td>25.000000</td>\n",
|
| 1153 |
+
" <td>24.50</td>\n",
|
| 1154 |
+
" <td>24.500000</td>\n",
|
| 1155 |
+
" <td>2</td>\n",
|
| 1156 |
+
" <td>0.0</td>\n",
|
| 1157 |
+
" <td>0.0</td>\n",
|
| 1158 |
+
" </tr>\n",
|
| 1159 |
+
" <tr>\n",
|
| 1160 |
+
" <th>2023-08-24</th>\n",
|
| 1161 |
+
" <td>25.00</td>\n",
|
| 1162 |
+
" <td>25.200001</td>\n",
|
| 1163 |
+
" <td>25.00</td>\n",
|
| 1164 |
+
" <td>25.200001</td>\n",
|
| 1165 |
+
" <td>2</td>\n",
|
| 1166 |
+
" <td>0.0</td>\n",
|
| 1167 |
+
" <td>0.0</td>\n",
|
| 1168 |
+
" </tr>\n",
|
| 1169 |
+
" <tr>\n",
|
| 1170 |
+
" <th>2023-08-25</th>\n",
|
| 1171 |
+
" <td>25.35</td>\n",
|
| 1172 |
+
" <td>25.350000</td>\n",
|
| 1173 |
+
" <td>24.18</td>\n",
|
| 1174 |
+
" <td>24.549999</td>\n",
|
| 1175 |
+
" <td>0</td>\n",
|
| 1176 |
+
" <td>0.0</td>\n",
|
| 1177 |
+
" <td>0.0</td>\n",
|
| 1178 |
+
" </tr>\n",
|
| 1179 |
+
" <tr>\n",
|
| 1180 |
+
" <th>2023-08-29</th>\n",
|
| 1181 |
+
" <td>24.00</td>\n",
|
| 1182 |
+
" <td>24.700001</td>\n",
|
| 1183 |
+
" <td>22.50</td>\n",
|
| 1184 |
+
" <td>23.910000</td>\n",
|
| 1185 |
+
" <td>0</td>\n",
|
| 1186 |
+
" <td>0.0</td>\n",
|
| 1187 |
+
" <td>0.0</td>\n",
|
| 1188 |
+
" </tr>\n",
|
| 1189 |
+
" <tr>\n",
|
| 1190 |
+
" <th>...</th>\n",
|
| 1191 |
+
" <td>...</td>\n",
|
| 1192 |
+
" <td>...</td>\n",
|
| 1193 |
+
" <td>...</td>\n",
|
| 1194 |
+
" <td>...</td>\n",
|
| 1195 |
+
" <td>...</td>\n",
|
| 1196 |
+
" <td>...</td>\n",
|
| 1197 |
+
" <td>...</td>\n",
|
| 1198 |
+
" </tr>\n",
|
| 1199 |
+
" <tr>\n",
|
| 1200 |
+
" <th>2024-08-16</th>\n",
|
| 1201 |
+
" <td>5.95</td>\n",
|
| 1202 |
+
" <td>6.100000</td>\n",
|
| 1203 |
+
" <td>5.95</td>\n",
|
| 1204 |
+
" <td>5.990000</td>\n",
|
| 1205 |
+
" <td>4</td>\n",
|
| 1206 |
+
" <td>0.0</td>\n",
|
| 1207 |
+
" <td>0.0</td>\n",
|
| 1208 |
+
" </tr>\n",
|
| 1209 |
+
" <tr>\n",
|
| 1210 |
+
" <th>2024-08-19</th>\n",
|
| 1211 |
+
" <td>5.92</td>\n",
|
| 1212 |
+
" <td>5.920000</td>\n",
|
| 1213 |
+
" <td>5.71</td>\n",
|
| 1214 |
+
" <td>5.710000</td>\n",
|
| 1215 |
+
" <td>40</td>\n",
|
| 1216 |
+
" <td>0.0</td>\n",
|
| 1217 |
+
" <td>0.0</td>\n",
|
| 1218 |
+
" </tr>\n",
|
| 1219 |
+
" <tr>\n",
|
| 1220 |
+
" <th>2024-08-20</th>\n",
|
| 1221 |
+
" <td>5.73</td>\n",
|
| 1222 |
+
" <td>6.240000</td>\n",
|
| 1223 |
+
" <td>5.73</td>\n",
|
| 1224 |
+
" <td>6.240000</td>\n",
|
| 1225 |
+
" <td>42</td>\n",
|
| 1226 |
+
" <td>0.0</td>\n",
|
| 1227 |
+
" <td>0.0</td>\n",
|
| 1228 |
+
" </tr>\n",
|
| 1229 |
+
" <tr>\n",
|
| 1230 |
+
" <th>2024-08-21</th>\n",
|
| 1231 |
+
" <td>6.28</td>\n",
|
| 1232 |
+
" <td>6.660000</td>\n",
|
| 1233 |
+
" <td>6.28</td>\n",
|
| 1234 |
+
" <td>6.440000</td>\n",
|
| 1235 |
+
" <td>276</td>\n",
|
| 1236 |
+
" <td>0.0</td>\n",
|
| 1237 |
+
" <td>0.0</td>\n",
|
| 1238 |
+
" </tr>\n",
|
| 1239 |
+
" <tr>\n",
|
| 1240 |
+
" <th>2024-08-22</th>\n",
|
| 1241 |
+
" <td>6.29</td>\n",
|
| 1242 |
+
" <td>6.660000</td>\n",
|
| 1243 |
+
" <td>6.29</td>\n",
|
| 1244 |
+
" <td>6.660000</td>\n",
|
| 1245 |
+
" <td>4</td>\n",
|
| 1246 |
+
" <td>0.0</td>\n",
|
| 1247 |
+
" <td>0.0</td>\n",
|
| 1248 |
+
" </tr>\n",
|
| 1249 |
+
" </tbody>\n",
|
| 1250 |
+
"</table>\n",
|
| 1251 |
+
"<p>234 rows × 7 columns</p>\n",
|
| 1252 |
+
"</div>"
|
| 1253 |
+
],
|
| 1254 |
+
"text/plain": [
|
| 1255 |
+
" open high low close volume split_ratio dividend\n",
|
| 1256 |
+
"date \n",
|
| 1257 |
+
"2023-08-22 25.10 25.100000 25.10 25.100000 11 0.0 0.0\n",
|
| 1258 |
+
"2023-08-23 25.00 25.000000 24.50 24.500000 2 0.0 0.0\n",
|
| 1259 |
+
"2023-08-24 25.00 25.200001 25.00 25.200001 2 0.0 0.0\n",
|
| 1260 |
+
"2023-08-25 25.35 25.350000 24.18 24.549999 0 0.0 0.0\n",
|
| 1261 |
+
"2023-08-29 24.00 24.700001 22.50 23.910000 0 0.0 0.0\n",
|
| 1262 |
+
"... ... ... ... ... ... ... ...\n",
|
| 1263 |
+
"2024-08-16 5.95 6.100000 5.95 5.990000 4 0.0 0.0\n",
|
| 1264 |
+
"2024-08-19 5.92 5.920000 5.71 5.710000 40 0.0 0.0\n",
|
| 1265 |
+
"2024-08-20 5.73 6.240000 5.73 6.240000 42 0.0 0.0\n",
|
| 1266 |
+
"2024-08-21 6.28 6.660000 6.28 6.440000 276 0.0 0.0\n",
|
| 1267 |
+
"2024-08-22 6.29 6.660000 6.29 6.660000 4 0.0 0.0\n",
|
| 1268 |
+
"\n",
|
| 1269 |
+
"[234 rows x 7 columns]"
|
| 1270 |
+
]
|
| 1271 |
+
},
|
| 1272 |
+
"execution_count": 13,
|
| 1273 |
+
"metadata": {},
|
| 1274 |
+
"output_type": "execute_result"
|
| 1275 |
+
}
|
| 1276 |
+
],
|
| 1277 |
+
"source": [
|
| 1278 |
+
"obb.equity.price.historical(\"SPY251219P00400000\", provider=\"yfinance\").to_df()"
|
| 1279 |
+
]
|
| 1280 |
+
},
|
| 1281 |
+
{
|
| 1282 |
+
"cell_type": "code",
|
| 1283 |
+
"execution_count": 16,
|
| 1284 |
+
"metadata": {},
|
| 1285 |
+
"outputs": [
|
| 1286 |
+
{
|
| 1287 |
+
"data": {
|
| 1288 |
+
"text/html": [
|
| 1289 |
+
"<div>\n",
|
| 1290 |
+
"<style scoped>\n",
|
| 1291 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1292 |
+
" vertical-align: middle;\n",
|
| 1293 |
+
" }\n",
|
| 1294 |
+
"\n",
|
| 1295 |
+
" .dataframe tbody tr th {\n",
|
| 1296 |
+
" vertical-align: top;\n",
|
| 1297 |
+
" }\n",
|
| 1298 |
+
"\n",
|
| 1299 |
+
" .dataframe thead th {\n",
|
| 1300 |
+
" text-align: right;\n",
|
| 1301 |
+
" }\n",
|
| 1302 |
+
"</style>\n",
|
| 1303 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1304 |
+
" <thead>\n",
|
| 1305 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1306 |
+
" <th></th>\n",
|
| 1307 |
+
" <th>open</th>\n",
|
| 1308 |
+
" <th>high</th>\n",
|
| 1309 |
+
" <th>low</th>\n",
|
| 1310 |
+
" <th>close</th>\n",
|
| 1311 |
+
" <th>volume</th>\n",
|
| 1312 |
+
" </tr>\n",
|
| 1313 |
+
" <tr>\n",
|
| 1314 |
+
" <th>date</th>\n",
|
| 1315 |
+
" <th></th>\n",
|
| 1316 |
+
" <th></th>\n",
|
| 1317 |
+
" <th></th>\n",
|
| 1318 |
+
" <th></th>\n",
|
| 1319 |
+
" <th></th>\n",
|
| 1320 |
+
" </tr>\n",
|
| 1321 |
+
" </thead>\n",
|
| 1322 |
+
" <tbody>\n",
|
| 1323 |
+
" <tr>\n",
|
| 1324 |
+
" <th>1978-01-03</th>\n",
|
| 1325 |
+
" <td>94.74</td>\n",
|
| 1326 |
+
" <td>95.15</td>\n",
|
| 1327 |
+
" <td>93.49</td>\n",
|
| 1328 |
+
" <td>93.82</td>\n",
|
| 1329 |
+
" <td>0</td>\n",
|
| 1330 |
+
" </tr>\n",
|
| 1331 |
+
" <tr>\n",
|
| 1332 |
+
" <th>1978-01-04</th>\n",
|
| 1333 |
+
" <td>93.16</td>\n",
|
| 1334 |
+
" <td>94.10</td>\n",
|
| 1335 |
+
" <td>92.57</td>\n",
|
| 1336 |
+
" <td>93.52</td>\n",
|
| 1337 |
+
" <td>0</td>\n",
|
| 1338 |
+
" </tr>\n",
|
| 1339 |
+
" <tr>\n",
|
| 1340 |
+
" <th>1978-01-05</th>\n",
|
| 1341 |
+
" <td>94.18</td>\n",
|
| 1342 |
+
" <td>94.53</td>\n",
|
| 1343 |
+
" <td>92.51</td>\n",
|
| 1344 |
+
" <td>92.74</td>\n",
|
| 1345 |
+
" <td>0</td>\n",
|
| 1346 |
+
" </tr>\n",
|
| 1347 |
+
" <tr>\n",
|
| 1348 |
+
" <th>1978-01-06</th>\n",
|
| 1349 |
+
" <td>92.06</td>\n",
|
| 1350 |
+
" <td>92.66</td>\n",
|
| 1351 |
+
" <td>91.05</td>\n",
|
| 1352 |
+
" <td>91.62</td>\n",
|
| 1353 |
+
" <td>0</td>\n",
|
| 1354 |
+
" </tr>\n",
|
| 1355 |
+
" <tr>\n",
|
| 1356 |
+
" <th>1978-01-09</th>\n",
|
| 1357 |
+
" <td>90.82</td>\n",
|
| 1358 |
+
" <td>91.48</td>\n",
|
| 1359 |
+
" <td>89.97</td>\n",
|
| 1360 |
+
" <td>90.64</td>\n",
|
| 1361 |
+
" <td>0</td>\n",
|
| 1362 |
+
" </tr>\n",
|
| 1363 |
+
" <tr>\n",
|
| 1364 |
+
" <th>...</th>\n",
|
| 1365 |
+
" <td>...</td>\n",
|
| 1366 |
+
" <td>...</td>\n",
|
| 1367 |
+
" <td>...</td>\n",
|
| 1368 |
+
" <td>...</td>\n",
|
| 1369 |
+
" <td>...</td>\n",
|
| 1370 |
+
" </tr>\n",
|
| 1371 |
+
" <tr>\n",
|
| 1372 |
+
" <th>2024-08-15</th>\n",
|
| 1373 |
+
" <td>5501.13</td>\n",
|
| 1374 |
+
" <td>5546.23</td>\n",
|
| 1375 |
+
" <td>5501.13</td>\n",
|
| 1376 |
+
" <td>5543.22</td>\n",
|
| 1377 |
+
" <td>0</td>\n",
|
| 1378 |
+
" </tr>\n",
|
| 1379 |
+
" <tr>\n",
|
| 1380 |
+
" <th>2024-08-16</th>\n",
|
| 1381 |
+
" <td>5530.50</td>\n",
|
| 1382 |
+
" <td>5561.98</td>\n",
|
| 1383 |
+
" <td>5525.17</td>\n",
|
| 1384 |
+
" <td>5554.25</td>\n",
|
| 1385 |
+
" <td>0</td>\n",
|
| 1386 |
+
" </tr>\n",
|
| 1387 |
+
" <tr>\n",
|
| 1388 |
+
" <th>2024-08-19</th>\n",
|
| 1389 |
+
" <td>5557.23</td>\n",
|
| 1390 |
+
" <td>5608.30</td>\n",
|
| 1391 |
+
" <td>5550.74</td>\n",
|
| 1392 |
+
" <td>5608.25</td>\n",
|
| 1393 |
+
" <td>0</td>\n",
|
| 1394 |
+
" </tr>\n",
|
| 1395 |
+
" <tr>\n",
|
| 1396 |
+
" <th>2024-08-20</th>\n",
|
| 1397 |
+
" <td>5602.88</td>\n",
|
| 1398 |
+
" <td>5620.51</td>\n",
|
| 1399 |
+
" <td>5585.50</td>\n",
|
| 1400 |
+
" <td>5597.12</td>\n",
|
| 1401 |
+
" <td>0</td>\n",
|
| 1402 |
+
" </tr>\n",
|
| 1403 |
+
" <tr>\n",
|
| 1404 |
+
" <th>2024-08-21</th>\n",
|
| 1405 |
+
" <td>5603.09</td>\n",
|
| 1406 |
+
" <td>5632.68</td>\n",
|
| 1407 |
+
" <td>5591.57</td>\n",
|
| 1408 |
+
" <td>5620.85</td>\n",
|
| 1409 |
+
" <td>0</td>\n",
|
| 1410 |
+
" </tr>\n",
|
| 1411 |
+
" </tbody>\n",
|
| 1412 |
+
"</table>\n",
|
| 1413 |
+
"<p>11509 rows × 5 columns</p>\n",
|
| 1414 |
+
"</div>"
|
| 1415 |
+
],
|
| 1416 |
+
"text/plain": [
|
| 1417 |
+
" open high low close volume\n",
|
| 1418 |
+
"date \n",
|
| 1419 |
+
"1978-01-03 94.74 95.15 93.49 93.82 0\n",
|
| 1420 |
+
"1978-01-04 93.16 94.10 92.57 93.52 0\n",
|
| 1421 |
+
"1978-01-05 94.18 94.53 92.51 92.74 0\n",
|
| 1422 |
+
"1978-01-06 92.06 92.66 91.05 91.62 0\n",
|
| 1423 |
+
"1978-01-09 90.82 91.48 89.97 90.64 0\n",
|
| 1424 |
+
"... ... ... ... ... ...\n",
|
| 1425 |
+
"2024-08-15 5501.13 5546.23 5501.13 5543.22 0\n",
|
| 1426 |
+
"2024-08-16 5530.50 5561.98 5525.17 5554.25 0\n",
|
| 1427 |
+
"2024-08-19 5557.23 5608.30 5550.74 5608.25 0\n",
|
| 1428 |
+
"2024-08-20 5602.88 5620.51 5585.50 5597.12 0\n",
|
| 1429 |
+
"2024-08-21 5603.09 5632.68 5591.57 5620.85 0\n",
|
| 1430 |
+
"\n",
|
| 1431 |
+
"[11509 rows x 5 columns]"
|
| 1432 |
+
]
|
| 1433 |
+
},
|
| 1434 |
+
"execution_count": 16,
|
| 1435 |
+
"metadata": {},
|
| 1436 |
+
"output_type": "execute_result"
|
| 1437 |
+
}
|
| 1438 |
+
],
|
| 1439 |
+
"source": [
|
| 1440 |
+
"obb.equity.price.historical(\"SPX\", provider=\"cboe\").to_df()"
|
| 1441 |
+
]
|
| 1442 |
+
},
|
| 1443 |
+
{
|
| 1444 |
+
"cell_type": "code",
|
| 1445 |
+
"execution_count": 17,
|
| 1446 |
+
"metadata": {},
|
| 1447 |
+
"outputs": [
|
| 1448 |
+
{
|
| 1449 |
+
"data": {
|
| 1450 |
+
"text/html": [
|
| 1451 |
+
"<div>\n",
|
| 1452 |
+
"<style scoped>\n",
|
| 1453 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1454 |
+
" vertical-align: middle;\n",
|
| 1455 |
+
" }\n",
|
| 1456 |
+
"\n",
|
| 1457 |
+
" .dataframe tbody tr th {\n",
|
| 1458 |
+
" vertical-align: top;\n",
|
| 1459 |
+
" }\n",
|
| 1460 |
+
"\n",
|
| 1461 |
+
" .dataframe thead th {\n",
|
| 1462 |
+
" text-align: right;\n",
|
| 1463 |
+
" }\n",
|
| 1464 |
+
"</style>\n",
|
| 1465 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1466 |
+
" <thead>\n",
|
| 1467 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1468 |
+
" <th></th>\n",
|
| 1469 |
+
" <th>open</th>\n",
|
| 1470 |
+
" <th>high</th>\n",
|
| 1471 |
+
" <th>low</th>\n",
|
| 1472 |
+
" <th>close</th>\n",
|
| 1473 |
+
" <th>volume</th>\n",
|
| 1474 |
+
" <th>vwap</th>\n",
|
| 1475 |
+
" <th>adj_close</th>\n",
|
| 1476 |
+
" <th>unadjusted_volume</th>\n",
|
| 1477 |
+
" <th>change</th>\n",
|
| 1478 |
+
" <th>change_percent</th>\n",
|
| 1479 |
+
" </tr>\n",
|
| 1480 |
+
" <tr>\n",
|
| 1481 |
+
" <th>date</th>\n",
|
| 1482 |
+
" <th></th>\n",
|
| 1483 |
+
" <th></th>\n",
|
| 1484 |
+
" <th></th>\n",
|
| 1485 |
+
" <th></th>\n",
|
| 1486 |
+
" <th></th>\n",
|
| 1487 |
+
" <th></th>\n",
|
| 1488 |
+
" <th></th>\n",
|
| 1489 |
+
" <th></th>\n",
|
| 1490 |
+
" <th></th>\n",
|
| 1491 |
+
" <th></th>\n",
|
| 1492 |
+
" </tr>\n",
|
| 1493 |
+
" </thead>\n",
|
| 1494 |
+
" <tbody>\n",
|
| 1495 |
+
" <tr>\n",
|
| 1496 |
+
" <th>2023-08-22</th>\n",
|
| 1497 |
+
" <td>4415.33008</td>\n",
|
| 1498 |
+
" <td>4418.58984</td>\n",
|
| 1499 |
+
" <td>4382.77002</td>\n",
|
| 1500 |
+
" <td>4387.54980</td>\n",
|
| 1501 |
+
" <td>3522760000</td>\n",
|
| 1502 |
+
" <td>4396.30</td>\n",
|
| 1503 |
+
" <td>4387.54980</td>\n",
|
| 1504 |
+
" <td>3.522760e+09</td>\n",
|
| 1505 |
+
" <td>-27.78028</td>\n",
|
| 1506 |
+
" <td>-0.006292</td>\n",
|
| 1507 |
+
" </tr>\n",
|
| 1508 |
+
" <tr>\n",
|
| 1509 |
+
" <th>2023-08-23</th>\n",
|
| 1510 |
+
" <td>4396.43994</td>\n",
|
| 1511 |
+
" <td>4443.18018</td>\n",
|
| 1512 |
+
" <td>4396.43994</td>\n",
|
| 1513 |
+
" <td>4436.00977</td>\n",
|
| 1514 |
+
" <td>3837270000</td>\n",
|
| 1515 |
+
" <td>4425.21</td>\n",
|
| 1516 |
+
" <td>4436.00977</td>\n",
|
| 1517 |
+
" <td>3.837270e+09</td>\n",
|
| 1518 |
+
" <td>39.56983</td>\n",
|
| 1519 |
+
" <td>0.009000</td>\n",
|
| 1520 |
+
" </tr>\n",
|
| 1521 |
+
" <tr>\n",
|
| 1522 |
+
" <th>2023-08-24</th>\n",
|
| 1523 |
+
" <td>4455.16016</td>\n",
|
| 1524 |
+
" <td>4458.29980</td>\n",
|
| 1525 |
+
" <td>4375.54980</td>\n",
|
| 1526 |
+
" <td>4376.31006</td>\n",
|
| 1527 |
+
" <td>3723470000</td>\n",
|
| 1528 |
+
" <td>4403.39</td>\n",
|
| 1529 |
+
" <td>4376.31006</td>\n",
|
| 1530 |
+
" <td>3.723470e+09</td>\n",
|
| 1531 |
+
" <td>-78.85010</td>\n",
|
| 1532 |
+
" <td>-0.017700</td>\n",
|
| 1533 |
+
" </tr>\n",
|
| 1534 |
+
" <tr>\n",
|
| 1535 |
+
" <th>2023-08-25</th>\n",
|
| 1536 |
+
" <td>4389.37988</td>\n",
|
| 1537 |
+
" <td>4418.45996</td>\n",
|
| 1538 |
+
" <td>4356.29004</td>\n",
|
| 1539 |
+
" <td>4405.70996</td>\n",
|
| 1540 |
+
" <td>3296180000</td>\n",
|
| 1541 |
+
" <td>4393.49</td>\n",
|
| 1542 |
+
" <td>4405.70996</td>\n",
|
| 1543 |
+
" <td>3.296180e+09</td>\n",
|
| 1544 |
+
" <td>16.33008</td>\n",
|
| 1545 |
+
" <td>0.003720</td>\n",
|
| 1546 |
+
" </tr>\n",
|
| 1547 |
+
" <tr>\n",
|
| 1548 |
+
" <th>2023-08-28</th>\n",
|
| 1549 |
+
" <td>4426.02979</td>\n",
|
| 1550 |
+
" <td>4439.56006</td>\n",
|
| 1551 |
+
" <td>4414.97998</td>\n",
|
| 1552 |
+
" <td>4433.31006</td>\n",
|
| 1553 |
+
" <td>2957230000</td>\n",
|
| 1554 |
+
" <td>4429.28</td>\n",
|
| 1555 |
+
" <td>4433.31006</td>\n",
|
| 1556 |
+
" <td>2.957230e+09</td>\n",
|
| 1557 |
+
" <td>7.28027</td>\n",
|
| 1558 |
+
" <td>0.001645</td>\n",
|
| 1559 |
+
" </tr>\n",
|
| 1560 |
+
" <tr>\n",
|
| 1561 |
+
" <th>...</th>\n",
|
| 1562 |
+
" <td>...</td>\n",
|
| 1563 |
+
" <td>...</td>\n",
|
| 1564 |
+
" <td>...</td>\n",
|
| 1565 |
+
" <td>...</td>\n",
|
| 1566 |
+
" <td>...</td>\n",
|
| 1567 |
+
" <td>...</td>\n",
|
| 1568 |
+
" <td>...</td>\n",
|
| 1569 |
+
" <td>...</td>\n",
|
| 1570 |
+
" <td>...</td>\n",
|
| 1571 |
+
" <td>...</td>\n",
|
| 1572 |
+
" </tr>\n",
|
| 1573 |
+
" <tr>\n",
|
| 1574 |
+
" <th>2024-08-16</th>\n",
|
| 1575 |
+
" <td>5530.50000</td>\n",
|
| 1576 |
+
" <td>5561.97998</td>\n",
|
| 1577 |
+
" <td>5525.16992</td>\n",
|
| 1578 |
+
" <td>5554.25000</td>\n",
|
| 1579 |
+
" <td>3357690000</td>\n",
|
| 1580 |
+
" <td>5542.97</td>\n",
|
| 1581 |
+
" <td>5554.25000</td>\n",
|
| 1582 |
+
" <td>3.357690e+09</td>\n",
|
| 1583 |
+
" <td>23.75000</td>\n",
|
| 1584 |
+
" <td>0.004294</td>\n",
|
| 1585 |
+
" </tr>\n",
|
| 1586 |
+
" <tr>\n",
|
| 1587 |
+
" <th>2024-08-19</th>\n",
|
| 1588 |
+
" <td>5557.22998</td>\n",
|
| 1589 |
+
" <td>5608.29981</td>\n",
|
| 1590 |
+
" <td>5550.74023</td>\n",
|
| 1591 |
+
" <td>5608.25000</td>\n",
|
| 1592 |
+
" <td>3222050000</td>\n",
|
| 1593 |
+
" <td>5581.13</td>\n",
|
| 1594 |
+
" <td>5608.25000</td>\n",
|
| 1595 |
+
" <td>3.222050e+09</td>\n",
|
| 1596 |
+
" <td>51.02002</td>\n",
|
| 1597 |
+
" <td>0.009181</td>\n",
|
| 1598 |
+
" </tr>\n",
|
| 1599 |
+
" <tr>\n",
|
| 1600 |
+
" <th>2024-08-20</th>\n",
|
| 1601 |
+
" <td>5602.87988</td>\n",
|
| 1602 |
+
" <td>5620.50977</td>\n",
|
| 1603 |
+
" <td>5585.50000</td>\n",
|
| 1604 |
+
" <td>5597.12012</td>\n",
|
| 1605 |
+
" <td>2994420000</td>\n",
|
| 1606 |
+
" <td>5601.50</td>\n",
|
| 1607 |
+
" <td>5597.12012</td>\n",
|
| 1608 |
+
" <td>2.994420e+09</td>\n",
|
| 1609 |
+
" <td>-5.75976</td>\n",
|
| 1610 |
+
" <td>-0.001028</td>\n",
|
| 1611 |
+
" </tr>\n",
|
| 1612 |
+
" <tr>\n",
|
| 1613 |
+
" <th>2024-08-21</th>\n",
|
| 1614 |
+
" <td>5603.08984</td>\n",
|
| 1615 |
+
" <td>5632.68018</td>\n",
|
| 1616 |
+
" <td>5591.56982</td>\n",
|
| 1617 |
+
" <td>5620.85010</td>\n",
|
| 1618 |
+
" <td>1982137065</td>\n",
|
| 1619 |
+
" <td>5612.05</td>\n",
|
| 1620 |
+
" <td>5620.85010</td>\n",
|
| 1621 |
+
" <td>1.982137e+09</td>\n",
|
| 1622 |
+
" <td>17.76026</td>\n",
|
| 1623 |
+
" <td>0.003170</td>\n",
|
| 1624 |
+
" </tr>\n",
|
| 1625 |
+
" <tr>\n",
|
| 1626 |
+
" <th>2024-08-22</th>\n",
|
| 1627 |
+
" <td>5637.77000</td>\n",
|
| 1628 |
+
" <td>5643.22000</td>\n",
|
| 1629 |
+
" <td>5563.54000</td>\n",
|
| 1630 |
+
" <td>5577.27000</td>\n",
|
| 1631 |
+
" <td>1218069912</td>\n",
|
| 1632 |
+
" <td>5594.68</td>\n",
|
| 1633 |
+
" <td>5577.27000</td>\n",
|
| 1634 |
+
" <td>1.218070e+09</td>\n",
|
| 1635 |
+
" <td>-60.50000</td>\n",
|
| 1636 |
+
" <td>-0.010731</td>\n",
|
| 1637 |
+
" </tr>\n",
|
| 1638 |
+
" </tbody>\n",
|
| 1639 |
+
"</table>\n",
|
| 1640 |
+
"<p>253 rows × 10 columns</p>\n",
|
| 1641 |
+
"</div>"
|
| 1642 |
+
],
|
| 1643 |
+
"text/plain": [
|
| 1644 |
+
" open high low close volume \\\n",
|
| 1645 |
+
"date \n",
|
| 1646 |
+
"2023-08-22 4415.33008 4418.58984 4382.77002 4387.54980 3522760000 \n",
|
| 1647 |
+
"2023-08-23 4396.43994 4443.18018 4396.43994 4436.00977 3837270000 \n",
|
| 1648 |
+
"2023-08-24 4455.16016 4458.29980 4375.54980 4376.31006 3723470000 \n",
|
| 1649 |
+
"2023-08-25 4389.37988 4418.45996 4356.29004 4405.70996 3296180000 \n",
|
| 1650 |
+
"2023-08-28 4426.02979 4439.56006 4414.97998 4433.31006 2957230000 \n",
|
| 1651 |
+
"... ... ... ... ... ... \n",
|
| 1652 |
+
"2024-08-16 5530.50000 5561.97998 5525.16992 5554.25000 3357690000 \n",
|
| 1653 |
+
"2024-08-19 5557.22998 5608.29981 5550.74023 5608.25000 3222050000 \n",
|
| 1654 |
+
"2024-08-20 5602.87988 5620.50977 5585.50000 5597.12012 2994420000 \n",
|
| 1655 |
+
"2024-08-21 5603.08984 5632.68018 5591.56982 5620.85010 1982137065 \n",
|
| 1656 |
+
"2024-08-22 5637.77000 5643.22000 5563.54000 5577.27000 1218069912 \n",
|
| 1657 |
+
"\n",
|
| 1658 |
+
" vwap adj_close unadjusted_volume change change_percent \n",
|
| 1659 |
+
"date \n",
|
| 1660 |
+
"2023-08-22 4396.30 4387.54980 3.522760e+09 -27.78028 -0.006292 \n",
|
| 1661 |
+
"2023-08-23 4425.21 4436.00977 3.837270e+09 39.56983 0.009000 \n",
|
| 1662 |
+
"2023-08-24 4403.39 4376.31006 3.723470e+09 -78.85010 -0.017700 \n",
|
| 1663 |
+
"2023-08-25 4393.49 4405.70996 3.296180e+09 16.33008 0.003720 \n",
|
| 1664 |
+
"2023-08-28 4429.28 4433.31006 2.957230e+09 7.28027 0.001645 \n",
|
| 1665 |
+
"... ... ... ... ... ... \n",
|
| 1666 |
+
"2024-08-16 5542.97 5554.25000 3.357690e+09 23.75000 0.004294 \n",
|
| 1667 |
+
"2024-08-19 5581.13 5608.25000 3.222050e+09 51.02002 0.009181 \n",
|
| 1668 |
+
"2024-08-20 5601.50 5597.12012 2.994420e+09 -5.75976 -0.001028 \n",
|
| 1669 |
+
"2024-08-21 5612.05 5620.85010 1.982137e+09 17.76026 0.003170 \n",
|
| 1670 |
+
"2024-08-22 5594.68 5577.27000 1.218070e+09 -60.50000 -0.010731 \n",
|
| 1671 |
+
"\n",
|
| 1672 |
+
"[253 rows x 10 columns]"
|
| 1673 |
+
]
|
| 1674 |
+
},
|
| 1675 |
+
"execution_count": 17,
|
| 1676 |
+
"metadata": {},
|
| 1677 |
+
"output_type": "execute_result"
|
| 1678 |
+
}
|
| 1679 |
+
],
|
| 1680 |
+
"source": [
|
| 1681 |
+
"obb.equity.price.historical(\"^SPX\", provider=\"fmp\").to_df()"
|
| 1682 |
+
]
|
| 1683 |
+
},
|
| 1684 |
+
{
|
| 1685 |
+
"cell_type": "code",
|
| 1686 |
+
"execution_count": 19,
|
| 1687 |
+
"metadata": {},
|
| 1688 |
+
"outputs": [
|
| 1689 |
+
{
|
| 1690 |
+
"data": {
|
| 1691 |
+
"text/html": [
|
| 1692 |
+
"<div>\n",
|
| 1693 |
+
"<style scoped>\n",
|
| 1694 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1695 |
+
" vertical-align: middle;\n",
|
| 1696 |
+
" }\n",
|
| 1697 |
+
"\n",
|
| 1698 |
+
" .dataframe tbody tr th {\n",
|
| 1699 |
+
" vertical-align: top;\n",
|
| 1700 |
+
" }\n",
|
| 1701 |
+
"\n",
|
| 1702 |
+
" .dataframe thead th {\n",
|
| 1703 |
+
" text-align: right;\n",
|
| 1704 |
+
" }\n",
|
| 1705 |
+
"</style>\n",
|
| 1706 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1707 |
+
" <thead>\n",
|
| 1708 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1709 |
+
" <th></th>\n",
|
| 1710 |
+
" <th>open</th>\n",
|
| 1711 |
+
" <th>high</th>\n",
|
| 1712 |
+
" <th>low</th>\n",
|
| 1713 |
+
" <th>close</th>\n",
|
| 1714 |
+
" <th>volume</th>\n",
|
| 1715 |
+
" <th>split_ratio</th>\n",
|
| 1716 |
+
" <th>dividend</th>\n",
|
| 1717 |
+
" </tr>\n",
|
| 1718 |
+
" <tr>\n",
|
| 1719 |
+
" <th>date</th>\n",
|
| 1720 |
+
" <th></th>\n",
|
| 1721 |
+
" <th></th>\n",
|
| 1722 |
+
" <th></th>\n",
|
| 1723 |
+
" <th></th>\n",
|
| 1724 |
+
" <th></th>\n",
|
| 1725 |
+
" <th></th>\n",
|
| 1726 |
+
" <th></th>\n",
|
| 1727 |
+
" </tr>\n",
|
| 1728 |
+
" </thead>\n",
|
| 1729 |
+
" <tbody>\n",
|
| 1730 |
+
" <tr>\n",
|
| 1731 |
+
" <th>2023-08-22</th>\n",
|
| 1732 |
+
" <td>71.419998</td>\n",
|
| 1733 |
+
" <td>71.949997</td>\n",
|
| 1734 |
+
" <td>71.029999</td>\n",
|
| 1735 |
+
" <td>71.160004</td>\n",
|
| 1736 |
+
" <td>5342</td>\n",
|
| 1737 |
+
" <td>0.0</td>\n",
|
| 1738 |
+
" <td>0.0</td>\n",
|
| 1739 |
+
" </tr>\n",
|
| 1740 |
+
" <tr>\n",
|
| 1741 |
+
" <th>2023-08-23</th>\n",
|
| 1742 |
+
" <td>71.120003</td>\n",
|
| 1743 |
+
" <td>71.320000</td>\n",
|
| 1744 |
+
" <td>69.709999</td>\n",
|
| 1745 |
+
" <td>70.730003</td>\n",
|
| 1746 |
+
" <td>5139</td>\n",
|
| 1747 |
+
" <td>0.0</td>\n",
|
| 1748 |
+
" <td>0.0</td>\n",
|
| 1749 |
+
" </tr>\n",
|
| 1750 |
+
" <tr>\n",
|
| 1751 |
+
" <th>2023-08-24</th>\n",
|
| 1752 |
+
" <td>70.459999</td>\n",
|
| 1753 |
+
" <td>70.860001</td>\n",
|
| 1754 |
+
" <td>69.870003</td>\n",
|
| 1755 |
+
" <td>70.190002</td>\n",
|
| 1756 |
+
" <td>7594</td>\n",
|
| 1757 |
+
" <td>0.0</td>\n",
|
| 1758 |
+
" <td>0.0</td>\n",
|
| 1759 |
+
" </tr>\n",
|
| 1760 |
+
" <tr>\n",
|
| 1761 |
+
" <th>2023-08-25</th>\n",
|
| 1762 |
+
" <td>70.050003</td>\n",
|
| 1763 |
+
" <td>70.889999</td>\n",
|
| 1764 |
+
" <td>69.470001</td>\n",
|
| 1765 |
+
" <td>70.680000</td>\n",
|
| 1766 |
+
" <td>9328</td>\n",
|
| 1767 |
+
" <td>0.0</td>\n",
|
| 1768 |
+
" <td>0.0</td>\n",
|
| 1769 |
+
" </tr>\n",
|
| 1770 |
+
" <tr>\n",
|
| 1771 |
+
" <th>2023-08-28</th>\n",
|
| 1772 |
+
" <td>70.690002</td>\n",
|
| 1773 |
+
" <td>71.190002</td>\n",
|
| 1774 |
+
" <td>70.239998</td>\n",
|
| 1775 |
+
" <td>70.480003</td>\n",
|
| 1776 |
+
" <td>6234</td>\n",
|
| 1777 |
+
" <td>0.0</td>\n",
|
| 1778 |
+
" <td>0.0</td>\n",
|
| 1779 |
+
" </tr>\n",
|
| 1780 |
+
" <tr>\n",
|
| 1781 |
+
" <th>...</th>\n",
|
| 1782 |
+
" <td>...</td>\n",
|
| 1783 |
+
" <td>...</td>\n",
|
| 1784 |
+
" <td>...</td>\n",
|
| 1785 |
+
" <td>...</td>\n",
|
| 1786 |
+
" <td>...</td>\n",
|
| 1787 |
+
" <td>...</td>\n",
|
| 1788 |
+
" <td>...</td>\n",
|
| 1789 |
+
" </tr>\n",
|
| 1790 |
+
" <tr>\n",
|
| 1791 |
+
" <th>2024-08-16</th>\n",
|
| 1792 |
+
" <td>70.940002</td>\n",
|
| 1793 |
+
" <td>70.989998</td>\n",
|
| 1794 |
+
" <td>69.440002</td>\n",
|
| 1795 |
+
" <td>70.019997</td>\n",
|
| 1796 |
+
" <td>38165</td>\n",
|
| 1797 |
+
" <td>0.0</td>\n",
|
| 1798 |
+
" <td>0.0</td>\n",
|
| 1799 |
+
" </tr>\n",
|
| 1800 |
+
" <tr>\n",
|
| 1801 |
+
" <th>2024-08-19</th>\n",
|
| 1802 |
+
" <td>70.099998</td>\n",
|
| 1803 |
+
" <td>70.400002</td>\n",
|
| 1804 |
+
" <td>68.870003</td>\n",
|
| 1805 |
+
" <td>69.029999</td>\n",
|
| 1806 |
+
" <td>29067</td>\n",
|
| 1807 |
+
" <td>0.0</td>\n",
|
| 1808 |
+
" <td>0.0</td>\n",
|
| 1809 |
+
" </tr>\n",
|
| 1810 |
+
" <tr>\n",
|
| 1811 |
+
" <th>2024-08-20</th>\n",
|
| 1812 |
+
" <td>69.150002</td>\n",
|
| 1813 |
+
" <td>69.250000</td>\n",
|
| 1814 |
+
" <td>68.309998</td>\n",
|
| 1815 |
+
" <td>68.389999</td>\n",
|
| 1816 |
+
" <td>29827</td>\n",
|
| 1817 |
+
" <td>0.0</td>\n",
|
| 1818 |
+
" <td>0.0</td>\n",
|
| 1819 |
+
" </tr>\n",
|
| 1820 |
+
" <tr>\n",
|
| 1821 |
+
" <th>2024-08-21</th>\n",
|
| 1822 |
+
" <td>68.389999</td>\n",
|
| 1823 |
+
" <td>68.959999</td>\n",
|
| 1824 |
+
" <td>67.370003</td>\n",
|
| 1825 |
+
" <td>67.629997</td>\n",
|
| 1826 |
+
" <td>29827</td>\n",
|
| 1827 |
+
" <td>0.0</td>\n",
|
| 1828 |
+
" <td>0.0</td>\n",
|
| 1829 |
+
" </tr>\n",
|
| 1830 |
+
" <tr>\n",
|
| 1831 |
+
" <th>2024-08-22</th>\n",
|
| 1832 |
+
" <td>67.730003</td>\n",
|
| 1833 |
+
" <td>68.650002</td>\n",
|
| 1834 |
+
" <td>67.430000</td>\n",
|
| 1835 |
+
" <td>68.220001</td>\n",
|
| 1836 |
+
" <td>33722</td>\n",
|
| 1837 |
+
" <td>0.0</td>\n",
|
| 1838 |
+
" <td>0.0</td>\n",
|
| 1839 |
+
" </tr>\n",
|
| 1840 |
+
" </tbody>\n",
|
| 1841 |
+
"</table>\n",
|
| 1842 |
+
"<p>254 rows × 7 columns</p>\n",
|
| 1843 |
+
"</div>"
|
| 1844 |
+
],
|
| 1845 |
+
"text/plain": [
|
| 1846 |
+
" open high low close volume split_ratio \\\n",
|
| 1847 |
+
"date \n",
|
| 1848 |
+
"2023-08-22 71.419998 71.949997 71.029999 71.160004 5342 0.0 \n",
|
| 1849 |
+
"2023-08-23 71.120003 71.320000 69.709999 70.730003 5139 0.0 \n",
|
| 1850 |
+
"2023-08-24 70.459999 70.860001 69.870003 70.190002 7594 0.0 \n",
|
| 1851 |
+
"2023-08-25 70.050003 70.889999 69.470001 70.680000 9328 0.0 \n",
|
| 1852 |
+
"2023-08-28 70.690002 71.190002 70.239998 70.480003 6234 0.0 \n",
|
| 1853 |
+
"... ... ... ... ... ... ... \n",
|
| 1854 |
+
"2024-08-16 70.940002 70.989998 69.440002 70.019997 38165 0.0 \n",
|
| 1855 |
+
"2024-08-19 70.099998 70.400002 68.870003 69.029999 29067 0.0 \n",
|
| 1856 |
+
"2024-08-20 69.150002 69.250000 68.309998 68.389999 29827 0.0 \n",
|
| 1857 |
+
"2024-08-21 68.389999 68.959999 67.370003 67.629997 29827 0.0 \n",
|
| 1858 |
+
"2024-08-22 67.730003 68.650002 67.430000 68.220001 33722 0.0 \n",
|
| 1859 |
+
"\n",
|
| 1860 |
+
" dividend \n",
|
| 1861 |
+
"date \n",
|
| 1862 |
+
"2023-08-22 0.0 \n",
|
| 1863 |
+
"2023-08-23 0.0 \n",
|
| 1864 |
+
"2023-08-24 0.0 \n",
|
| 1865 |
+
"2023-08-25 0.0 \n",
|
| 1866 |
+
"2023-08-28 0.0 \n",
|
| 1867 |
+
"... ... \n",
|
| 1868 |
+
"2024-08-16 0.0 \n",
|
| 1869 |
+
"2024-08-19 0.0 \n",
|
| 1870 |
+
"2024-08-20 0.0 \n",
|
| 1871 |
+
"2024-08-21 0.0 \n",
|
| 1872 |
+
"2024-08-22 0.0 \n",
|
| 1873 |
+
"\n",
|
| 1874 |
+
"[254 rows x 7 columns]"
|
| 1875 |
+
]
|
| 1876 |
+
},
|
| 1877 |
+
"execution_count": 19,
|
| 1878 |
+
"metadata": {},
|
| 1879 |
+
"output_type": "execute_result"
|
| 1880 |
+
}
|
| 1881 |
+
],
|
| 1882 |
+
"source": [
|
| 1883 |
+
"obb.equity.price.historical(\"CLZ25.NYM\", provider=\"yfinance\").to_df()"
|
| 1884 |
+
]
|
| 1885 |
+
},
|
| 1886 |
+
{
|
| 1887 |
+
"cell_type": "code",
|
| 1888 |
+
"execution_count": 20,
|
| 1889 |
+
"metadata": {},
|
| 1890 |
+
"outputs": [
|
| 1891 |
+
{
|
| 1892 |
+
"data": {
|
| 1893 |
+
"text/html": [
|
| 1894 |
+
"<div>\n",
|
| 1895 |
+
"<style scoped>\n",
|
| 1896 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1897 |
+
" vertical-align: middle;\n",
|
| 1898 |
+
" }\n",
|
| 1899 |
+
"\n",
|
| 1900 |
+
" .dataframe tbody tr th {\n",
|
| 1901 |
+
" vertical-align: top;\n",
|
| 1902 |
+
" }\n",
|
| 1903 |
+
"\n",
|
| 1904 |
+
" .dataframe thead th {\n",
|
| 1905 |
+
" text-align: right;\n",
|
| 1906 |
+
" }\n",
|
| 1907 |
+
"</style>\n",
|
| 1908 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1909 |
+
" <thead>\n",
|
| 1910 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1911 |
+
" <th></th>\n",
|
| 1912 |
+
" <th>open</th>\n",
|
| 1913 |
+
" <th>high</th>\n",
|
| 1914 |
+
" <th>low</th>\n",
|
| 1915 |
+
" <th>close</th>\n",
|
| 1916 |
+
" <th>volume</th>\n",
|
| 1917 |
+
" <th>vwap</th>\n",
|
| 1918 |
+
" <th>adj_close</th>\n",
|
| 1919 |
+
" <th>unadjusted_volume</th>\n",
|
| 1920 |
+
" <th>change</th>\n",
|
| 1921 |
+
" <th>change_percent</th>\n",
|
| 1922 |
+
" </tr>\n",
|
| 1923 |
+
" <tr>\n",
|
| 1924 |
+
" <th>date</th>\n",
|
| 1925 |
+
" <th></th>\n",
|
| 1926 |
+
" <th></th>\n",
|
| 1927 |
+
" <th></th>\n",
|
| 1928 |
+
" <th></th>\n",
|
| 1929 |
+
" <th></th>\n",
|
| 1930 |
+
" <th></th>\n",
|
| 1931 |
+
" <th></th>\n",
|
| 1932 |
+
" <th></th>\n",
|
| 1933 |
+
" <th></th>\n",
|
| 1934 |
+
" <th></th>\n",
|
| 1935 |
+
" </tr>\n",
|
| 1936 |
+
" </thead>\n",
|
| 1937 |
+
" <tbody>\n",
|
| 1938 |
+
" <tr>\n",
|
| 1939 |
+
" <th>2023-08-22</th>\n",
|
| 1940 |
+
" <td>80.80</td>\n",
|
| 1941 |
+
" <td>80.99</td>\n",
|
| 1942 |
+
" <td>80.10</td>\n",
|
| 1943 |
+
" <td>80.35</td>\n",
|
| 1944 |
+
" <td>287489</td>\n",
|
| 1945 |
+
" <td>80.48</td>\n",
|
| 1946 |
+
" <td>80.35</td>\n",
|
| 1947 |
+
" <td>287489.0</td>\n",
|
| 1948 |
+
" <td>-0.45</td>\n",
|
| 1949 |
+
" <td>-0.005569</td>\n",
|
| 1950 |
+
" </tr>\n",
|
| 1951 |
+
" <tr>\n",
|
| 1952 |
+
" <th>2023-08-23</th>\n",
|
| 1953 |
+
" <td>79.64</td>\n",
|
| 1954 |
+
" <td>79.91</td>\n",
|
| 1955 |
+
" <td>77.62</td>\n",
|
| 1956 |
+
" <td>78.89</td>\n",
|
| 1957 |
+
" <td>378146</td>\n",
|
| 1958 |
+
" <td>78.81</td>\n",
|
| 1959 |
+
" <td>78.89</td>\n",
|
| 1960 |
+
" <td>378146.0</td>\n",
|
| 1961 |
+
" <td>-0.75</td>\n",
|
| 1962 |
+
" <td>-0.009417</td>\n",
|
| 1963 |
+
" </tr>\n",
|
| 1964 |
+
" <tr>\n",
|
| 1965 |
+
" <th>2023-08-24</th>\n",
|
| 1966 |
+
" <td>78.57</td>\n",
|
| 1967 |
+
" <td>79.28</td>\n",
|
| 1968 |
+
" <td>77.59</td>\n",
|
| 1969 |
+
" <td>79.05</td>\n",
|
| 1970 |
+
" <td>349230</td>\n",
|
| 1971 |
+
" <td>78.64</td>\n",
|
| 1972 |
+
" <td>79.05</td>\n",
|
| 1973 |
+
" <td>349230.0</td>\n",
|
| 1974 |
+
" <td>0.48</td>\n",
|
| 1975 |
+
" <td>0.006109</td>\n",
|
| 1976 |
+
" </tr>\n",
|
| 1977 |
+
" <tr>\n",
|
| 1978 |
+
" <th>2023-08-25</th>\n",
|
| 1979 |
+
" <td>78.88</td>\n",
|
| 1980 |
+
" <td>80.45</td>\n",
|
| 1981 |
+
" <td>78.14</td>\n",
|
| 1982 |
+
" <td>79.83</td>\n",
|
| 1983 |
+
" <td>411409</td>\n",
|
| 1984 |
+
" <td>79.47</td>\n",
|
| 1985 |
+
" <td>79.83</td>\n",
|
| 1986 |
+
" <td>411409.0</td>\n",
|
| 1987 |
+
" <td>0.95</td>\n",
|
| 1988 |
+
" <td>0.012000</td>\n",
|
| 1989 |
+
" </tr>\n",
|
| 1990 |
+
" <tr>\n",
|
| 1991 |
+
" <th>2023-08-28</th>\n",
|
| 1992 |
+
" <td>80.15</td>\n",
|
| 1993 |
+
" <td>80.87</td>\n",
|
| 1994 |
+
" <td>79.61</td>\n",
|
| 1995 |
+
" <td>80.10</td>\n",
|
| 1996 |
+
" <td>246584</td>\n",
|
| 1997 |
+
" <td>80.19</td>\n",
|
| 1998 |
+
" <td>80.10</td>\n",
|
| 1999 |
+
" <td>246584.0</td>\n",
|
| 2000 |
+
" <td>-0.05</td>\n",
|
| 2001 |
+
" <td>-0.000624</td>\n",
|
| 2002 |
+
" </tr>\n",
|
| 2003 |
+
" <tr>\n",
|
| 2004 |
+
" <th>...</th>\n",
|
| 2005 |
+
" <td>...</td>\n",
|
| 2006 |
+
" <td>...</td>\n",
|
| 2007 |
+
" <td>...</td>\n",
|
| 2008 |
+
" <td>...</td>\n",
|
| 2009 |
+
" <td>...</td>\n",
|
| 2010 |
+
" <td>...</td>\n",
|
| 2011 |
+
" <td>...</td>\n",
|
| 2012 |
+
" <td>...</td>\n",
|
| 2013 |
+
" <td>...</td>\n",
|
| 2014 |
+
" <td>...</td>\n",
|
| 2015 |
+
" </tr>\n",
|
| 2016 |
+
" <tr>\n",
|
| 2017 |
+
" <th>2024-08-18</th>\n",
|
| 2018 |
+
" <td>76.58</td>\n",
|
| 2019 |
+
" <td>76.71</td>\n",
|
| 2020 |
+
" <td>76.48</td>\n",
|
| 2021 |
+
" <td>76.71</td>\n",
|
| 2022 |
+
" <td>175</td>\n",
|
| 2023 |
+
" <td>76.62</td>\n",
|
| 2024 |
+
" <td>76.71</td>\n",
|
| 2025 |
+
" <td>175.0</td>\n",
|
| 2026 |
+
" <td>0.13</td>\n",
|
| 2027 |
+
" <td>0.001698</td>\n",
|
| 2028 |
+
" </tr>\n",
|
| 2029 |
+
" <tr>\n",
|
| 2030 |
+
" <th>2024-08-19</th>\n",
|
| 2031 |
+
" <td>76.58</td>\n",
|
| 2032 |
+
" <td>76.87</td>\n",
|
| 2033 |
+
" <td>74.17</td>\n",
|
| 2034 |
+
" <td>74.37</td>\n",
|
| 2035 |
+
" <td>118172</td>\n",
|
| 2036 |
+
" <td>75.50</td>\n",
|
| 2037 |
+
" <td>74.37</td>\n",
|
| 2038 |
+
" <td>118172.0</td>\n",
|
| 2039 |
+
" <td>-2.21</td>\n",
|
| 2040 |
+
" <td>-0.028900</td>\n",
|
| 2041 |
+
" </tr>\n",
|
| 2042 |
+
" <tr>\n",
|
| 2043 |
+
" <th>2024-08-20</th>\n",
|
| 2044 |
+
" <td>74.34</td>\n",
|
| 2045 |
+
" <td>75.03</td>\n",
|
| 2046 |
+
" <td>73.50</td>\n",
|
| 2047 |
+
" <td>74.04</td>\n",
|
| 2048 |
+
" <td>118172</td>\n",
|
| 2049 |
+
" <td>74.23</td>\n",
|
| 2050 |
+
" <td>74.04</td>\n",
|
| 2051 |
+
" <td>118172.0</td>\n",
|
| 2052 |
+
" <td>-0.30</td>\n",
|
| 2053 |
+
" <td>-0.004036</td>\n",
|
| 2054 |
+
" </tr>\n",
|
| 2055 |
+
" <tr>\n",
|
| 2056 |
+
" <th>2024-08-21</th>\n",
|
| 2057 |
+
" <td>73.12</td>\n",
|
| 2058 |
+
" <td>74.16</td>\n",
|
| 2059 |
+
" <td>71.46</td>\n",
|
| 2060 |
+
" <td>71.93</td>\n",
|
| 2061 |
+
" <td>361850</td>\n",
|
| 2062 |
+
" <td>72.67</td>\n",
|
| 2063 |
+
" <td>71.93</td>\n",
|
| 2064 |
+
" <td>361850.0</td>\n",
|
| 2065 |
+
" <td>-1.19</td>\n",
|
| 2066 |
+
" <td>-0.016300</td>\n",
|
| 2067 |
+
" </tr>\n",
|
| 2068 |
+
" <tr>\n",
|
| 2069 |
+
" <th>2024-08-22</th>\n",
|
| 2070 |
+
" <td>71.93</td>\n",
|
| 2071 |
+
" <td>73.52</td>\n",
|
| 2072 |
+
" <td>71.58</td>\n",
|
| 2073 |
+
" <td>73.00</td>\n",
|
| 2074 |
+
" <td>28663</td>\n",
|
| 2075 |
+
" <td>72.70</td>\n",
|
| 2076 |
+
" <td>73.00</td>\n",
|
| 2077 |
+
" <td>28663.0</td>\n",
|
| 2078 |
+
" <td>1.07</td>\n",
|
| 2079 |
+
" <td>0.014876</td>\n",
|
| 2080 |
+
" </tr>\n",
|
| 2081 |
+
" </tbody>\n",
|
| 2082 |
+
"</table>\n",
|
| 2083 |
+
"<p>266 rows × 10 columns</p>\n",
|
| 2084 |
+
"</div>"
|
| 2085 |
+
],
|
| 2086 |
+
"text/plain": [
|
| 2087 |
+
" open high low close volume vwap adj_close \\\n",
|
| 2088 |
+
"date \n",
|
| 2089 |
+
"2023-08-22 80.80 80.99 80.10 80.35 287489 80.48 80.35 \n",
|
| 2090 |
+
"2023-08-23 79.64 79.91 77.62 78.89 378146 78.81 78.89 \n",
|
| 2091 |
+
"2023-08-24 78.57 79.28 77.59 79.05 349230 78.64 79.05 \n",
|
| 2092 |
+
"2023-08-25 78.88 80.45 78.14 79.83 411409 79.47 79.83 \n",
|
| 2093 |
+
"2023-08-28 80.15 80.87 79.61 80.10 246584 80.19 80.10 \n",
|
| 2094 |
+
"... ... ... ... ... ... ... ... \n",
|
| 2095 |
+
"2024-08-18 76.58 76.71 76.48 76.71 175 76.62 76.71 \n",
|
| 2096 |
+
"2024-08-19 76.58 76.87 74.17 74.37 118172 75.50 74.37 \n",
|
| 2097 |
+
"2024-08-20 74.34 75.03 73.50 74.04 118172 74.23 74.04 \n",
|
| 2098 |
+
"2024-08-21 73.12 74.16 71.46 71.93 361850 72.67 71.93 \n",
|
| 2099 |
+
"2024-08-22 71.93 73.52 71.58 73.00 28663 72.70 73.00 \n",
|
| 2100 |
+
"\n",
|
| 2101 |
+
" unadjusted_volume change change_percent \n",
|
| 2102 |
+
"date \n",
|
| 2103 |
+
"2023-08-22 287489.0 -0.45 -0.005569 \n",
|
| 2104 |
+
"2023-08-23 378146.0 -0.75 -0.009417 \n",
|
| 2105 |
+
"2023-08-24 349230.0 0.48 0.006109 \n",
|
| 2106 |
+
"2023-08-25 411409.0 0.95 0.012000 \n",
|
| 2107 |
+
"2023-08-28 246584.0 -0.05 -0.000624 \n",
|
| 2108 |
+
"... ... ... ... \n",
|
| 2109 |
+
"2024-08-18 175.0 0.13 0.001698 \n",
|
| 2110 |
+
"2024-08-19 118172.0 -2.21 -0.028900 \n",
|
| 2111 |
+
"2024-08-20 118172.0 -0.30 -0.004036 \n",
|
| 2112 |
+
"2024-08-21 361850.0 -1.19 -0.016300 \n",
|
| 2113 |
+
"2024-08-22 28663.0 1.07 0.014876 \n",
|
| 2114 |
+
"\n",
|
| 2115 |
+
"[266 rows x 10 columns]"
|
| 2116 |
+
]
|
| 2117 |
+
},
|
| 2118 |
+
"execution_count": 20,
|
| 2119 |
+
"metadata": {},
|
| 2120 |
+
"output_type": "execute_result"
|
| 2121 |
+
}
|
| 2122 |
+
],
|
| 2123 |
+
"source": [
|
| 2124 |
+
"obb.equity.price.historical(\"CL=F\", provider=\"fmp\").to_df()"
|
| 2125 |
+
]
|
| 2126 |
+
},
|
| 2127 |
+
{
|
| 2128 |
+
"cell_type": "code",
|
| 2129 |
+
"execution_count": 21,
|
| 2130 |
+
"metadata": {},
|
| 2131 |
+
"outputs": [
|
| 2132 |
+
{
|
| 2133 |
+
"data": {
|
| 2134 |
+
"text/html": [
|
| 2135 |
+
"<div>\n",
|
| 2136 |
+
"<style scoped>\n",
|
| 2137 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 2138 |
+
" vertical-align: middle;\n",
|
| 2139 |
+
" }\n",
|
| 2140 |
+
"\n",
|
| 2141 |
+
" .dataframe tbody tr th {\n",
|
| 2142 |
+
" vertical-align: top;\n",
|
| 2143 |
+
" }\n",
|
| 2144 |
+
"\n",
|
| 2145 |
+
" .dataframe thead th {\n",
|
| 2146 |
+
" text-align: right;\n",
|
| 2147 |
+
" }\n",
|
| 2148 |
+
"</style>\n",
|
| 2149 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 2150 |
+
" <thead>\n",
|
| 2151 |
+
" <tr style=\"text-align: right;\">\n",
|
| 2152 |
+
" <th></th>\n",
|
| 2153 |
+
" <th>open</th>\n",
|
| 2154 |
+
" <th>high</th>\n",
|
| 2155 |
+
" <th>low</th>\n",
|
| 2156 |
+
" <th>close</th>\n",
|
| 2157 |
+
" <th>volume</th>\n",
|
| 2158 |
+
" <th>split_ratio</th>\n",
|
| 2159 |
+
" <th>dividend</th>\n",
|
| 2160 |
+
" </tr>\n",
|
| 2161 |
+
" <tr>\n",
|
| 2162 |
+
" <th>date</th>\n",
|
| 2163 |
+
" <th></th>\n",
|
| 2164 |
+
" <th></th>\n",
|
| 2165 |
+
" <th></th>\n",
|
| 2166 |
+
" <th></th>\n",
|
| 2167 |
+
" <th></th>\n",
|
| 2168 |
+
" <th></th>\n",
|
| 2169 |
+
" <th></th>\n",
|
| 2170 |
+
" </tr>\n",
|
| 2171 |
+
" </thead>\n",
|
| 2172 |
+
" <tbody>\n",
|
| 2173 |
+
" <tr>\n",
|
| 2174 |
+
" <th>2023-08-22</th>\n",
|
| 2175 |
+
" <td>146.238007</td>\n",
|
| 2176 |
+
" <td>146.389999</td>\n",
|
| 2177 |
+
" <td>145.501999</td>\n",
|
| 2178 |
+
" <td>146.238007</td>\n",
|
| 2179 |
+
" <td>0</td>\n",
|
| 2180 |
+
" <td>0.0</td>\n",
|
| 2181 |
+
" <td>0.0</td>\n",
|
| 2182 |
+
" </tr>\n",
|
| 2183 |
+
" <tr>\n",
|
| 2184 |
+
" <th>2023-08-23</th>\n",
|
| 2185 |
+
" <td>145.763000</td>\n",
|
| 2186 |
+
" <td>145.813004</td>\n",
|
| 2187 |
+
" <td>144.580002</td>\n",
|
| 2188 |
+
" <td>145.763000</td>\n",
|
| 2189 |
+
" <td>0</td>\n",
|
| 2190 |
+
" <td>0.0</td>\n",
|
| 2191 |
+
" <td>0.0</td>\n",
|
| 2192 |
+
" </tr>\n",
|
| 2193 |
+
" <tr>\n",
|
| 2194 |
+
" <th>2023-08-24</th>\n",
|
| 2195 |
+
" <td>144.673004</td>\n",
|
| 2196 |
+
" <td>145.947006</td>\n",
|
| 2197 |
+
" <td>144.621002</td>\n",
|
| 2198 |
+
" <td>144.673004</td>\n",
|
| 2199 |
+
" <td>0</td>\n",
|
| 2200 |
+
" <td>0.0</td>\n",
|
| 2201 |
+
" <td>0.0</td>\n",
|
| 2202 |
+
" </tr>\n",
|
| 2203 |
+
" <tr>\n",
|
| 2204 |
+
" <th>2023-08-25</th>\n",
|
| 2205 |
+
" <td>146.067001</td>\n",
|
| 2206 |
+
" <td>146.604996</td>\n",
|
| 2207 |
+
" <td>145.733994</td>\n",
|
| 2208 |
+
" <td>146.067001</td>\n",
|
| 2209 |
+
" <td>0</td>\n",
|
| 2210 |
+
" <td>0.0</td>\n",
|
| 2211 |
+
" <td>0.0</td>\n",
|
| 2212 |
+
" </tr>\n",
|
| 2213 |
+
" <tr>\n",
|
| 2214 |
+
" <th>2023-08-28</th>\n",
|
| 2215 |
+
" <td>146.531006</td>\n",
|
| 2216 |
+
" <td>146.716003</td>\n",
|
| 2217 |
+
" <td>146.278000</td>\n",
|
| 2218 |
+
" <td>146.531006</td>\n",
|
| 2219 |
+
" <td>0</td>\n",
|
| 2220 |
+
" <td>0.0</td>\n",
|
| 2221 |
+
" <td>0.0</td>\n",
|
| 2222 |
+
" </tr>\n",
|
| 2223 |
+
" <tr>\n",
|
| 2224 |
+
" <th>...</th>\n",
|
| 2225 |
+
" <td>...</td>\n",
|
| 2226 |
+
" <td>...</td>\n",
|
| 2227 |
+
" <td>...</td>\n",
|
| 2228 |
+
" <td>...</td>\n",
|
| 2229 |
+
" <td>...</td>\n",
|
| 2230 |
+
" <td>...</td>\n",
|
| 2231 |
+
" <td>...</td>\n",
|
| 2232 |
+
" </tr>\n",
|
| 2233 |
+
" <tr>\n",
|
| 2234 |
+
" <th>2024-08-16</th>\n",
|
| 2235 |
+
" <td>149.222000</td>\n",
|
| 2236 |
+
" <td>149.229996</td>\n",
|
| 2237 |
+
" <td>147.639008</td>\n",
|
| 2238 |
+
" <td>149.222000</td>\n",
|
| 2239 |
+
" <td>0</td>\n",
|
| 2240 |
+
" <td>0.0</td>\n",
|
| 2241 |
+
" <td>0.0</td>\n",
|
| 2242 |
+
" </tr>\n",
|
| 2243 |
+
" <tr>\n",
|
| 2244 |
+
" <th>2024-08-19</th>\n",
|
| 2245 |
+
" <td>147.955994</td>\n",
|
| 2246 |
+
" <td>147.959000</td>\n",
|
| 2247 |
+
" <td>145.220993</td>\n",
|
| 2248 |
+
" <td>147.955994</td>\n",
|
| 2249 |
+
" <td>0</td>\n",
|
| 2250 |
+
" <td>0.0</td>\n",
|
| 2251 |
+
" <td>0.0</td>\n",
|
| 2252 |
+
" </tr>\n",
|
| 2253 |
+
" <tr>\n",
|
| 2254 |
+
" <th>2024-08-20</th>\n",
|
| 2255 |
+
" <td>146.699005</td>\n",
|
| 2256 |
+
" <td>147.319000</td>\n",
|
| 2257 |
+
" <td>145.533997</td>\n",
|
| 2258 |
+
" <td>146.699005</td>\n",
|
| 2259 |
+
" <td>0</td>\n",
|
| 2260 |
+
" <td>0.0</td>\n",
|
| 2261 |
+
" <td>0.0</td>\n",
|
| 2262 |
+
" </tr>\n",
|
| 2263 |
+
" <tr>\n",
|
| 2264 |
+
" <th>2024-08-21</th>\n",
|
| 2265 |
+
" <td>145.347000</td>\n",
|
| 2266 |
+
" <td>146.339005</td>\n",
|
| 2267 |
+
" <td>144.981003</td>\n",
|
| 2268 |
+
" <td>145.347000</td>\n",
|
| 2269 |
+
" <td>0</td>\n",
|
| 2270 |
+
" <td>0.0</td>\n",
|
| 2271 |
+
" <td>0.0</td>\n",
|
| 2272 |
+
" </tr>\n",
|
| 2273 |
+
" <tr>\n",
|
| 2274 |
+
" <th>2024-08-22</th>\n",
|
| 2275 |
+
" <td>145.117996</td>\n",
|
| 2276 |
+
" <td>146.524994</td>\n",
|
| 2277 |
+
" <td>144.839996</td>\n",
|
| 2278 |
+
" <td>146.292999</td>\n",
|
| 2279 |
+
" <td>0</td>\n",
|
| 2280 |
+
" <td>0.0</td>\n",
|
| 2281 |
+
" <td>0.0</td>\n",
|
| 2282 |
+
" </tr>\n",
|
| 2283 |
+
" </tbody>\n",
|
| 2284 |
+
"</table>\n",
|
| 2285 |
+
"<p>262 rows × 7 columns</p>\n",
|
| 2286 |
+
"</div>"
|
| 2287 |
+
],
|
| 2288 |
+
"text/plain": [
|
| 2289 |
+
" open high low close volume \\\n",
|
| 2290 |
+
"date \n",
|
| 2291 |
+
"2023-08-22 146.238007 146.389999 145.501999 146.238007 0 \n",
|
| 2292 |
+
"2023-08-23 145.763000 145.813004 144.580002 145.763000 0 \n",
|
| 2293 |
+
"2023-08-24 144.673004 145.947006 144.621002 144.673004 0 \n",
|
| 2294 |
+
"2023-08-25 146.067001 146.604996 145.733994 146.067001 0 \n",
|
| 2295 |
+
"2023-08-28 146.531006 146.716003 146.278000 146.531006 0 \n",
|
| 2296 |
+
"... ... ... ... ... ... \n",
|
| 2297 |
+
"2024-08-16 149.222000 149.229996 147.639008 149.222000 0 \n",
|
| 2298 |
+
"2024-08-19 147.955994 147.959000 145.220993 147.955994 0 \n",
|
| 2299 |
+
"2024-08-20 146.699005 147.319000 145.533997 146.699005 0 \n",
|
| 2300 |
+
"2024-08-21 145.347000 146.339005 144.981003 145.347000 0 \n",
|
| 2301 |
+
"2024-08-22 145.117996 146.524994 144.839996 146.292999 0 \n",
|
| 2302 |
+
"\n",
|
| 2303 |
+
" split_ratio dividend \n",
|
| 2304 |
+
"date \n",
|
| 2305 |
+
"2023-08-22 0.0 0.0 \n",
|
| 2306 |
+
"2023-08-23 0.0 0.0 \n",
|
| 2307 |
+
"2023-08-24 0.0 0.0 \n",
|
| 2308 |
+
"2023-08-25 0.0 0.0 \n",
|
| 2309 |
+
"2023-08-28 0.0 0.0 \n",
|
| 2310 |
+
"... ... ... \n",
|
| 2311 |
+
"2024-08-16 0.0 0.0 \n",
|
| 2312 |
+
"2024-08-19 0.0 0.0 \n",
|
| 2313 |
+
"2024-08-20 0.0 0.0 \n",
|
| 2314 |
+
"2024-08-21 0.0 0.0 \n",
|
| 2315 |
+
"2024-08-22 0.0 0.0 \n",
|
| 2316 |
+
"\n",
|
| 2317 |
+
"[262 rows x 7 columns]"
|
| 2318 |
+
]
|
| 2319 |
+
},
|
| 2320 |
+
"execution_count": 21,
|
| 2321 |
+
"metadata": {},
|
| 2322 |
+
"output_type": "execute_result"
|
| 2323 |
+
}
|
| 2324 |
+
],
|
| 2325 |
+
"source": [
|
| 2326 |
+
"obb.equity.price.historical(\"usdjpy=x\", provider=\"yfinance\").to_df()"
|
| 2327 |
+
]
|
| 2328 |
+
},
|
| 2329 |
+
{
|
| 2330 |
+
"cell_type": "code",
|
| 2331 |
+
"execution_count": 22,
|
| 2332 |
+
"metadata": {},
|
| 2333 |
+
"outputs": [
|
| 2334 |
+
{
|
| 2335 |
+
"data": {
|
| 2336 |
+
"text/html": [
|
| 2337 |
+
"<div>\n",
|
| 2338 |
+
"<style scoped>\n",
|
| 2339 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 2340 |
+
" vertical-align: middle;\n",
|
| 2341 |
+
" }\n",
|
| 2342 |
+
"\n",
|
| 2343 |
+
" .dataframe tbody tr th {\n",
|
| 2344 |
+
" vertical-align: top;\n",
|
| 2345 |
+
" }\n",
|
| 2346 |
+
"\n",
|
| 2347 |
+
" .dataframe thead th {\n",
|
| 2348 |
+
" text-align: right;\n",
|
| 2349 |
+
" }\n",
|
| 2350 |
+
"</style>\n",
|
| 2351 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 2352 |
+
" <thead>\n",
|
| 2353 |
+
" <tr style=\"text-align: right;\">\n",
|
| 2354 |
+
" <th></th>\n",
|
| 2355 |
+
" <th>open</th>\n",
|
| 2356 |
+
" <th>high</th>\n",
|
| 2357 |
+
" <th>low</th>\n",
|
| 2358 |
+
" <th>close</th>\n",
|
| 2359 |
+
" <th>volume</th>\n",
|
| 2360 |
+
" </tr>\n",
|
| 2361 |
+
" <tr>\n",
|
| 2362 |
+
" <th>date</th>\n",
|
| 2363 |
+
" <th></th>\n",
|
| 2364 |
+
" <th></th>\n",
|
| 2365 |
+
" <th></th>\n",
|
| 2366 |
+
" <th></th>\n",
|
| 2367 |
+
" <th></th>\n",
|
| 2368 |
+
" </tr>\n",
|
| 2369 |
+
" </thead>\n",
|
| 2370 |
+
" <tbody>\n",
|
| 2371 |
+
" <tr>\n",
|
| 2372 |
+
" <th>2023-08-22</th>\n",
|
| 2373 |
+
" <td>146.238007</td>\n",
|
| 2374 |
+
" <td>146.389999</td>\n",
|
| 2375 |
+
" <td>145.501999</td>\n",
|
| 2376 |
+
" <td>146.238007</td>\n",
|
| 2377 |
+
" <td>0.0</td>\n",
|
| 2378 |
+
" </tr>\n",
|
| 2379 |
+
" <tr>\n",
|
| 2380 |
+
" <th>2023-08-23</th>\n",
|
| 2381 |
+
" <td>145.763000</td>\n",
|
| 2382 |
+
" <td>145.813004</td>\n",
|
| 2383 |
+
" <td>144.580002</td>\n",
|
| 2384 |
+
" <td>145.763000</td>\n",
|
| 2385 |
+
" <td>0.0</td>\n",
|
| 2386 |
+
" </tr>\n",
|
| 2387 |
+
" <tr>\n",
|
| 2388 |
+
" <th>2023-08-24</th>\n",
|
| 2389 |
+
" <td>144.673004</td>\n",
|
| 2390 |
+
" <td>145.947006</td>\n",
|
| 2391 |
+
" <td>144.621002</td>\n",
|
| 2392 |
+
" <td>144.673004</td>\n",
|
| 2393 |
+
" <td>0.0</td>\n",
|
| 2394 |
+
" </tr>\n",
|
| 2395 |
+
" <tr>\n",
|
| 2396 |
+
" <th>2023-08-25</th>\n",
|
| 2397 |
+
" <td>146.067001</td>\n",
|
| 2398 |
+
" <td>146.604996</td>\n",
|
| 2399 |
+
" <td>145.733994</td>\n",
|
| 2400 |
+
" <td>146.067001</td>\n",
|
| 2401 |
+
" <td>0.0</td>\n",
|
| 2402 |
+
" </tr>\n",
|
| 2403 |
+
" <tr>\n",
|
| 2404 |
+
" <th>2023-08-28</th>\n",
|
| 2405 |
+
" <td>146.531006</td>\n",
|
| 2406 |
+
" <td>146.716003</td>\n",
|
| 2407 |
+
" <td>146.278000</td>\n",
|
| 2408 |
+
" <td>146.531006</td>\n",
|
| 2409 |
+
" <td>0.0</td>\n",
|
| 2410 |
+
" </tr>\n",
|
| 2411 |
+
" <tr>\n",
|
| 2412 |
+
" <th>...</th>\n",
|
| 2413 |
+
" <td>...</td>\n",
|
| 2414 |
+
" <td>...</td>\n",
|
| 2415 |
+
" <td>...</td>\n",
|
| 2416 |
+
" <td>...</td>\n",
|
| 2417 |
+
" <td>...</td>\n",
|
| 2418 |
+
" </tr>\n",
|
| 2419 |
+
" <tr>\n",
|
| 2420 |
+
" <th>2024-08-16</th>\n",
|
| 2421 |
+
" <td>149.222000</td>\n",
|
| 2422 |
+
" <td>149.229996</td>\n",
|
| 2423 |
+
" <td>147.639008</td>\n",
|
| 2424 |
+
" <td>149.222000</td>\n",
|
| 2425 |
+
" <td>0.0</td>\n",
|
| 2426 |
+
" </tr>\n",
|
| 2427 |
+
" <tr>\n",
|
| 2428 |
+
" <th>2024-08-19</th>\n",
|
| 2429 |
+
" <td>147.955994</td>\n",
|
| 2430 |
+
" <td>147.959000</td>\n",
|
| 2431 |
+
" <td>145.220993</td>\n",
|
| 2432 |
+
" <td>147.955994</td>\n",
|
| 2433 |
+
" <td>0.0</td>\n",
|
| 2434 |
+
" </tr>\n",
|
| 2435 |
+
" <tr>\n",
|
| 2436 |
+
" <th>2024-08-20</th>\n",
|
| 2437 |
+
" <td>146.699005</td>\n",
|
| 2438 |
+
" <td>147.319000</td>\n",
|
| 2439 |
+
" <td>145.533997</td>\n",
|
| 2440 |
+
" <td>146.699005</td>\n",
|
| 2441 |
+
" <td>0.0</td>\n",
|
| 2442 |
+
" </tr>\n",
|
| 2443 |
+
" <tr>\n",
|
| 2444 |
+
" <th>2024-08-21</th>\n",
|
| 2445 |
+
" <td>145.347000</td>\n",
|
| 2446 |
+
" <td>146.339005</td>\n",
|
| 2447 |
+
" <td>144.981003</td>\n",
|
| 2448 |
+
" <td>145.347000</td>\n",
|
| 2449 |
+
" <td>0.0</td>\n",
|
| 2450 |
+
" </tr>\n",
|
| 2451 |
+
" <tr>\n",
|
| 2452 |
+
" <th>2024-08-22</th>\n",
|
| 2453 |
+
" <td>145.117996</td>\n",
|
| 2454 |
+
" <td>146.524994</td>\n",
|
| 2455 |
+
" <td>144.839996</td>\n",
|
| 2456 |
+
" <td>146.287003</td>\n",
|
| 2457 |
+
" <td>0.0</td>\n",
|
| 2458 |
+
" </tr>\n",
|
| 2459 |
+
" </tbody>\n",
|
| 2460 |
+
"</table>\n",
|
| 2461 |
+
"<p>262 rows × 5 columns</p>\n",
|
| 2462 |
+
"</div>"
|
| 2463 |
+
],
|
| 2464 |
+
"text/plain": [
|
| 2465 |
+
" open high low close volume\n",
|
| 2466 |
+
"date \n",
|
| 2467 |
+
"2023-08-22 146.238007 146.389999 145.501999 146.238007 0.0\n",
|
| 2468 |
+
"2023-08-23 145.763000 145.813004 144.580002 145.763000 0.0\n",
|
| 2469 |
+
"2023-08-24 144.673004 145.947006 144.621002 144.673004 0.0\n",
|
| 2470 |
+
"2023-08-25 146.067001 146.604996 145.733994 146.067001 0.0\n",
|
| 2471 |
+
"2023-08-28 146.531006 146.716003 146.278000 146.531006 0.0\n",
|
| 2472 |
+
"... ... ... ... ... ...\n",
|
| 2473 |
+
"2024-08-16 149.222000 149.229996 147.639008 149.222000 0.0\n",
|
| 2474 |
+
"2024-08-19 147.955994 147.959000 145.220993 147.955994 0.0\n",
|
| 2475 |
+
"2024-08-20 146.699005 147.319000 145.533997 146.699005 0.0\n",
|
| 2476 |
+
"2024-08-21 145.347000 146.339005 144.981003 145.347000 0.0\n",
|
| 2477 |
+
"2024-08-22 145.117996 146.524994 144.839996 146.287003 0.0\n",
|
| 2478 |
+
"\n",
|
| 2479 |
+
"[262 rows x 5 columns]"
|
| 2480 |
+
]
|
| 2481 |
+
},
|
| 2482 |
+
"execution_count": 22,
|
| 2483 |
+
"metadata": {},
|
| 2484 |
+
"output_type": "execute_result"
|
| 2485 |
+
}
|
| 2486 |
+
],
|
| 2487 |
+
"source": [
|
| 2488 |
+
"obb.currency.price.historical(\"usdjpy\", provider=\"yfinance\").to_df()"
|
| 2489 |
+
]
|
| 2490 |
+
}
|
| 2491 |
+
],
|
| 2492 |
+
"metadata": {
|
| 2493 |
+
"kernelspec": {
|
| 2494 |
+
"display_name": "obb",
|
| 2495 |
+
"language": "python",
|
| 2496 |
+
"name": "python3"
|
| 2497 |
+
},
|
| 2498 |
+
"language_info": {
|
| 2499 |
+
"codemirror_mode": {
|
| 2500 |
+
"name": "ipython",
|
| 2501 |
+
"version": 3
|
| 2502 |
+
},
|
| 2503 |
+
"file_extension": ".py",
|
| 2504 |
+
"mimetype": "text/x-python",
|
| 2505 |
+
"name": "python",
|
| 2506 |
+
"nbconvert_exporter": "python",
|
| 2507 |
+
"pygments_lexer": "ipython3",
|
| 2508 |
+
"version": "3.12.4"
|
| 2509 |
+
},
|
| 2510 |
+
"orig_nbformat": 4
|
| 2511 |
+
},
|
| 2512 |
+
"nbformat": 4,
|
| 2513 |
+
"nbformat_minor": 2
|
| 2514 |
+
}
|
examples/mAndAImpact.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/openbb-apachebeam/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# OBB Dataflow Sample
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
This is a sample how to invoke OBB fetchers in an Apache Beam pipeline. (GCP dataflow is build on Apache Beam)
|
| 5 |
+
Pre-requisites
|
| 6 |
+
- You need to create a Conda environment (or a virtual env) using requirements.txt in this directory
|
| 7 |
+
- The script exercise 3 OBB endpoints, all of which require no credentials
|
| 8 |
+
- Run the test from the main directory
|
| 9 |
+
python -m unittest .\tests\test_obb_pipeline.py
|
| 10 |
+
|
| 11 |
+
The script will run a pipeline consisting of 3 task which will fetch AAPL quote, profile and news
|
| 12 |
+
This is just a very basic sample which can be used as building block to create more complex scenarios
|
examples/openbb-apachebeam/requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
apache-beam
|
| 2 |
+
openbb-yfinance
|
examples/openbb-apachebeam/tests/__init__.py
ADDED
|
File without changes
|
examples/openbb-apachebeam/tests/test_obb_pipeline.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import unittest
|
| 2 |
+
from apache_beam.testing.test_pipeline import TestPipeline
|
| 3 |
+
from apache_beam.options.pipeline_options import PipelineOptions
|
| 4 |
+
import asyncio
|
| 5 |
+
import apache_beam as beam
|
| 6 |
+
from openbb_yfinance.models.equity_quote import YFinanceEquityQuoteFetcher as quote_fetcher
|
| 7 |
+
from openbb_yfinance.models.equity_profile import YFinanceEquityProfileFetcher as profile_fetcher
|
| 8 |
+
from openbb_yfinance.models.company_news import YFinanceCompanyNewsFetcher as news_fetcher
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class AsyncProcess(beam.DoFn):
|
| 12 |
+
|
| 13 |
+
def __init__(self, credentials, fetcher):
|
| 14 |
+
self.credentials = credentials
|
| 15 |
+
self.fetcher = fetcher
|
| 16 |
+
|
| 17 |
+
async def fetch_data(self, element: str):
|
| 18 |
+
params = dict(symbol=element)
|
| 19 |
+
data = await self.fetcher.fetch_data(params, self.credentials)
|
| 20 |
+
return [d.model_dump(exclude_none=True) for d in data]
|
| 21 |
+
|
| 22 |
+
def process(self, element: str):
|
| 23 |
+
return asyncio.run(self.fetch_data(element))
|
| 24 |
+
|
| 25 |
+
class MyTestCase(unittest.TestCase):
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_sample_pipeline(self):
|
| 29 |
+
credentials = {} # Running OBB endpoints which do not require credentials
|
| 30 |
+
debug_sink = beam.Map(print)
|
| 31 |
+
ticker = 'AAPL'
|
| 32 |
+
|
| 33 |
+
with TestPipeline(options=PipelineOptions()) as p:
|
| 34 |
+
quote = (p | 'Start Quote' >> beam.Create([ticker])
|
| 35 |
+
| 'Run Quote' >> beam.ParDo(AsyncProcess(credentials, quote_fetcher))
|
| 36 |
+
| 'Print quote' >> debug_sink)
|
| 37 |
+
|
| 38 |
+
profile = (p | 'Start Profile' >> beam.Create([ticker])
|
| 39 |
+
| 'Run Profile' >> beam.ParDo(AsyncProcess(credentials, profile_fetcher))
|
| 40 |
+
| 'Print profile' >> debug_sink)
|
| 41 |
+
|
| 42 |
+
news = (p | 'Start News' >> beam.Create([ticker])
|
| 43 |
+
| 'Run News' >> beam.ParDo(AsyncProcess(credentials, news_fetcher))
|
| 44 |
+
| 'Print nes' >> debug_sink)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
if __name__ == '__main__':
|
| 48 |
+
unittest.main()
|
examples/openbbPlatformAsLLMTools.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/platform_standardization.ipynb
ADDED
|
@@ -0,0 +1,761 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# How The OpenBB Platform Works"
|
| 8 |
+
]
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"cell_type": "code",
|
| 12 |
+
"execution_count": 1,
|
| 13 |
+
"metadata": {},
|
| 14 |
+
"outputs": [],
|
| 15 |
+
"source": [
|
| 16 |
+
"from openbb import obb"
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"execution_count": null,
|
| 22 |
+
"metadata": {},
|
| 23 |
+
"outputs": [],
|
| 24 |
+
"source": [
|
| 25 |
+
"obb"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "code",
|
| 30 |
+
"execution_count": 3,
|
| 31 |
+
"metadata": {},
|
| 32 |
+
"outputs": [
|
| 33 |
+
{
|
| 34 |
+
"data": {
|
| 35 |
+
"text/plain": [
|
| 36 |
+
"/news\n",
|
| 37 |
+
" company\n",
|
| 38 |
+
" world\n",
|
| 39 |
+
" "
|
| 40 |
+
]
|
| 41 |
+
},
|
| 42 |
+
"execution_count": 3,
|
| 43 |
+
"metadata": {},
|
| 44 |
+
"output_type": "execute_result"
|
| 45 |
+
}
|
| 46 |
+
],
|
| 47 |
+
"source": [
|
| 48 |
+
"obb.news"
|
| 49 |
+
]
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
"cell_type": "code",
|
| 53 |
+
"execution_count": 4,
|
| 54 |
+
"metadata": {},
|
| 55 |
+
"outputs": [
|
| 56 |
+
{
|
| 57 |
+
"name": "stdout",
|
| 58 |
+
"output_type": "stream",
|
| 59 |
+
"text": [
|
| 60 |
+
"Help on method world in module openbb.package.news:\n",
|
| 61 |
+
"\n",
|
| 62 |
+
"world(limit: Annotated[int, OpenBBField(description='The number of data entries to return. The number of articles to return.')] = 2500, start_date: Annotated[Union[datetime.date, NoneType, str], OpenBBField(description='Start date of the data, in YYYY-MM-DD format.')] = None, end_date: Annotated[Union[datetime.date, NoneType, str], OpenBBField(description='End date of the data, in YYYY-MM-DD format.')] = None, provider: Annotated[Optional[Literal['benzinga', 'biztoc', 'fmp', 'intrinio', 'tiingo']], OpenBBField(description='The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: benzinga, biztoc, fmp, intrinio, tiingo.')] = None, **kwargs) -> openbb_core.app.model.obbject.OBBject method of openbb.package.news.ROUTER_news instance\n",
|
| 63 |
+
" World News. Global news data.\n",
|
| 64 |
+
"\n",
|
| 65 |
+
" Parameters\n",
|
| 66 |
+
" ----------\n",
|
| 67 |
+
" limit : int\n",
|
| 68 |
+
" The number of data entries to return. The number of articles to return.\n",
|
| 69 |
+
" start_date : Union[date, None, str]\n",
|
| 70 |
+
" Start date of the data, in YYYY-MM-DD format.\n",
|
| 71 |
+
" end_date : Union[date, None, str]\n",
|
| 72 |
+
" End date of the data, in YYYY-MM-DD format.\n",
|
| 73 |
+
" provider : Optional[Literal['benzinga', 'biztoc', 'fmp', 'intrinio', 'tiingo']]\n",
|
| 74 |
+
" The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: benzinga, biztoc, fmp, intrinio, tiingo.\n",
|
| 75 |
+
" date : Optional[datetime.date]\n",
|
| 76 |
+
" A specific date to get data for. (provider: benzinga)\n",
|
| 77 |
+
" display : Literal['headline', 'abstract', 'full']\n",
|
| 78 |
+
" Specify headline only (headline), headline + teaser (abstract), or headline + full body (full). (provider: benzinga)\n",
|
| 79 |
+
" updated_since : Optional[int]\n",
|
| 80 |
+
" Number of seconds since the news was updated. (provider: benzinga)\n",
|
| 81 |
+
" published_since : Optional[int]\n",
|
| 82 |
+
" Number of seconds since the news was published. (provider: benzinga)\n",
|
| 83 |
+
" sort : Literal['id', 'created', 'updated']\n",
|
| 84 |
+
" Key to sort the news by. (provider: benzinga)\n",
|
| 85 |
+
" order : Literal['asc', 'desc']\n",
|
| 86 |
+
" Order to sort the news by. (provider: benzinga)\n",
|
| 87 |
+
" isin : Optional[str]\n",
|
| 88 |
+
" The ISIN of the news to retrieve. (provider: benzinga)\n",
|
| 89 |
+
" cusip : Optional[str]\n",
|
| 90 |
+
" The CUSIP of the news to retrieve. (provider: benzinga)\n",
|
| 91 |
+
" channels : Optional[str]\n",
|
| 92 |
+
" Channels of the news to retrieve. (provider: benzinga)\n",
|
| 93 |
+
" topics : Optional[str]\n",
|
| 94 |
+
" Topics of the news to retrieve. (provider: benzinga)\n",
|
| 95 |
+
" authors : Optional[str]\n",
|
| 96 |
+
" Authors of the news to retrieve. (provider: benzinga)\n",
|
| 97 |
+
" content_types : Optional[str]\n",
|
| 98 |
+
" Content types of the news to retrieve. (provider: benzinga)\n",
|
| 99 |
+
" term : Optional[str]\n",
|
| 100 |
+
" Search term to filter articles by. This overrides all other filters. (provider: biztoc)\n",
|
| 101 |
+
" source : Optional[Union[str, Literal['yahoo', 'moody', 'moody_us_news', 'moody_us_press_releases']]]\n",
|
| 102 |
+
" Filter by a specific publisher. Only valid when filter is set to source. (provider: biztoc);\n",
|
| 103 |
+
" The source of the news article. (provider: intrinio);\n",
|
| 104 |
+
" A comma-separated list of the domains requested. (provider: tiingo)\n",
|
| 105 |
+
" sentiment : Optional[Literal['positive', 'neutral', 'negative']]\n",
|
| 106 |
+
" Return news only from this source. (provider: intrinio)\n",
|
| 107 |
+
" language : Optional[str]\n",
|
| 108 |
+
" Filter by language. Unsupported for yahoo source. (provider: intrinio)\n",
|
| 109 |
+
" topic : Optional[str]\n",
|
| 110 |
+
" Filter by topic. Unsupported for yahoo source. (provider: intrinio)\n",
|
| 111 |
+
" word_count_greater_than : Optional[int]\n",
|
| 112 |
+
" News stories will have a word count greater than this value. Unsupported for yahoo source. (provider: intrinio)\n",
|
| 113 |
+
" word_count_less_than : Optional[int]\n",
|
| 114 |
+
" News stories will have a word count less than this value. Unsupported for yahoo source. (provider: intrinio)\n",
|
| 115 |
+
" is_spam : Optional[bool]\n",
|
| 116 |
+
" Filter whether it is marked as spam or not. Unsupported for yahoo source. (provider: intrinio)\n",
|
| 117 |
+
" business_relevance_greater_than : Optional[float]\n",
|
| 118 |
+
" News stories will have a business relevance score more than this value. Unsupported for yahoo source. Value is a decimal between 0 and 1. (provider: intrinio)\n",
|
| 119 |
+
" business_relevance_less_than : Optional[float]\n",
|
| 120 |
+
" News stories will have a business relevance score less than this value. Unsupported for yahoo source. Value is a decimal between 0 and 1. (provider: intrinio)\n",
|
| 121 |
+
" offset : Optional[int]\n",
|
| 122 |
+
" Page offset, used in conjunction with limit. (provider: tiingo)\n",
|
| 123 |
+
"\n",
|
| 124 |
+
" Returns\n",
|
| 125 |
+
" -------\n",
|
| 126 |
+
" OBBject\n",
|
| 127 |
+
" results : List[WorldNews]\n",
|
| 128 |
+
" Serializable results.\n",
|
| 129 |
+
" provider : Optional[Literal['benzinga', 'biztoc', 'fmp', 'intrinio', 'tiingo']]\n",
|
| 130 |
+
" Provider name.\n",
|
| 131 |
+
" warnings : Optional[List[Warning_]]\n",
|
| 132 |
+
" List of warnings.\n",
|
| 133 |
+
" chart : Optional[Chart]\n",
|
| 134 |
+
" Chart object.\n",
|
| 135 |
+
" extra : Dict[str, Any]\n",
|
| 136 |
+
" Extra info.\n",
|
| 137 |
+
"\n",
|
| 138 |
+
" WorldNews\n",
|
| 139 |
+
" ---------\n",
|
| 140 |
+
" date : datetime\n",
|
| 141 |
+
" The date of the data. The published date of the article.\n",
|
| 142 |
+
" title : str\n",
|
| 143 |
+
" Title of the article.\n",
|
| 144 |
+
" images : Optional[List[Dict[str, str]]]\n",
|
| 145 |
+
" Images associated with the article.\n",
|
| 146 |
+
" text : Optional[str]\n",
|
| 147 |
+
" Text/body of the article.\n",
|
| 148 |
+
" url : Optional[str]\n",
|
| 149 |
+
" URL to the article.\n",
|
| 150 |
+
" id : Optional[str]\n",
|
| 151 |
+
" Article ID. (provider: benzinga, intrinio)\n",
|
| 152 |
+
" author : Optional[str]\n",
|
| 153 |
+
" Author of the news. (provider: benzinga)\n",
|
| 154 |
+
" teaser : Optional[str]\n",
|
| 155 |
+
" Teaser of the news. (provider: benzinga)\n",
|
| 156 |
+
" channels : Optional[str]\n",
|
| 157 |
+
" Channels associated with the news. (provider: benzinga)\n",
|
| 158 |
+
" stocks : Optional[str]\n",
|
| 159 |
+
" Stocks associated with the news. (provider: benzinga)\n",
|
| 160 |
+
" tags : Optional[Union[str, List[str]]]\n",
|
| 161 |
+
" Tags associated with the news. (provider: benzinga, biztoc, tiingo)\n",
|
| 162 |
+
" updated : Optional[datetime]\n",
|
| 163 |
+
" Updated date of the news. (provider: benzinga)\n",
|
| 164 |
+
" score : Optional[float]\n",
|
| 165 |
+
" Search relevance score for the article. (provider: biztoc)\n",
|
| 166 |
+
" site : Optional[str]\n",
|
| 167 |
+
" News source. (provider: fmp, tiingo)\n",
|
| 168 |
+
" source : Optional[str]\n",
|
| 169 |
+
" The source of the news article. (provider: intrinio)\n",
|
| 170 |
+
" summary : Optional[str]\n",
|
| 171 |
+
" The summary of the news article. (provider: intrinio)\n",
|
| 172 |
+
" topics : Optional[str]\n",
|
| 173 |
+
" The topics related to the news article. (provider: intrinio)\n",
|
| 174 |
+
" word_count : Optional[int]\n",
|
| 175 |
+
" The word count of the news article. (provider: intrinio)\n",
|
| 176 |
+
" business_relevance : Optional[float]\n",
|
| 177 |
+
" How strongly correlated the news article is to the business (provider: intrinio)\n",
|
| 178 |
+
" sentiment : Optional[str]\n",
|
| 179 |
+
" The sentiment of the news article - i.e, negative, positive. (provider: intrinio)\n",
|
| 180 |
+
" sentiment_confidence : Optional[float]\n",
|
| 181 |
+
" The confidence score of the sentiment rating. (provider: intrinio)\n",
|
| 182 |
+
" language : Optional[str]\n",
|
| 183 |
+
" The language of the news article. (provider: intrinio)\n",
|
| 184 |
+
" spam : Optional[bool]\n",
|
| 185 |
+
" Whether the news article is spam. (provider: intrinio)\n",
|
| 186 |
+
" copyright : Optional[str]\n",
|
| 187 |
+
" The copyright notice of the news article. (provider: intrinio)\n",
|
| 188 |
+
" company : Optional[IntrinioCompany]\n",
|
| 189 |
+
" The Intrinio Company object. Contains details company reference data. (provider: intrinio)\n",
|
| 190 |
+
" security : Optional[IntrinioSecurity]\n",
|
| 191 |
+
" The Intrinio Security object. Contains the security details related to the news article. (provider: intrinio)\n",
|
| 192 |
+
" symbols : Optional[str]\n",
|
| 193 |
+
" Ticker tagged in the fetched news. (provider: tiingo)\n",
|
| 194 |
+
" article_id : Optional[int]\n",
|
| 195 |
+
" Unique ID of the news article. (provider: tiingo)\n",
|
| 196 |
+
" crawl_date : Optional[datetime]\n",
|
| 197 |
+
" Date the news article was crawled. (provider: tiingo)\n",
|
| 198 |
+
"\n",
|
| 199 |
+
" Examples\n",
|
| 200 |
+
" --------\n",
|
| 201 |
+
" >>> from openbb import obb\n",
|
| 202 |
+
" >>> obb.news.world(provider='fmp')\n",
|
| 203 |
+
" >>> obb.news.world(limit=100, provider='intrinio')\n",
|
| 204 |
+
" >>> # Get news on the specified dates.\n",
|
| 205 |
+
" >>> obb.news.world(start_date='2024-02-01', end_date='2024-02-07', provider='intrinio')\n",
|
| 206 |
+
" >>> # Display the headlines of the news.\n",
|
| 207 |
+
" >>> obb.news.world(display='headline', provider='benzinga')\n",
|
| 208 |
+
" >>> # Get news by topics.\n",
|
| 209 |
+
" >>> obb.news.world(topics='finance', provider='benzinga')\n",
|
| 210 |
+
" >>> # Get news by source using 'tingo' as provider.\n",
|
| 211 |
+
" >>> obb.news.world(provider='tiingo', source='bloomberg')\n",
|
| 212 |
+
" >>> # Filter aticles by term using 'biztoc' as provider.\n",
|
| 213 |
+
" >>> obb.news.world(provider='biztoc', term='apple')\n",
|
| 214 |
+
"\n"
|
| 215 |
+
]
|
| 216 |
+
}
|
| 217 |
+
],
|
| 218 |
+
"source": [
|
| 219 |
+
"help(obb.news.world)"
|
| 220 |
+
]
|
| 221 |
+
},
|
| 222 |
+
{
|
| 223 |
+
"cell_type": "markdown",
|
| 224 |
+
"metadata": {},
|
| 225 |
+
"source": [
|
| 226 |
+
"Uniform interface allows switching between providers"
|
| 227 |
+
]
|
| 228 |
+
},
|
| 229 |
+
{
|
| 230 |
+
"cell_type": "code",
|
| 231 |
+
"execution_count": 5,
|
| 232 |
+
"metadata": {},
|
| 233 |
+
"outputs": [
|
| 234 |
+
{
|
| 235 |
+
"data": {
|
| 236 |
+
"text/html": [
|
| 237 |
+
"<div>\n",
|
| 238 |
+
"<style scoped>\n",
|
| 239 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 240 |
+
" vertical-align: middle;\n",
|
| 241 |
+
" }\n",
|
| 242 |
+
"\n",
|
| 243 |
+
" .dataframe tbody tr th {\n",
|
| 244 |
+
" vertical-align: top;\n",
|
| 245 |
+
" }\n",
|
| 246 |
+
"\n",
|
| 247 |
+
" .dataframe thead th {\n",
|
| 248 |
+
" text-align: right;\n",
|
| 249 |
+
" }\n",
|
| 250 |
+
"</style>\n",
|
| 251 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 252 |
+
" <thead>\n",
|
| 253 |
+
" <tr style=\"text-align: right;\">\n",
|
| 254 |
+
" <th>date</th>\n",
|
| 255 |
+
" <th>2024-08-22 18:02:00+00:00</th>\n",
|
| 256 |
+
" </tr>\n",
|
| 257 |
+
" </thead>\n",
|
| 258 |
+
" <tbody>\n",
|
| 259 |
+
" <tr>\n",
|
| 260 |
+
" <th>title</th>\n",
|
| 261 |
+
" <td>Natural Grocers® Teams Up With Local Artist, S...</td>\n",
|
| 262 |
+
" </tr>\n",
|
| 263 |
+
" <tr>\n",
|
| 264 |
+
" <th>text</th>\n",
|
| 265 |
+
" <td>Natural Grocers®, the leading family-operated ...</td>\n",
|
| 266 |
+
" </tr>\n",
|
| 267 |
+
" <tr>\n",
|
| 268 |
+
" <th>url</th>\n",
|
| 269 |
+
" <td>https://finance.yahoo.com/news/natural-grocers...</td>\n",
|
| 270 |
+
" </tr>\n",
|
| 271 |
+
" <tr>\n",
|
| 272 |
+
" <th>source</th>\n",
|
| 273 |
+
" <td>yahoo</td>\n",
|
| 274 |
+
" </tr>\n",
|
| 275 |
+
" <tr>\n",
|
| 276 |
+
" <th>id</th>\n",
|
| 277 |
+
" <td>new_DDGR2v</td>\n",
|
| 278 |
+
" </tr>\n",
|
| 279 |
+
" <tr>\n",
|
| 280 |
+
" <th>company</th>\n",
|
| 281 |
+
" <td>{'id': 'com_g4Q8NX', 'ticker': 'NGVC', 'name':...</td>\n",
|
| 282 |
+
" </tr>\n",
|
| 283 |
+
" </tbody>\n",
|
| 284 |
+
"</table>\n",
|
| 285 |
+
"</div>"
|
| 286 |
+
],
|
| 287 |
+
"text/plain": [
|
| 288 |
+
"date 2024-08-22 18:02:00+00:00\n",
|
| 289 |
+
"title Natural Grocers® Teams Up With Local Artist, S...\n",
|
| 290 |
+
"text Natural Grocers®, the leading family-operated ...\n",
|
| 291 |
+
"url https://finance.yahoo.com/news/natural-grocers...\n",
|
| 292 |
+
"source yahoo\n",
|
| 293 |
+
"id new_DDGR2v\n",
|
| 294 |
+
"company {'id': 'com_g4Q8NX', 'ticker': 'NGVC', 'name':..."
|
| 295 |
+
]
|
| 296 |
+
},
|
| 297 |
+
"execution_count": 5,
|
| 298 |
+
"metadata": {},
|
| 299 |
+
"output_type": "execute_result"
|
| 300 |
+
}
|
| 301 |
+
],
|
| 302 |
+
"source": [
|
| 303 |
+
"obb.news.world(limit=1, provider=\"intrinio\").to_df().T"
|
| 304 |
+
]
|
| 305 |
+
},
|
| 306 |
+
{
|
| 307 |
+
"cell_type": "code",
|
| 308 |
+
"execution_count": 6,
|
| 309 |
+
"metadata": {},
|
| 310 |
+
"outputs": [
|
| 311 |
+
{
|
| 312 |
+
"data": {
|
| 313 |
+
"text/html": [
|
| 314 |
+
"<div>\n",
|
| 315 |
+
"<style scoped>\n",
|
| 316 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 317 |
+
" vertical-align: middle;\n",
|
| 318 |
+
" }\n",
|
| 319 |
+
"\n",
|
| 320 |
+
" .dataframe tbody tr th {\n",
|
| 321 |
+
" vertical-align: top;\n",
|
| 322 |
+
" }\n",
|
| 323 |
+
"\n",
|
| 324 |
+
" .dataframe thead th {\n",
|
| 325 |
+
" text-align: right;\n",
|
| 326 |
+
" }\n",
|
| 327 |
+
"</style>\n",
|
| 328 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 329 |
+
" <thead>\n",
|
| 330 |
+
" <tr style=\"text-align: right;\">\n",
|
| 331 |
+
" <th>date</th>\n",
|
| 332 |
+
" <th>2024-08-22 14:46:33-04:00</th>\n",
|
| 333 |
+
" </tr>\n",
|
| 334 |
+
" </thead>\n",
|
| 335 |
+
" <tbody>\n",
|
| 336 |
+
" <tr>\n",
|
| 337 |
+
" <th>title</th>\n",
|
| 338 |
+
" <td>Behind the Scenes of Vertiv Hldgs's Latest Opt...</td>\n",
|
| 339 |
+
" </tr>\n",
|
| 340 |
+
" <tr>\n",
|
| 341 |
+
" <th>images</th>\n",
|
| 342 |
+
" <td>[{'size': 'thumb', 'url': 'https://cdn.benzing...</td>\n",
|
| 343 |
+
" </tr>\n",
|
| 344 |
+
" <tr>\n",
|
| 345 |
+
" <th>text</th>\n",
|
| 346 |
+
" <td><p>Whales with a lot of money to spend have ta...</td>\n",
|
| 347 |
+
" </tr>\n",
|
| 348 |
+
" <tr>\n",
|
| 349 |
+
" <th>url</th>\n",
|
| 350 |
+
" <td>https://www.benzinga.com/insights/options/24/0...</td>\n",
|
| 351 |
+
" </tr>\n",
|
| 352 |
+
" <tr>\n",
|
| 353 |
+
" <th>id</th>\n",
|
| 354 |
+
" <td>40515079</td>\n",
|
| 355 |
+
" </tr>\n",
|
| 356 |
+
" <tr>\n",
|
| 357 |
+
" <th>author</th>\n",
|
| 358 |
+
" <td>Benzinga Insights</td>\n",
|
| 359 |
+
" </tr>\n",
|
| 360 |
+
" <tr>\n",
|
| 361 |
+
" <th>teaser</th>\n",
|
| 362 |
+
" <td></td>\n",
|
| 363 |
+
" </tr>\n",
|
| 364 |
+
" <tr>\n",
|
| 365 |
+
" <th>channels</th>\n",
|
| 366 |
+
" <td>Options,Markets</td>\n",
|
| 367 |
+
" </tr>\n",
|
| 368 |
+
" <tr>\n",
|
| 369 |
+
" <th>stocks</th>\n",
|
| 370 |
+
" <td>VRT</td>\n",
|
| 371 |
+
" </tr>\n",
|
| 372 |
+
" <tr>\n",
|
| 373 |
+
" <th>tags</th>\n",
|
| 374 |
+
" <td>BZI-UOA</td>\n",
|
| 375 |
+
" </tr>\n",
|
| 376 |
+
" <tr>\n",
|
| 377 |
+
" <th>updated</th>\n",
|
| 378 |
+
" <td>2024-08-22 14:46:33-04:00</td>\n",
|
| 379 |
+
" </tr>\n",
|
| 380 |
+
" </tbody>\n",
|
| 381 |
+
"</table>\n",
|
| 382 |
+
"</div>"
|
| 383 |
+
],
|
| 384 |
+
"text/plain": [
|
| 385 |
+
"date 2024-08-22 14:46:33-04:00\n",
|
| 386 |
+
"title Behind the Scenes of Vertiv Hldgs's Latest Opt...\n",
|
| 387 |
+
"images [{'size': 'thumb', 'url': 'https://cdn.benzing...\n",
|
| 388 |
+
"text <p>Whales with a lot of money to spend have ta...\n",
|
| 389 |
+
"url https://www.benzinga.com/insights/options/24/0...\n",
|
| 390 |
+
"id 40515079\n",
|
| 391 |
+
"author Benzinga Insights\n",
|
| 392 |
+
"teaser \n",
|
| 393 |
+
"channels Options,Markets\n",
|
| 394 |
+
"stocks VRT\n",
|
| 395 |
+
"tags BZI-UOA\n",
|
| 396 |
+
"updated 2024-08-22 14:46:33-04:00"
|
| 397 |
+
]
|
| 398 |
+
},
|
| 399 |
+
"execution_count": 6,
|
| 400 |
+
"metadata": {},
|
| 401 |
+
"output_type": "execute_result"
|
| 402 |
+
}
|
| 403 |
+
],
|
| 404 |
+
"source": [
|
| 405 |
+
"obb.news.world(limit=1, provider=\"benzinga\").to_df().T"
|
| 406 |
+
]
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"cell_type": "markdown",
|
| 410 |
+
"metadata": {},
|
| 411 |
+
"source": [
|
| 412 |
+
"\n",
|
| 413 |
+
"\n",
|
| 414 |
+
"\n",
|
| 415 |
+
"---\n",
|
| 416 |
+
"\n",
|
| 417 |
+
"\n"
|
| 418 |
+
]
|
| 419 |
+
},
|
| 420 |
+
{
|
| 421 |
+
"cell_type": "markdown",
|
| 422 |
+
"metadata": {},
|
| 423 |
+
"source": [
|
| 424 |
+
"## Standardization of input and output schemas is done with Pydantic models"
|
| 425 |
+
]
|
| 426 |
+
},
|
| 427 |
+
{
|
| 428 |
+
"cell_type": "markdown",
|
| 429 |
+
"metadata": {},
|
| 430 |
+
"source": [
|
| 431 |
+
"#### This is a standard model"
|
| 432 |
+
]
|
| 433 |
+
},
|
| 434 |
+
{
|
| 435 |
+
"cell_type": "code",
|
| 436 |
+
"execution_count": 7,
|
| 437 |
+
"metadata": {},
|
| 438 |
+
"outputs": [
|
| 439 |
+
{
|
| 440 |
+
"data": {
|
| 441 |
+
"text/plain": [
|
| 442 |
+
"{'date': FieldInfo(annotation=datetime, required=True, alias_priority=1, validation_alias='date', serialization_alias='date', description='The date of the data. The published date of the article.'),\n",
|
| 443 |
+
" 'title': FieldInfo(annotation=str, required=True, alias_priority=1, validation_alias='title', serialization_alias='title', description='Title of the article.'),\n",
|
| 444 |
+
" 'images': FieldInfo(annotation=Union[List[Dict[str, str]], NoneType], required=False, default=None, alias_priority=1, validation_alias='images', serialization_alias='images', description='Images associated with the article.'),\n",
|
| 445 |
+
" 'text': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='text', serialization_alias='text', description='Text/body of the article.'),\n",
|
| 446 |
+
" 'url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='url', serialization_alias='url', description='URL to the article.')}"
|
| 447 |
+
]
|
| 448 |
+
},
|
| 449 |
+
"execution_count": 7,
|
| 450 |
+
"metadata": {},
|
| 451 |
+
"output_type": "execute_result"
|
| 452 |
+
}
|
| 453 |
+
],
|
| 454 |
+
"source": [
|
| 455 |
+
"from openbb_core.provider.standard_models.world_news import WorldNewsData\n",
|
| 456 |
+
"\n",
|
| 457 |
+
"WorldNewsData.__fields__"
|
| 458 |
+
]
|
| 459 |
+
},
|
| 460 |
+
{
|
| 461 |
+
"cell_type": "markdown",
|
| 462 |
+
"metadata": {},
|
| 463 |
+
"source": [
|
| 464 |
+
"#### These are provider models"
|
| 465 |
+
]
|
| 466 |
+
},
|
| 467 |
+
{
|
| 468 |
+
"cell_type": "code",
|
| 469 |
+
"execution_count": 8,
|
| 470 |
+
"metadata": {},
|
| 471 |
+
"outputs": [],
|
| 472 |
+
"source": [
|
| 473 |
+
"from openbb_intrinio.models.world_news import IntrinioWorldNewsData\n",
|
| 474 |
+
"from openbb_benzinga.models.world_news import BenzingaWorldNewsData"
|
| 475 |
+
]
|
| 476 |
+
},
|
| 477 |
+
{
|
| 478 |
+
"cell_type": "code",
|
| 479 |
+
"execution_count": 9,
|
| 480 |
+
"metadata": {},
|
| 481 |
+
"outputs": [
|
| 482 |
+
{
|
| 483 |
+
"data": {
|
| 484 |
+
"text/plain": [
|
| 485 |
+
"{'date': FieldInfo(annotation=datetime, required=True, alias_priority=1, validation_alias='date', serialization_alias='date', description='The date of the data. The published date of the article.'),\n",
|
| 486 |
+
" 'title': FieldInfo(annotation=str, required=True, alias_priority=1, validation_alias='title', serialization_alias='title', description='Title of the article.'),\n",
|
| 487 |
+
" 'images': FieldInfo(annotation=Union[List[Dict[str, str]], NoneType], required=False, default=None, alias_priority=1, validation_alias='images', serialization_alias='images', description='Images associated with the article.'),\n",
|
| 488 |
+
" 'text': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='text', serialization_alias='text', description='Text/body of the article.'),\n",
|
| 489 |
+
" 'url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='url', serialization_alias='url', description='URL to the article.'),\n",
|
| 490 |
+
" 'source': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='source', serialization_alias='source', description='The source of the news article.'),\n",
|
| 491 |
+
" 'summary': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='summary', serialization_alias='summary', description='The summary of the news article.'),\n",
|
| 492 |
+
" 'topics': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='topics', serialization_alias='topics', description='The topics related to the news article.'),\n",
|
| 493 |
+
" 'word_count': FieldInfo(annotation=Union[int, NoneType], required=False, default=None, alias_priority=1, validation_alias='wordCount', serialization_alias='word_count', description='The word count of the news article.'),\n",
|
| 494 |
+
" 'business_relevance': FieldInfo(annotation=Union[float, NoneType], required=False, default=None, alias_priority=1, validation_alias='businessRelevance', serialization_alias='business_relevance', description=' \\tHow strongly correlated the news article is to the business'),\n",
|
| 495 |
+
" 'sentiment': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='sentiment', serialization_alias='sentiment', description='The sentiment of the news article - i.e, negative, positive.'),\n",
|
| 496 |
+
" 'sentiment_confidence': FieldInfo(annotation=Union[float, NoneType], required=False, default=None, alias_priority=1, validation_alias='sentimentConfidence', serialization_alias='sentiment_confidence', description='The confidence score of the sentiment rating.'),\n",
|
| 497 |
+
" 'language': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='language', serialization_alias='language', description='The language of the news article.'),\n",
|
| 498 |
+
" 'spam': FieldInfo(annotation=Union[bool, NoneType], required=False, default=None, alias_priority=1, validation_alias='spam', serialization_alias='spam', description='Whether the news article is spam.'),\n",
|
| 499 |
+
" 'copyright': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='copyright', serialization_alias='copyright', description='The copyright notice of the news article.'),\n",
|
| 500 |
+
" 'id': FieldInfo(annotation=str, required=True, alias_priority=1, validation_alias='id', serialization_alias='id', description='Article ID.'),\n",
|
| 501 |
+
" 'company': FieldInfo(annotation=Union[IntrinioCompany, NoneType], required=False, default=None, alias_priority=1, validation_alias='company', serialization_alias='company', description='The Intrinio Company object. Contains details company reference data.'),\n",
|
| 502 |
+
" 'security': FieldInfo(annotation=Union[IntrinioSecurity, NoneType], required=False, default=None, alias_priority=1, validation_alias='security', serialization_alias='security', description='The Intrinio Security object. Contains the security details related to the news article.')}"
|
| 503 |
+
]
|
| 504 |
+
},
|
| 505 |
+
"execution_count": 9,
|
| 506 |
+
"metadata": {},
|
| 507 |
+
"output_type": "execute_result"
|
| 508 |
+
}
|
| 509 |
+
],
|
| 510 |
+
"source": [
|
| 511 |
+
"IntrinioWorldNewsData.__fields__"
|
| 512 |
+
]
|
| 513 |
+
},
|
| 514 |
+
{
|
| 515 |
+
"cell_type": "code",
|
| 516 |
+
"execution_count": 10,
|
| 517 |
+
"metadata": {},
|
| 518 |
+
"outputs": [
|
| 519 |
+
{
|
| 520 |
+
"data": {
|
| 521 |
+
"text/plain": [
|
| 522 |
+
"{'date': FieldInfo(annotation=datetime, required=True, alias_priority=1, validation_alias='date', serialization_alias='date', description='The date of the data. The published date of the article.'),\n",
|
| 523 |
+
" 'title': FieldInfo(annotation=str, required=True, alias_priority=1, validation_alias='title', serialization_alias='title', description='Title of the article.'),\n",
|
| 524 |
+
" 'images': FieldInfo(annotation=Union[List[Dict[str, str]], NoneType], required=False, default=None, alias_priority=1, validation_alias='images', serialization_alias='images', description='Images associated with the article.'),\n",
|
| 525 |
+
" 'text': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='text', serialization_alias='text', description='Text/body of the article.'),\n",
|
| 526 |
+
" 'url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='url', serialization_alias='url', description='URL to the article.'),\n",
|
| 527 |
+
" 'id': FieldInfo(annotation=str, required=True, alias_priority=1, validation_alias='id', serialization_alias='id', description='Article ID.'),\n",
|
| 528 |
+
" 'author': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='author', serialization_alias='author', description='Author of the news.'),\n",
|
| 529 |
+
" 'teaser': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='teaser', serialization_alias='teaser', description='Teaser of the news.'),\n",
|
| 530 |
+
" 'channels': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='channels', serialization_alias='channels', description='Channels associated with the news.'),\n",
|
| 531 |
+
" 'stocks': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='stocks', serialization_alias='stocks', description='Stocks associated with the news.'),\n",
|
| 532 |
+
" 'tags': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, alias_priority=1, validation_alias='tags', serialization_alias='tags', description='Tags associated with the news.'),\n",
|
| 533 |
+
" 'updated': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None, alias_priority=1, validation_alias='updated', serialization_alias='updated', description='Updated date of the news.')}"
|
| 534 |
+
]
|
| 535 |
+
},
|
| 536 |
+
"execution_count": 10,
|
| 537 |
+
"metadata": {},
|
| 538 |
+
"output_type": "execute_result"
|
| 539 |
+
}
|
| 540 |
+
],
|
| 541 |
+
"source": [
|
| 542 |
+
"BenzingaWorldNewsData.__fields__"
|
| 543 |
+
]
|
| 544 |
+
},
|
| 545 |
+
{
|
| 546 |
+
"cell_type": "markdown",
|
| 547 |
+
"metadata": {},
|
| 548 |
+
"source": [
|
| 549 |
+
"## Inheritance, field mapping and quality assurance"
|
| 550 |
+
]
|
| 551 |
+
},
|
| 552 |
+
{
|
| 553 |
+
"cell_type": "markdown",
|
| 554 |
+
"metadata": {},
|
| 555 |
+
"source": [
|
| 556 |
+
"#### Provider models inherit from Standard Models"
|
| 557 |
+
]
|
| 558 |
+
},
|
| 559 |
+
{
|
| 560 |
+
"cell_type": "code",
|
| 561 |
+
"execution_count": 11,
|
| 562 |
+
"metadata": {},
|
| 563 |
+
"outputs": [
|
| 564 |
+
{
|
| 565 |
+
"data": {
|
| 566 |
+
"text/plain": [
|
| 567 |
+
"True"
|
| 568 |
+
]
|
| 569 |
+
},
|
| 570 |
+
"execution_count": 11,
|
| 571 |
+
"metadata": {},
|
| 572 |
+
"output_type": "execute_result"
|
| 573 |
+
}
|
| 574 |
+
],
|
| 575 |
+
"source": [
|
| 576 |
+
"issubclass(BenzingaWorldNewsData, WorldNewsData)"
|
| 577 |
+
]
|
| 578 |
+
},
|
| 579 |
+
{
|
| 580 |
+
"cell_type": "markdown",
|
| 581 |
+
"metadata": {},
|
| 582 |
+
"source": [
|
| 583 |
+
"#### Provider models use aliases to map to standard fields"
|
| 584 |
+
]
|
| 585 |
+
},
|
| 586 |
+
{
|
| 587 |
+
"cell_type": "code",
|
| 588 |
+
"execution_count": 12,
|
| 589 |
+
"metadata": {},
|
| 590 |
+
"outputs": [
|
| 591 |
+
{
|
| 592 |
+
"data": {
|
| 593 |
+
"text/plain": [
|
| 594 |
+
"{'date': 'created', 'text': 'body', 'images': 'image'}"
|
| 595 |
+
]
|
| 596 |
+
},
|
| 597 |
+
"execution_count": 12,
|
| 598 |
+
"metadata": {},
|
| 599 |
+
"output_type": "execute_result"
|
| 600 |
+
}
|
| 601 |
+
],
|
| 602 |
+
"source": [
|
| 603 |
+
"BenzingaWorldNewsData.__alias_dict__"
|
| 604 |
+
]
|
| 605 |
+
},
|
| 606 |
+
{
|
| 607 |
+
"cell_type": "markdown",
|
| 608 |
+
"metadata": {},
|
| 609 |
+
"source": [
|
| 610 |
+
"#### Provider models implement field validation"
|
| 611 |
+
]
|
| 612 |
+
},
|
| 613 |
+
{
|
| 614 |
+
"cell_type": "code",
|
| 615 |
+
"execution_count": 13,
|
| 616 |
+
"metadata": {},
|
| 617 |
+
"outputs": [
|
| 618 |
+
{
|
| 619 |
+
"data": {
|
| 620 |
+
"text/plain": [
|
| 621 |
+
"{'date_validate': Decorator(cls_ref='openbb_intrinio.models.world_news.IntrinioWorldNewsData:140298041431344', cls_var_name='date_validate', func=<bound method IntrinioWorldNewsData.date_validate of <class 'openbb_intrinio.models.world_news.IntrinioWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('publication_date',), mode='before', check_fields=False)),\n",
|
| 622 |
+
" 'topics_validate': Decorator(cls_ref='openbb_intrinio.models.world_news.IntrinioWorldNewsData:140298041431344', cls_var_name='topics_validate', func=<bound method IntrinioWorldNewsData.topics_validate of <class 'openbb_intrinio.models.world_news.IntrinioWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('topics',), mode='before', check_fields=False)),\n",
|
| 623 |
+
" 'copyright_validate': Decorator(cls_ref='openbb_intrinio.models.world_news.IntrinioWorldNewsData:140298041431344', cls_var_name='copyright_validate', func=<bound method IntrinioWorldNewsData.copyright_validate of <class 'openbb_intrinio.models.world_news.IntrinioWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('copyright',), mode='before', check_fields=False))}"
|
| 624 |
+
]
|
| 625 |
+
},
|
| 626 |
+
"execution_count": 13,
|
| 627 |
+
"metadata": {},
|
| 628 |
+
"output_type": "execute_result"
|
| 629 |
+
}
|
| 630 |
+
],
|
| 631 |
+
"source": [
|
| 632 |
+
"IntrinioWorldNewsData.__dict__[\"__pydantic_decorators__\"].field_validators"
|
| 633 |
+
]
|
| 634 |
+
},
|
| 635 |
+
{
|
| 636 |
+
"cell_type": "code",
|
| 637 |
+
"execution_count": 14,
|
| 638 |
+
"metadata": {},
|
| 639 |
+
"outputs": [
|
| 640 |
+
{
|
| 641 |
+
"data": {
|
| 642 |
+
"text/plain": [
|
| 643 |
+
"{'date_validate': Decorator(cls_ref='openbb_benzinga.models.world_news.BenzingaWorldNewsData:140297991464784', cls_var_name='date_validate', func=<bound method BenzingaWorldNewsData.date_validate of <class 'openbb_benzinga.models.world_news.BenzingaWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('date', 'updated'), mode='before', check_fields=False)),\n",
|
| 644 |
+
" 'list_validate': Decorator(cls_ref='openbb_benzinga.models.world_news.BenzingaWorldNewsData:140297991464784', cls_var_name='list_validate', func=<bound method BenzingaWorldNewsData.list_validate of <class 'openbb_benzinga.models.world_news.BenzingaWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('stocks', 'channels', 'tags'), mode='before', check_fields=False)),\n",
|
| 645 |
+
" 'id_validate': Decorator(cls_ref='openbb_benzinga.models.world_news.BenzingaWorldNewsData:140297991464784', cls_var_name='id_validate', func=<bound method BenzingaWorldNewsData.id_validate of <class 'openbb_benzinga.models.world_news.BenzingaWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('id', 'text', 'teaser', 'title', 'author'), mode='before', check_fields=False)),\n",
|
| 646 |
+
" 'empty_list': Decorator(cls_ref='openbb_benzinga.models.world_news.BenzingaWorldNewsData:140297991464784', cls_var_name='empty_list', func=<bound method BenzingaWorldNewsData.empty_list of <class 'openbb_benzinga.models.world_news.BenzingaWorldNewsData'>>, shim=None, info=FieldValidatorDecoratorInfo(fields=('images',), mode='before', check_fields=False))}"
|
| 647 |
+
]
|
| 648 |
+
},
|
| 649 |
+
"execution_count": 14,
|
| 650 |
+
"metadata": {},
|
| 651 |
+
"output_type": "execute_result"
|
| 652 |
+
}
|
| 653 |
+
],
|
| 654 |
+
"source": [
|
| 655 |
+
"BenzingaWorldNewsData.__dict__[\"__pydantic_decorators__\"].field_validators"
|
| 656 |
+
]
|
| 657 |
+
},
|
| 658 |
+
{
|
| 659 |
+
"cell_type": "markdown",
|
| 660 |
+
"metadata": {},
|
| 661 |
+
"source": [
|
| 662 |
+
"Example:\n",
|
| 663 |
+
"\n",
|
| 664 |
+
"```python\n",
|
| 665 |
+
"@field_validator(\"date\")\n",
|
| 666 |
+
"def date_validate(cls, v):\n",
|
| 667 |
+
" \"\"\"Return the date as a datetime object.\"\"\"\n",
|
| 668 |
+
" return datetime.strptime(v, \"%a, %d %b %Y %H:%M:%S %z\")\n",
|
| 669 |
+
"```\n"
|
| 670 |
+
]
|
| 671 |
+
},
|
| 672 |
+
{
|
| 673 |
+
"cell_type": "markdown",
|
| 674 |
+
"metadata": {},
|
| 675 |
+
"source": [
|
| 676 |
+
"---"
|
| 677 |
+
]
|
| 678 |
+
},
|
| 679 |
+
{
|
| 680 |
+
"cell_type": "markdown",
|
| 681 |
+
"metadata": {},
|
| 682 |
+
"source": [
|
| 683 |
+
"## Modularity"
|
| 684 |
+
]
|
| 685 |
+
},
|
| 686 |
+
{
|
| 687 |
+
"cell_type": "code",
|
| 688 |
+
"execution_count": null,
|
| 689 |
+
"metadata": {},
|
| 690 |
+
"outputs": [],
|
| 691 |
+
"source": [
|
| 692 |
+
"obb"
|
| 693 |
+
]
|
| 694 |
+
},
|
| 695 |
+
{
|
| 696 |
+
"cell_type": "markdown",
|
| 697 |
+
"metadata": {},
|
| 698 |
+
"source": [
|
| 699 |
+
"#### Each extension and provider integration is a separate python package"
|
| 700 |
+
]
|
| 701 |
+
},
|
| 702 |
+
{
|
| 703 |
+
"cell_type": "code",
|
| 704 |
+
"execution_count": null,
|
| 705 |
+
"metadata": {},
|
| 706 |
+
"outputs": [],
|
| 707 |
+
"source": [
|
| 708 |
+
"!pip list | grep openbb"
|
| 709 |
+
]
|
| 710 |
+
},
|
| 711 |
+
{
|
| 712 |
+
"cell_type": "markdown",
|
| 713 |
+
"metadata": {},
|
| 714 |
+
"source": [
|
| 715 |
+
"#### Install/Uninstall a provider as python packages"
|
| 716 |
+
]
|
| 717 |
+
},
|
| 718 |
+
{
|
| 719 |
+
"cell_type": "code",
|
| 720 |
+
"execution_count": null,
|
| 721 |
+
"metadata": {},
|
| 722 |
+
"outputs": [],
|
| 723 |
+
"source": [
|
| 724 |
+
"!pip uninstall openbb-yfinance"
|
| 725 |
+
]
|
| 726 |
+
},
|
| 727 |
+
{
|
| 728 |
+
"cell_type": "markdown",
|
| 729 |
+
"metadata": {},
|
| 730 |
+
"source": [
|
| 731 |
+
"To learn more about how it works, here are a few links to the [documentation](https://docs.openbb.co/platform):\n",
|
| 732 |
+
"\n",
|
| 733 |
+
"- [Architecture. Data, Query Parameters and Fetchers.](https://docs.openbb.co/platform/developer_guide/architecture_overview)\n",
|
| 734 |
+
"- [Integrating a new provider.](https://docs.openbb.co/platform/user_guides/add_data_provider_extension)\n",
|
| 735 |
+
"- [Building standalone extensions.](https://docs.openbb.co/platform/getting_started/create_new_provider_extension)\n",
|
| 736 |
+
"- and more in the [Development](https://docs.openbb.co/platform/developer_guide) section of the docs...\n"
|
| 737 |
+
]
|
| 738 |
+
}
|
| 739 |
+
],
|
| 740 |
+
"metadata": {
|
| 741 |
+
"kernelspec": {
|
| 742 |
+
"display_name": "venv",
|
| 743 |
+
"language": "python",
|
| 744 |
+
"name": "python3"
|
| 745 |
+
},
|
| 746 |
+
"language_info": {
|
| 747 |
+
"codemirror_mode": {
|
| 748 |
+
"name": "ipython",
|
| 749 |
+
"version": 3
|
| 750 |
+
},
|
| 751 |
+
"file_extension": ".py",
|
| 752 |
+
"mimetype": "text/x-python",
|
| 753 |
+
"name": "python",
|
| 754 |
+
"nbconvert_exporter": "python",
|
| 755 |
+
"pygments_lexer": "ipython3",
|
| 756 |
+
"version": "3.12.4"
|
| 757 |
+
}
|
| 758 |
+
},
|
| 759 |
+
"nbformat": 4,
|
| 760 |
+
"nbformat_minor": 2
|
| 761 |
+
}
|
examples/portfolioOptimizationUsingModernPortfolioTheory.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/riskReturnAnalysis.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/sectorRotationStrategy.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/streamlit/news.py
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Streamlit News Page"""
|
| 2 |
+
|
| 3 |
+
# flake8: noqa: I001
|
| 4 |
+
|
| 5 |
+
from datetime import datetime, timedelta
|
| 6 |
+
|
| 7 |
+
from openbb import obb
|
| 8 |
+
from numpy import nan
|
| 9 |
+
|
| 10 |
+
import streamlit as st
|
| 11 |
+
|
| 12 |
+
st.set_page_config(
|
| 13 |
+
layout="wide",
|
| 14 |
+
page_title="News",
|
| 15 |
+
initial_sidebar_state="expanded",
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
st.sidebar.markdown(
|
| 19 |
+
"""
|
| 20 |
+
<style>
|
| 21 |
+
section[data-testid="stSidebar"] {
|
| 22 |
+
top: 1% !important;
|
| 23 |
+
height: 98.25% !important;
|
| 24 |
+
left: 0.33% !important;
|
| 25 |
+
margin-top: 0 !important;
|
| 26 |
+
}
|
| 27 |
+
section[data-testid="stSidebar"] img {
|
| 28 |
+
margin-top: -75px !important;
|
| 29 |
+
margin-left: -10px !important;
|
| 30 |
+
width: 95% !important;
|
| 31 |
+
}
|
| 32 |
+
section[data-testid="stVerticalBlock"] {
|
| 33 |
+
gap: 0rem;
|
| 34 |
+
}
|
| 35 |
+
body {
|
| 36 |
+
line-height: 1.2;
|
| 37 |
+
}
|
| 38 |
+
</style>
|
| 39 |
+
<figure style='text-align: center;'>
|
| 40 |
+
<img src='https://openbb.co/assets/images/ogimages/Homepage.png' />
|
| 41 |
+
<figcaption style='font-size: 0.8em; color: #888;'>Powered by Open Source</figcaption>
|
| 42 |
+
</figure>
|
| 43 |
+
""",
|
| 44 |
+
unsafe_allow_html=True,
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
button_pressed = False
|
| 49 |
+
|
| 50 |
+
SUPPORTED_SOURCES = ["benzinga", "biztoc", "intrinio", "fmp", "tiingo"]
|
| 51 |
+
|
| 52 |
+
providers = [
|
| 53 |
+
d
|
| 54 |
+
for d in list(obb.user.credentials.__dict__.keys()) # type: ignore
|
| 55 |
+
if obb.user.credentials.__dict__[d] is not None # type: ignore
|
| 56 |
+
]
|
| 57 |
+
providers = [d.split("_")[0] for d in providers if d.split("_")[0] in SUPPORTED_SOURCES]
|
| 58 |
+
news_sources = [d.upper() if d == "fmp" else d.title() for d in providers]
|
| 59 |
+
|
| 60 |
+
if "news" not in st.session_state:
|
| 61 |
+
st.session_state.news = None
|
| 62 |
+
|
| 63 |
+
if "biztoc_sources" not in st.session_state:
|
| 64 |
+
st.session_state.biztoc_sources = []
|
| 65 |
+
if "news_container" not in st.session_state:
|
| 66 |
+
st.session_state.news_container = st.empty()
|
| 67 |
+
if "selected_limit" not in st.session_state:
|
| 68 |
+
st.session_state.selected_limit = 100
|
| 69 |
+
if "selected_provider" not in st.session_state:
|
| 70 |
+
if len(news_sources) == 0:
|
| 71 |
+
st.error(
|
| 72 |
+
f"No news sources available. Please check your credentials for one of: {SUPPORTED_SOURCES}"
|
| 73 |
+
)
|
| 74 |
+
st.stop()
|
| 75 |
+
if len(news_sources) > 0:
|
| 76 |
+
st.session_state.selected_provider = (
|
| 77 |
+
"Biztoc" if "Biztoc" in news_sources else news_sources[0]
|
| 78 |
+
)
|
| 79 |
+
if "selected_tags" not in st.session_state:
|
| 80 |
+
st.session_state.selected_tags = ""
|
| 81 |
+
if "selected_term" not in st.session_state:
|
| 82 |
+
st.session_state.selected_term = ""
|
| 83 |
+
if "news_start_date" not in st.session_state:
|
| 84 |
+
st.session_state.news_start_date = (datetime.now() - timedelta(days=2)).date()
|
| 85 |
+
if "news_end_date" not in st.session_state:
|
| 86 |
+
st.session_state.news_end_date = datetime.now().date()
|
| 87 |
+
if "selected_biztoc_source" not in st.session_state:
|
| 88 |
+
st.session_state.selected_biztoc_source = ""
|
| 89 |
+
if "content_type" not in st.session_state:
|
| 90 |
+
st.session_state.content_type = "news"
|
| 91 |
+
if "benzinga_tickers" not in st.session_state:
|
| 92 |
+
st.session_state.benzinga_tickers = ""
|
| 93 |
+
if "selected_benzinga_channel" not in st.session_state:
|
| 94 |
+
st.session_state.selected_benzinga_channel = ""
|
| 95 |
+
if "fmp_tickers" not in st.session_state:
|
| 96 |
+
st.session_state.fmp_tickers = ""
|
| 97 |
+
if "intrinio_tickers" not in st.session_state:
|
| 98 |
+
st.session_state.intrinio_tickers = ""
|
| 99 |
+
if "tiingo_tickers" not in st.session_state:
|
| 100 |
+
st.session_state.tiingo_tickers = ""
|
| 101 |
+
if "tiingo_source" not in st.session_state:
|
| 102 |
+
st.session_state.tiingo_source = ""
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def fetch_openbb():
|
| 106 |
+
kwargs = {
|
| 107 |
+
"provider": st.session_state.selected_provider.lower(),
|
| 108 |
+
"limit": st.session_state.selected_limit,
|
| 109 |
+
}
|
| 110 |
+
if st.session_state.selected_provider == "Benzinga":
|
| 111 |
+
kwargs["start_date"] = st.session_state.news_start_date.strftime("%Y-%m-%d")
|
| 112 |
+
kwargs["end_date"] = st.session_state.news_end_date.strftime("%Y-%m-%d")
|
| 113 |
+
kwargs["topics"] = st.session_state.selected_tags
|
| 114 |
+
kwargs["display"] = "full"
|
| 115 |
+
kwargs["page_size"] = 100
|
| 116 |
+
kwargs["channels"] = (
|
| 117 |
+
st.session_state.selected_benzinga_channel.lower()
|
| 118 |
+
if st.session_state.selected_benzinga_channel
|
| 119 |
+
else None
|
| 120 |
+
)
|
| 121 |
+
kwargs["symbol"] = (
|
| 122 |
+
st.session_state.benzinga_tickers
|
| 123 |
+
if st.session_state.benzinga_tickers
|
| 124 |
+
else None
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
if st.session_state.selected_provider == "Biztoc":
|
| 128 |
+
kwargs["term"] = st.session_state.selected_term
|
| 129 |
+
kwargs["tag"] = st.session_state.selected_tags
|
| 130 |
+
kwargs["filter"] = "tag" if kwargs.get("tag") else None
|
| 131 |
+
if kwargs.get("filter") is None:
|
| 132 |
+
kwargs["filter"] = "latest"
|
| 133 |
+
kwargs["source"] = (
|
| 134 |
+
st.session_state.selected_biztoc_source
|
| 135 |
+
if st.session_state.selected_biztoc_source
|
| 136 |
+
else None
|
| 137 |
+
)
|
| 138 |
+
kwargs["filter"] = "source" if kwargs.get("source") else kwargs.get("filter")
|
| 139 |
+
if kwargs.get("filter") == "source":
|
| 140 |
+
kwargs.pop("tag")
|
| 141 |
+
|
| 142 |
+
if st.session_state.selected_provider == "FMP":
|
| 143 |
+
kwargs["symbol"] = (
|
| 144 |
+
st.session_state.fmp_tickers if st.session_state.fmp_tickers else None
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
if st.session_state.selected_provider == "Intrinio":
|
| 148 |
+
kwargs["symbol"] = (
|
| 149 |
+
st.session_state.intrinio_tickers
|
| 150 |
+
if st.session_state.intrinio_tickers
|
| 151 |
+
else None
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
if st.session_state.selected_provider == "Tiingo":
|
| 155 |
+
kwargs["start_date"] = st.session_state.news_start_date.strftime("%Y-%m-%d")
|
| 156 |
+
kwargs["end_date"] = st.session_state.news_end_date.strftime("%Y-%m-%d")
|
| 157 |
+
kwargs["symbol"] = (
|
| 158 |
+
st.session_state.tiingo_tickers if st.session_state.tiingo_tickers else None
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
kwargs = {key: value for key, value in kwargs.items() if value is not None}
|
| 162 |
+
|
| 163 |
+
data = (
|
| 164 |
+
obb.news.company(**kwargs) # type: ignore
|
| 165 |
+
if kwargs.get("symbol")
|
| 166 |
+
else obb.news.world(**kwargs) # type: ignore
|
| 167 |
+
)
|
| 168 |
+
if data.results != []:
|
| 169 |
+
return data.to_df().sort_index(ascending=False).reset_index()
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def update_data():
|
| 173 |
+
st.session_state.news = fetch_openbb()
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
with st.sidebar:
|
| 177 |
+
c1, c2 = st.columns(2)
|
| 178 |
+
with c1:
|
| 179 |
+
old_start_date = st.session_state.news_start_date
|
| 180 |
+
old_provider = st.session_state.selected_provider
|
| 181 |
+
st.session_state.selected_provider = st.selectbox(
|
| 182 |
+
label="Provider",
|
| 183 |
+
options=news_sources,
|
| 184 |
+
index=news_sources.index(st.session_state.selected_provider),
|
| 185 |
+
)
|
| 186 |
+
old_tags = st.session_state.selected_tags
|
| 187 |
+
if st.session_state.selected_provider == "Benzinga":
|
| 188 |
+
st.session_state.news_start_date = st.date_input(
|
| 189 |
+
"Start Date", value=old_start_date
|
| 190 |
+
)
|
| 191 |
+
st.session_state.selected_tags = st.text_input(
|
| 192 |
+
label="Tag", value=st.session_state.selected_tags
|
| 193 |
+
)
|
| 194 |
+
old_biztoc_source = st.session_state.selected_biztoc_source
|
| 195 |
+
if st.session_state.selected_provider == "Biztoc":
|
| 196 |
+
|
| 197 |
+
st.session_state.selected_biztoc_source = st.text_input(label="Source")
|
| 198 |
+
old_benzinga_tickers = st.session_state.benzinga_tickers
|
| 199 |
+
if st.session_state.selected_provider == "Benzinga":
|
| 200 |
+
st.session_state.benzinga_tickers = st.text_input(
|
| 201 |
+
label="Tickers", value=old_benzinga_tickers
|
| 202 |
+
)
|
| 203 |
+
old_fmp_tickers = st.session_state.fmp_tickers
|
| 204 |
+
if st.session_state.selected_provider == "FMP":
|
| 205 |
+
st.session_state.fmp_tickers = st.text_input(
|
| 206 |
+
label="Tickers", value=old_fmp_tickers
|
| 207 |
+
)
|
| 208 |
+
old_intrinio_tickers = st.session_state.intrinio_tickers
|
| 209 |
+
if st.session_state.selected_provider == "Intrinio":
|
| 210 |
+
st.session_state.intrinio_tickers = st.text_input(
|
| 211 |
+
label="Tickers", value=old_intrinio_tickers
|
| 212 |
+
)
|
| 213 |
+
old_tiingo_tickers = st.session_state.tiingo_tickers
|
| 214 |
+
if st.session_state.selected_provider == "Tiingo":
|
| 215 |
+
st.session_state.news_start_date = st.date_input(
|
| 216 |
+
"Start Date", value=old_start_date
|
| 217 |
+
)
|
| 218 |
+
old_tiingo_tickers = st.session_state.tiingo_tickers
|
| 219 |
+
st.session_state.tiingo_tickers = st.text_input(
|
| 220 |
+
label="Tickers", value=st.session_state.tiingo_tickers
|
| 221 |
+
)
|
| 222 |
+
with c2:
|
| 223 |
+
old_limit = st.session_state.selected_limit
|
| 224 |
+
old_end_date = st.session_state.news_end_date
|
| 225 |
+
st.session_state.selected_limit = st.number_input(
|
| 226 |
+
"Number of Stories", min_value=1, value=100
|
| 227 |
+
)
|
| 228 |
+
old_channel = st.session_state.selected_benzinga_channel
|
| 229 |
+
if st.session_state.selected_provider == "Benzinga":
|
| 230 |
+
st.session_state.news_end_date = st.date_input(
|
| 231 |
+
"End Date", value=old_end_date
|
| 232 |
+
)
|
| 233 |
+
st.session_state.selected_benzinga_channel = st.text_input(
|
| 234 |
+
label="Feed Channel", value=old_channel
|
| 235 |
+
)
|
| 236 |
+
old_term = st.session_state.selected_term
|
| 237 |
+
if st.session_state.selected_provider == "Biztoc":
|
| 238 |
+
st.session_state.selected_term = st.text_input(
|
| 239 |
+
label="Search Term", value=old_term
|
| 240 |
+
)
|
| 241 |
+
if st.session_state.selected_provider == "Tiingo":
|
| 242 |
+
st.session_state.news_end_date = st.date_input(
|
| 243 |
+
"End Date", value=old_end_date
|
| 244 |
+
)
|
| 245 |
+
|
| 246 |
+
if any(
|
| 247 |
+
[
|
| 248 |
+
old_start_date != st.session_state.news_start_date,
|
| 249 |
+
old_end_date != st.session_state.news_end_date,
|
| 250 |
+
old_limit != st.session_state.selected_limit,
|
| 251 |
+
old_provider != st.session_state.selected_provider,
|
| 252 |
+
old_tags != st.session_state.selected_tags,
|
| 253 |
+
old_term != st.session_state.selected_term,
|
| 254 |
+
old_biztoc_source != st.session_state.selected_biztoc_source,
|
| 255 |
+
old_channel != st.session_state.selected_benzinga_channel,
|
| 256 |
+
old_benzinga_tickers != st.session_state.benzinga_tickers,
|
| 257 |
+
old_fmp_tickers != st.session_state.fmp_tickers,
|
| 258 |
+
old_intrinio_tickers != st.session_state.intrinio_tickers,
|
| 259 |
+
old_tiingo_tickers != st.session_state.tiingo_tickers,
|
| 260 |
+
]
|
| 261 |
+
):
|
| 262 |
+
update_data()
|
| 263 |
+
|
| 264 |
+
if st.button("Fetch Data"):
|
| 265 |
+
update_data()
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
def main():
|
| 269 |
+
with st.session_state.news_container.container():
|
| 270 |
+
st.markdown(
|
| 271 |
+
" <style> div[class^='block-container'] { padding-top: 1rem; } h1 { margin-bottom: -10px; } </style> "
|
| 272 |
+
"<h1 style='text-align: center;'>Headlines and Stories</h1> ",
|
| 273 |
+
unsafe_allow_html=True,
|
| 274 |
+
)
|
| 275 |
+
if st.session_state.news is not None:
|
| 276 |
+
story = -1
|
| 277 |
+
expanded = False
|
| 278 |
+
for i in st.session_state.news.index:
|
| 279 |
+
story += 1
|
| 280 |
+
expanded = story == 0
|
| 281 |
+
text = (
|
| 282 |
+
st.session_state.news.loc[i].text
|
| 283 |
+
if "text" in st.session_state.news.loc[i]
|
| 284 |
+
else st.session_state.news.loc[i].get("title")
|
| 285 |
+
)
|
| 286 |
+
src = st.session_state.news.loc[i].url
|
| 287 |
+
date = str(st.session_state.news.loc[i].date)
|
| 288 |
+
title = st.session_state.news.loc[i].title
|
| 289 |
+
if text and text is not nan and text != "":
|
| 290 |
+
with st.expander(label=f"{date} - {title}", expanded=expanded):
|
| 291 |
+
st.markdown(
|
| 292 |
+
f"""
|
| 293 |
+
<div style='max-width: 90%; margin: auto; word-wrap: break-word;'>
|
| 294 |
+
<h2 style='text-align: center;'>{title}</h2>
|
| 295 |
+
</div>
|
| 296 |
+
""",
|
| 297 |
+
unsafe_allow_html=True,
|
| 298 |
+
)
|
| 299 |
+
|
| 300 |
+
if st.session_state.selected_provider == "Benzinga":
|
| 301 |
+
_tags = (
|
| 302 |
+
st.session_state.news.loc[i].tags
|
| 303 |
+
if st.session_state.news.loc[i].get("tags")
|
| 304 |
+
else ""
|
| 305 |
+
)
|
| 306 |
+
_stocks = (
|
| 307 |
+
st.session_state.news.loc[i].stocks
|
| 308 |
+
if st.session_state.news.loc[i].get("stocks")
|
| 309 |
+
else ""
|
| 310 |
+
)
|
| 311 |
+
_channels = (
|
| 312 |
+
st.session_state.news.loc[i].channels
|
| 313 |
+
if st.session_state.news.loc[i].get("channels")
|
| 314 |
+
else ""
|
| 315 |
+
)
|
| 316 |
+
_images = (
|
| 317 |
+
st.session_state.news.loc[i].images
|
| 318 |
+
if st.session_state.news.loc[i].get("images")
|
| 319 |
+
else []
|
| 320 |
+
)
|
| 321 |
+
_url = st.session_state.news.loc[i].url
|
| 322 |
+
st.markdown(
|
| 323 |
+
"""
|
| 324 |
+
<style>
|
| 325 |
+
img {
|
| 326 |
+
max-width: 98%;
|
| 327 |
+
height: auto;
|
| 328 |
+
margin: auto;
|
| 329 |
+
}
|
| 330 |
+
</style>
|
| 331 |
+
""",
|
| 332 |
+
unsafe_allow_html=True,
|
| 333 |
+
)
|
| 334 |
+
if _images and _images is not nan:
|
| 335 |
+
img = _images[0].get("url")
|
| 336 |
+
if img is not None:
|
| 337 |
+
st.markdown(
|
| 338 |
+
f"<div style='text-align: center;'><img src='{img}'></div><br></br>",
|
| 339 |
+
unsafe_allow_html=True,
|
| 340 |
+
)
|
| 341 |
+
if text is not None:
|
| 342 |
+
st.markdown(text, unsafe_allow_html=True)
|
| 343 |
+
st.divider()
|
| 344 |
+
st.write(_url)
|
| 345 |
+
if _tags:
|
| 346 |
+
st.markdown(
|
| 347 |
+
f"##### Tags for this story: \n {_tags} \n"
|
| 348 |
+
)
|
| 349 |
+
if _stocks and _stocks is not nan:
|
| 350 |
+
st.markdown(f"##### Stocks mentioned:\n {_stocks} \n")
|
| 351 |
+
if _channels:
|
| 352 |
+
st.markdown(
|
| 353 |
+
f"##### Channels for this story: \n {_channels} \n"
|
| 354 |
+
)
|
| 355 |
+
|
| 356 |
+
if st.session_state.selected_provider == "Biztoc":
|
| 357 |
+
if st.session_state.news.loc[i].get("images") not in [
|
| 358 |
+
None,
|
| 359 |
+
nan,
|
| 360 |
+
]:
|
| 361 |
+
img = st.session_state.news.loc[i].images[0].get("s")
|
| 362 |
+
img = (
|
| 363 |
+
st.session_state.news.loc[i].images.get("o")
|
| 364 |
+
if img is None
|
| 365 |
+
else img
|
| 366 |
+
)
|
| 367 |
+
if img is not None:
|
| 368 |
+
st.markdown(
|
| 369 |
+
f"<div style='text-align: center;'><img src='{img}'></div><br></br>",
|
| 370 |
+
unsafe_allow_html=True,
|
| 371 |
+
)
|
| 372 |
+
if text:
|
| 373 |
+
st.markdown(text, unsafe_allow_html=True)
|
| 374 |
+
st.write(src)
|
| 375 |
+
_story_tags = st.session_state.news.loc[i].get("tags")
|
| 376 |
+
_story_tags = ",".join(_story_tags) if _story_tags else ""
|
| 377 |
+
if _story_tags:
|
| 378 |
+
st.divider()
|
| 379 |
+
st.markdown(
|
| 380 |
+
f"##### Tags for this story: \n {_story_tags} \n\n"
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
if st.session_state.selected_provider == "Intrinio":
|
| 384 |
+
_tags = st.session_state.news.loc[i].get("tags")
|
| 385 |
+
_stocks = (
|
| 386 |
+
st.session_state.news.loc[i]["company"].get("ticker")
|
| 387 |
+
if st.session_state.news.loc[i].get("company")
|
| 388 |
+
else None
|
| 389 |
+
)
|
| 390 |
+
_images = st.session_state.news.loc[i].get("images")
|
| 391 |
+
_url = st.session_state.news.loc[i].get("url")
|
| 392 |
+
st.markdown(text, unsafe_allow_html=True)
|
| 393 |
+
if _url:
|
| 394 |
+
st.write(_url)
|
| 395 |
+
if _stocks and _stocks is not nan:
|
| 396 |
+
st.divider()
|
| 397 |
+
st.markdown(f"##### Stocks mentioned:\n {_stocks} \n")
|
| 398 |
+
|
| 399 |
+
if st.session_state.selected_provider == "FMP":
|
| 400 |
+
_url = st.session_state.news.loc[i].get("url")
|
| 401 |
+
_images = st.session_state.news.loc[i].get("images")
|
| 402 |
+
_symbols = st.session_state.news.loc[i].get("symbols")
|
| 403 |
+
img = (
|
| 404 |
+
_images[0].get("o") or _images[0].get("url")
|
| 405 |
+
if _images
|
| 406 |
+
else None
|
| 407 |
+
)
|
| 408 |
+
if img is not None:
|
| 409 |
+
st.markdown(
|
| 410 |
+
f"""
|
| 411 |
+
<div style='text-align: center;'>
|
| 412 |
+
<img src='{img}' width='95%' />
|
| 413 |
+
</div>
|
| 414 |
+
<br>
|
| 415 |
+
""",
|
| 416 |
+
unsafe_allow_html=True,
|
| 417 |
+
)
|
| 418 |
+
if text:
|
| 419 |
+
st.markdown(text, unsafe_allow_html=True)
|
| 420 |
+
if _url:
|
| 421 |
+
st.write(_url)
|
| 422 |
+
|
| 423 |
+
if st.session_state.selected_provider == "Tiingo":
|
| 424 |
+
_url = st.session_state.news.loc[i].get("url")
|
| 425 |
+
_tags = st.session_state.news.loc[i].get("tags")
|
| 426 |
+
_stocks = st.session_state.news.loc[i].get("symbols")
|
| 427 |
+
if _url:
|
| 428 |
+
st.write(_url)
|
| 429 |
+
st.divider()
|
| 430 |
+
if _tags:
|
| 431 |
+
st.markdown(
|
| 432 |
+
f"##### Tags for this story: \n {_tags} \n"
|
| 433 |
+
)
|
| 434 |
+
if _stocks and _stocks is not nan:
|
| 435 |
+
st.markdown(f"##### Stocks mentioned:\n {_stocks} \n")
|
| 436 |
+
|
| 437 |
+
st.divider()
|
| 438 |
+
st.write(
|
| 439 |
+
"Learn more about the OpenBB Platform [here](https://docs.openbb.co/platform)"
|
| 440 |
+
)
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
if __name__ == "__main__":
|
| 444 |
+
main()
|
examples/streamlit/requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit
|
| 2 |
+
openbb
|
| 3 |
+
openbb-biztoc
|
examples/streamlit_news.webp
ADDED
|
examples/usdLiquidityIndex.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
frontend-components/fonts/FiraCode-Regular.ttf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5992ab9640e2df491b2f609467b1de60e8bc39b2c28db184342a0592d98f6117
|
| 3 |
+
size 289624
|
frontend-components/fonts/FiraCode-VF.ttf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:04149681350f161aca538858b88d17443c586cacca83c165939a13423fe91a26
|
| 3 |
+
size 286320
|
frontend-components/plotly/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Logs
|
| 2 |
+
logs
|
| 3 |
+
*.log
|
| 4 |
+
npm-debug.log*
|
| 5 |
+
yarn-debug.log*
|
| 6 |
+
yarn-error.log*
|
| 7 |
+
pnpm-debug.log*
|
| 8 |
+
lerna-debug.log*
|
| 9 |
+
|
| 10 |
+
node_modules
|
| 11 |
+
dist
|
| 12 |
+
dist-ssr
|
| 13 |
+
*.local
|
| 14 |
+
|
| 15 |
+
# Editor directories and files
|
| 16 |
+
.vscode/*
|
| 17 |
+
!.vscode/extensions.json
|
| 18 |
+
.idea
|
| 19 |
+
.DS_Store
|
| 20 |
+
*.suo
|
| 21 |
+
*.ntvs*
|
| 22 |
+
*.njsproj
|
| 23 |
+
*.sln
|
| 24 |
+
*.sw?
|
frontend-components/plotly/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Getting Started with Create React App
|
| 2 |
+
|
| 3 |
+
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
| 4 |
+
|
| 5 |
+
## Available Scripts
|
| 6 |
+
|
| 7 |
+
In the project directory, you can run:
|
| 8 |
+
|
| 9 |
+
### `npm start`
|
| 10 |
+
|
| 11 |
+
Runs the app in the development mode.\
|
| 12 |
+
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
| 13 |
+
|
| 14 |
+
The page will reload when you make changes.\
|
| 15 |
+
You may also see any lint errors in the console.
|
| 16 |
+
|
| 17 |
+
### `npm test`
|
| 18 |
+
|
| 19 |
+
Launches the test runner in the interactive watch mode.\
|
| 20 |
+
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
| 21 |
+
|
| 22 |
+
### `npm run build`
|
| 23 |
+
|
| 24 |
+
Builds the app for production to the `build` folder.\
|
| 25 |
+
It correctly bundles React in production mode and optimizes the build for the best performance.
|
| 26 |
+
|
| 27 |
+
The build is minified and the filenames include the hashes.\
|
| 28 |
+
Your app is ready to be deployed!
|
| 29 |
+
|
| 30 |
+
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
| 31 |
+
|
| 32 |
+
### `npm run eject`
|
| 33 |
+
|
| 34 |
+
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
| 35 |
+
|
| 36 |
+
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
| 37 |
+
|
| 38 |
+
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
| 39 |
+
|
| 40 |
+
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
| 41 |
+
|
| 42 |
+
## Learn More
|
| 43 |
+
|
| 44 |
+
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
| 45 |
+
|
| 46 |
+
To learn React, check out the [React documentation](https://reactjs.org/).
|
| 47 |
+
|
| 48 |
+
### Code Splitting
|
| 49 |
+
|
| 50 |
+
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
| 51 |
+
|
| 52 |
+
### Analyzing the Bundle Size
|
| 53 |
+
|
| 54 |
+
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
| 55 |
+
|
| 56 |
+
### Making a Progressive Web App
|
| 57 |
+
|
| 58 |
+
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
| 59 |
+
|
| 60 |
+
### Advanced Configuration
|
| 61 |
+
|
| 62 |
+
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
| 63 |
+
|
| 64 |
+
### Deployment
|
| 65 |
+
|
| 66 |
+
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
| 67 |
+
|
| 68 |
+
### `npm run build` fails to minify
|
| 69 |
+
|
| 70 |
+
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
frontend-components/plotly/index.html
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<meta name="color-scheme" content="dark light" />
|
| 7 |
+
<title>OpenBB Interactive Charts</title>
|
| 8 |
+
<script>
|
| 9 |
+
if (
|
| 10 |
+
// check if user had saved dark as their
|
| 11 |
+
// theme when accessing page before
|
| 12 |
+
localStorage.theme === "dark" ||
|
| 13 |
+
// or user's requesting dark color
|
| 14 |
+
// scheme through operating system
|
| 15 |
+
(!("theme" in localStorage) &&
|
| 16 |
+
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
| 17 |
+
) {
|
| 18 |
+
// then if we have access to the document and the element
|
| 19 |
+
// we add the dark class to the html element and
|
| 20 |
+
// store the dark value in the localStorage
|
| 21 |
+
if (document && document.documentElement) {
|
| 22 |
+
document.documentElement.classList.add("dark");
|
| 23 |
+
localStorage.setItem("theme", "dark");
|
| 24 |
+
}
|
| 25 |
+
} else {
|
| 26 |
+
// else if we have access to the document and the element
|
| 27 |
+
// we remove the dark class to the html element and
|
| 28 |
+
// store the value light in the localStorage
|
| 29 |
+
if (document && document.documentElement) {
|
| 30 |
+
document.documentElement.classList.remove("dark");
|
| 31 |
+
localStorage.setItem("theme", "light");
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
</script>
|
| 35 |
+
</head>
|
| 36 |
+
<body>
|
| 37 |
+
<div id="root" class="h-full"></div>
|
| 38 |
+
<script type="module" src="/src/main.tsx"></script>
|
| 39 |
+
</body>
|
| 40 |
+
</html>
|
frontend-components/plotly/package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
frontend-components/plotly/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "plotly",
|
| 3 |
+
"version": "0.1.0",
|
| 4 |
+
"private": true,
|
| 5 |
+
"scripts": {
|
| 6 |
+
"dev": "vite",
|
| 7 |
+
"build": "vite build",
|
| 8 |
+
"build_tsc": "tsc && vite build",
|
| 9 |
+
"deploy": "npm run build && mv dist/index.html ../../openbb_platform/obbject_extensions/charting/openbb_charting/core/plotly.html",
|
| 10 |
+
"preview": "vite preview"
|
| 11 |
+
},
|
| 12 |
+
"dependencies": {
|
| 13 |
+
"@radix-ui/react-dialog": "^1.0.3",
|
| 14 |
+
"dom-to-image": "^2.6.0",
|
| 15 |
+
"esbuild": ">=0.25.0",
|
| 16 |
+
"lodash": "^4.17.21",
|
| 17 |
+
"plotly.js-dist-min": "^3.0.0",
|
| 18 |
+
"react": "^18.0.0",
|
| 19 |
+
"react-dom": "^18.0.0",
|
| 20 |
+
"react-plotly.js": "^2.6.0",
|
| 21 |
+
"rollup": ">=4.22.4"
|
| 22 |
+
},
|
| 23 |
+
"devDependencies": {
|
| 24 |
+
"@types/dom-to-image": "^2.6.4",
|
| 25 |
+
"@types/lodash": "^4.14.195",
|
| 26 |
+
"@types/node": "^18.16.3",
|
| 27 |
+
"@types/plotly.js-dist-min": "^2.3.4",
|
| 28 |
+
"@types/react": "^18.0.27",
|
| 29 |
+
"@types/react-dom": "^18.0.10",
|
| 30 |
+
"@types/react-plotly.js": "^2.6.3",
|
| 31 |
+
"@types/wicg-file-system-access": "^2020.9.6",
|
| 32 |
+
"@vitejs/plugin-react": "^4.2.1",
|
| 33 |
+
"autoprefixer": "^10.4.13",
|
| 34 |
+
"clsx": "^1.2.1",
|
| 35 |
+
"postcss": "^8.4.21",
|
| 36 |
+
"react-hotkeys-hook": "^4.4.0",
|
| 37 |
+
"tailwindcss": "^3.2.7",
|
| 38 |
+
"typescript": "^4.9.3",
|
| 39 |
+
"vite": ">=6.2.7",
|
| 40 |
+
"vite-plugin-singlefile": "^0.13.3"
|
| 41 |
+
}
|
| 42 |
+
}
|
frontend-components/plotly/postcss.config.cjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
module.exports = {
|
| 2 |
+
plugins: {
|
| 3 |
+
tailwindcss: {},
|
| 4 |
+
autoprefixer: {},
|
| 5 |
+
},
|
| 6 |
+
};
|
frontend-components/plotly/src/App.tsx
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//@ts-nocheck
|
| 2 |
+
import { useEffect, useState } from "react";
|
| 3 |
+
import Chart from "./components/Chart";
|
| 4 |
+
import { candlestickMockup } from "./data/mockup";
|
| 5 |
+
|
| 6 |
+
declare global {
|
| 7 |
+
[Exposed === Window, SecureContext];
|
| 8 |
+
interface Window {
|
| 9 |
+
json_data: any;
|
| 10 |
+
export_image: string;
|
| 11 |
+
save_image: boolean;
|
| 12 |
+
title: string;
|
| 13 |
+
Plotly: any;
|
| 14 |
+
MODEBAR: HTMLElement;
|
| 15 |
+
download_path: string;
|
| 16 |
+
pywry: any;
|
| 17 |
+
}
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
function App() {
|
| 21 |
+
const [json_data, setData] = useState(
|
| 22 |
+
process.env.NODE_ENV === "production" ? null : candlestickMockup,
|
| 23 |
+
);
|
| 24 |
+
const [options, setOptions] = useState({});
|
| 25 |
+
|
| 26 |
+
useEffect(() => {
|
| 27 |
+
if (process.env.NODE_ENV === "production") {
|
| 28 |
+
const interval = setInterval(() => {
|
| 29 |
+
if (window.json_data) {
|
| 30 |
+
const plotly_json = window.json_data;
|
| 31 |
+
console.log(plotly_json);
|
| 32 |
+
setData(plotly_json);
|
| 33 |
+
clearInterval(interval);
|
| 34 |
+
}
|
| 35 |
+
}, 100);
|
| 36 |
+
return () => clearInterval(interval);
|
| 37 |
+
}
|
| 38 |
+
}, []);
|
| 39 |
+
|
| 40 |
+
const transformData = (data: any) => {
|
| 41 |
+
if (!data) return null;
|
| 42 |
+
const globals = {
|
| 43 |
+
added_traces: [],
|
| 44 |
+
csv_yaxis_id: null,
|
| 45 |
+
cmd_src_idx: null,
|
| 46 |
+
cmd_idx: null,
|
| 47 |
+
cmd_src: "",
|
| 48 |
+
old_margin: null,
|
| 49 |
+
title: "",
|
| 50 |
+
};
|
| 51 |
+
const filename = data.layout?.title?.text
|
| 52 |
+
.replace(/ -/g, "")
|
| 53 |
+
.replace(/-/g, "")
|
| 54 |
+
.replace(/<b>|<\/b>/g, "")
|
| 55 |
+
.replace(/ /g, "_");
|
| 56 |
+
const date = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
| 57 |
+
const time = new Date().toISOString().slice(11, 19).replace(/:/g, "");
|
| 58 |
+
window.title = `openbb_${filename}_${date}_${time}`.replace(/_{2,}/g, "_");
|
| 59 |
+
|
| 60 |
+
if (data.layout.annotations !== undefined) {
|
| 61 |
+
data.layout.annotations.forEach(function (annotation) {
|
| 62 |
+
if (annotation.text !== undefined)
|
| 63 |
+
if (annotation.text[0] === "/") {
|
| 64 |
+
globals.cmd_src = annotation.text;
|
| 65 |
+
globals.cmd_idx = data.layout.annotations.indexOf(annotation);
|
| 66 |
+
annotation.text = "";
|
| 67 |
+
|
| 68 |
+
const margin = data.layout.margin;
|
| 69 |
+
globals.old_margin = { ...margin };
|
| 70 |
+
if (margin.t !== undefined && margin.t > 40) margin.t = 40;
|
| 71 |
+
|
| 72 |
+
if (data.cmd === "/equity/price/historical") margin.r -= 50;
|
| 73 |
+
}
|
| 74 |
+
});
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// We add spaces to all trace names, due to Fira Code font width issues
|
| 78 |
+
// to make sure that the legend is not cut off
|
| 79 |
+
data.data.forEach(function (trace) {
|
| 80 |
+
if (trace.name !== undefined) {
|
| 81 |
+
trace.hoverlabel = {
|
| 82 |
+
namelength: -1,
|
| 83 |
+
};
|
| 84 |
+
}
|
| 85 |
+
});
|
| 86 |
+
|
| 87 |
+
const title = data.layout?.title?.text || "OpenBB Platform";
|
| 88 |
+
globals.title = title;
|
| 89 |
+
return {
|
| 90 |
+
data: data,
|
| 91 |
+
date: new Date(),
|
| 92 |
+
globals: globals,
|
| 93 |
+
cmd: data.command_location,
|
| 94 |
+
python_version: data.python_version,
|
| 95 |
+
pywry_version: data.pywry_version,
|
| 96 |
+
terminal_version: data.terminal_version,
|
| 97 |
+
theme: data.theme,
|
| 98 |
+
title,
|
| 99 |
+
};
|
| 100 |
+
};
|
| 101 |
+
|
| 102 |
+
const transformedData = transformData(json_data);
|
| 103 |
+
|
| 104 |
+
if (transformedData) {
|
| 105 |
+
return (
|
| 106 |
+
<Chart
|
| 107 |
+
json={transformedData.data}
|
| 108 |
+
date={transformedData.date}
|
| 109 |
+
cmd={transformedData.cmd}
|
| 110 |
+
title={transformedData.title}
|
| 111 |
+
globals={transformedData.globals}
|
| 112 |
+
theme={transformedData.theme}
|
| 113 |
+
/>
|
| 114 |
+
);
|
| 115 |
+
} else
|
| 116 |
+
return (
|
| 117 |
+
<div className="absolute inset-0 flex items-center justify-center z-[100]">
|
| 118 |
+
<svg
|
| 119 |
+
className="animate-spin h-20 w-20 text-white"
|
| 120 |
+
xmlns="http://www.w3.org/2000/svg"
|
| 121 |
+
fill="none"
|
| 122 |
+
viewBox="0 0 24 24"
|
| 123 |
+
>
|
| 124 |
+
<circle
|
| 125 |
+
className="opacity-25"
|
| 126 |
+
cx="12"
|
| 127 |
+
cy="12"
|
| 128 |
+
r="10"
|
| 129 |
+
stroke="currentColor"
|
| 130 |
+
strokeWidth="4"
|
| 131 |
+
/>
|
| 132 |
+
<path
|
| 133 |
+
className="opacity-75"
|
| 134 |
+
fill="currentColor"
|
| 135 |
+
d="M4 12a8 8 0 018-8v8z"
|
| 136 |
+
/>
|
| 137 |
+
</svg>
|
| 138 |
+
</div>
|
| 139 |
+
);
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
export default App;
|
frontend-components/plotly/src/components/AutoScaling.tsx
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//@ts-nocheck
|
| 2 |
+
import { Figure } from "react-plotly.js";
|
| 3 |
+
|
| 4 |
+
export const isoDateRegex = new RegExp(
|
| 5 |
+
"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}",
|
| 6 |
+
);
|
| 7 |
+
|
| 8 |
+
function merge(target, source) {
|
| 9 |
+
Object.keys(source).forEach((key) => {
|
| 10 |
+
if (typeof source[key] === "object") {
|
| 11 |
+
Object.assign(source[key], merge(target[key], source[key]));
|
| 12 |
+
}
|
| 13 |
+
});
|
| 14 |
+
Object.assign(target || {}, source);
|
| 15 |
+
return target;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
export default async function autoScaling(
|
| 19 |
+
eventdata: Readonly<Plotly.PlotRelayoutEvent>,
|
| 20 |
+
graphs: Figure,
|
| 21 |
+
) {
|
| 22 |
+
try {
|
| 23 |
+
if (eventdata["xaxis.range[0]"] !== undefined) {
|
| 24 |
+
const x_min = eventdata["xaxis.range[0]"];
|
| 25 |
+
const x_max = eventdata["xaxis.range[1]"];
|
| 26 |
+
let x0_min = x_min;
|
| 27 |
+
let x1_max = x_max;
|
| 28 |
+
|
| 29 |
+
if (isoDateRegex.test(x_min.replace(" ", "T").split(".")[0])) {
|
| 30 |
+
x0_min = new Date(x_min.replace(" ", "T").split(".")[0]);
|
| 31 |
+
x1_max = new Date(x_max.replace(" ", "T").split(".")[0]);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
const to_update = {};
|
| 35 |
+
const yaxis_fixedrange = [];
|
| 36 |
+
let y_min: number;
|
| 37 |
+
let y_max: number;
|
| 38 |
+
let min_xrange: any;
|
| 39 |
+
|
| 40 |
+
const get_all_yaxis_traces = {};
|
| 41 |
+
const get_all_yaxis_annotations = {};
|
| 42 |
+
let volumeTraceYaxis = null;
|
| 43 |
+
|
| 44 |
+
const yaxis_unique = [
|
| 45 |
+
...new Set(
|
| 46 |
+
graphs.data.map((trace: Plotly.PlotData) => {
|
| 47 |
+
if (trace.y !== undefined || trace.type === "candlestick") {
|
| 48 |
+
if (
|
| 49 |
+
trace.yaxis === undefined &&
|
| 50 |
+
trace?.name?.trim() !== "Volume"
|
| 51 |
+
) {
|
| 52 |
+
trace.yaxis = "y";
|
| 53 |
+
}
|
| 54 |
+
if (trace.type === "bar" && trace?.name?.trim() === "Volume") {
|
| 55 |
+
volumeTraceYaxis = `yaxis${trace.yaxis.replace("y", "")}`;
|
| 56 |
+
}
|
| 57 |
+
get_all_yaxis_traces[trace.yaxis] =
|
| 58 |
+
get_all_yaxis_traces[trace.yaxis] || [];
|
| 59 |
+
get_all_yaxis_traces[trace.yaxis].push(trace);
|
| 60 |
+
return trace.yaxis;
|
| 61 |
+
}
|
| 62 |
+
}),
|
| 63 |
+
),
|
| 64 |
+
];
|
| 65 |
+
|
| 66 |
+
graphs.layout.annotations.map((annotation: any, i: number) => {
|
| 67 |
+
if (annotation.yref !== undefined && annotation.yref !== "paper") {
|
| 68 |
+
annotation.index = i;
|
| 69 |
+
const yaxis = `yaxis${annotation.yref.replace("y", "")}`;
|
| 70 |
+
get_all_yaxis_annotations[yaxis] =
|
| 71 |
+
get_all_yaxis_annotations[yaxis] || [];
|
| 72 |
+
get_all_yaxis_annotations[yaxis].push(annotation);
|
| 73 |
+
}
|
| 74 |
+
});
|
| 75 |
+
|
| 76 |
+
yaxis_unique.map((unique) => {
|
| 77 |
+
if (typeof unique !== "string") {
|
| 78 |
+
return;
|
| 79 |
+
}
|
| 80 |
+
const yaxis = `yaxis${unique.replace("y", "")}`;
|
| 81 |
+
let y_candle = [];
|
| 82 |
+
let y_values = [];
|
| 83 |
+
let log_scale = graphs.layout[yaxis].type === "log";
|
| 84 |
+
|
| 85 |
+
get_all_yaxis_traces[unique].map((trace2) => {
|
| 86 |
+
const x = trace2.x;
|
| 87 |
+
log_scale = graphs.layout[yaxis].type === "log";
|
| 88 |
+
|
| 89 |
+
let y = trace2.y !== undefined ? trace2.y : [];
|
| 90 |
+
let y_low = trace2.type === "candlestick" ? trace2.low : [];
|
| 91 |
+
let y_high = trace2.type === "candlestick" ? trace2.high : [];
|
| 92 |
+
|
| 93 |
+
if (log_scale) {
|
| 94 |
+
y = y.map(Math.log10);
|
| 95 |
+
if (trace2.type === "candlestick") {
|
| 96 |
+
y_low = trace2.low.map(Math.log10);
|
| 97 |
+
y_high = trace2.high.map(Math.log10);
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
const yx_values = x.map(
|
| 102 |
+
(x: string | number | Date, i: string | number) => {
|
| 103 |
+
let out = null;
|
| 104 |
+
|
| 105 |
+
if (isoDateRegex.test(x.toString())) {
|
| 106 |
+
const x_time = new Date(x).getTime();
|
| 107 |
+
if (x_time >= x0_min.getTime() && x_time <= x1_max.getTime()) {
|
| 108 |
+
if (trace2.y !== undefined && y[i] !== undefined) {
|
| 109 |
+
out = y[i];
|
| 110 |
+
}
|
| 111 |
+
if (trace2.type === "candlestick") {
|
| 112 |
+
y_candle.push(y_low[i]);
|
| 113 |
+
y_candle.push(y_high[i]);
|
| 114 |
+
}
|
| 115 |
+
if (!min_xrange || x_time < min_xrange) {
|
| 116 |
+
min_xrange = x_time;
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
} else if (x >= x_min && x <= x_max) {
|
| 120 |
+
if (trace2.y !== undefined) {
|
| 121 |
+
out = y[i];
|
| 122 |
+
}
|
| 123 |
+
if (trace2.type === "candlestick") {
|
| 124 |
+
y_candle.push(y_low[i]);
|
| 125 |
+
y_candle.push(y_high[i]);
|
| 126 |
+
}
|
| 127 |
+
if (!min_xrange || x < min_xrange) {
|
| 128 |
+
min_xrange = x;
|
| 129 |
+
}
|
| 130 |
+
}
|
| 131 |
+
return out;
|
| 132 |
+
},
|
| 133 |
+
);
|
| 134 |
+
|
| 135 |
+
y_values = y_values.concat(yx_values);
|
| 136 |
+
});
|
| 137 |
+
|
| 138 |
+
y_values = y_values
|
| 139 |
+
.flat()
|
| 140 |
+
.filter((y2) => y2 !== undefined && y2 !== null);
|
| 141 |
+
y_min = Math.min(...y_values);
|
| 142 |
+
y_max = Math.max(...y_values);
|
| 143 |
+
|
| 144 |
+
if (y_candle.length > 0) {
|
| 145 |
+
y_candle = y_candle
|
| 146 |
+
.flat()
|
| 147 |
+
.filter((y2) => y2 !== undefined && y2 !== null);
|
| 148 |
+
y_min = Math.min(...y_candle);
|
| 149 |
+
y_max = Math.max(...y_candle);
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
const org_y_max = y_max;
|
| 153 |
+
|
| 154 |
+
if (y_min !== undefined && y_max !== undefined) {
|
| 155 |
+
const y_range = y_max - y_min;
|
| 156 |
+
let y_mult = 0.15;
|
| 157 |
+
if (y_candle.length > 0) {
|
| 158 |
+
y_mult = 0.3;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
y_min -= y_range * y_mult;
|
| 162 |
+
y_max += y_range * y_mult;
|
| 163 |
+
if (to_update[yaxis] === undefined) {
|
| 164 |
+
to_update[yaxis] = {};
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
if (yaxis === volumeTraceYaxis) {
|
| 168 |
+
if (graphs.layout[yaxis].tickvals !== undefined) {
|
| 169 |
+
const range_x = 7;
|
| 170 |
+
const volume_ticks = org_y_max;
|
| 171 |
+
let round_digits = -3;
|
| 172 |
+
// @ts-ignore
|
| 173 |
+
let first_val = Math.round(volume_ticks * 0.2, round_digits);
|
| 174 |
+
const x_zipped = [2, 5, 6, 7, 8, 9, 10];
|
| 175 |
+
const y_zipped = [1, 4, 5, 6, 7, 8, 9];
|
| 176 |
+
|
| 177 |
+
for (let i = 0; i < x_zipped.length; i++) {
|
| 178 |
+
if (String(volume_ticks).length > x_zipped[i]) {
|
| 179 |
+
round_digits = -y_zipped[i];
|
| 180 |
+
// @ts-ignore
|
| 181 |
+
first_val = Math.round(volume_ticks * 0.2, round_digits);
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
const tickvals = [
|
| 185 |
+
Math.floor(first_val),
|
| 186 |
+
Math.floor(first_val * 2),
|
| 187 |
+
Math.floor(first_val * 3),
|
| 188 |
+
Math.floor(first_val * 4),
|
| 189 |
+
];
|
| 190 |
+
const volume_range = [0, Math.floor(volume_ticks * range_x)];
|
| 191 |
+
|
| 192 |
+
to_update[yaxis].tickvals = tickvals;
|
| 193 |
+
to_update[yaxis].range = volume_range;
|
| 194 |
+
to_update[yaxis].tickformat = ".2s";
|
| 195 |
+
return;
|
| 196 |
+
}
|
| 197 |
+
y_min = 0;
|
| 198 |
+
y_max = graphs.layout[yaxis].range[1];
|
| 199 |
+
}
|
| 200 |
+
to_update[yaxis].range = [y_min, y_max];
|
| 201 |
+
to_update[yaxis].fixedrange = true;
|
| 202 |
+
yaxis_fixedrange.push(yaxis);
|
| 203 |
+
|
| 204 |
+
if (get_all_yaxis_annotations[yaxis] !== undefined) {
|
| 205 |
+
get_all_yaxis_annotations[yaxis].map((annotation) => {
|
| 206 |
+
if (annotation.ay !== undefined) {
|
| 207 |
+
const yshift = annotation.ay;
|
| 208 |
+
const yshift_new = Math.min(
|
| 209 |
+
Math.max(yshift, y_min + y_range * 0.2),
|
| 210 |
+
y_max - y_range * 0.2,
|
| 211 |
+
);
|
| 212 |
+
|
| 213 |
+
if (to_update.annotations === undefined) {
|
| 214 |
+
to_update.annotations = graphs.layout.annotations;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
to_update.annotations[annotation.index].ay = yshift_new;
|
| 218 |
+
}
|
| 219 |
+
});
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
});
|
| 223 |
+
|
| 224 |
+
graphs.layout = merge(graphs.layout, to_update);
|
| 225 |
+
|
| 226 |
+
return { to_update: graphs.layout, yaxis_fixedrange };
|
| 227 |
+
}
|
| 228 |
+
} catch (e) {
|
| 229 |
+
console.log(`Error in AutoScaling: ${e}`);
|
| 230 |
+
}
|
| 231 |
+
return { to_update: {}, yaxis_fixedrange: [] };
|
| 232 |
+
}
|
frontend-components/plotly/src/components/ChangeColor.tsx
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//@ts-nocheck
|
| 2 |
+
import { useEffect, useState } from "react";
|
| 3 |
+
|
| 4 |
+
export default function ChangeColor({
|
| 5 |
+
open,
|
| 6 |
+
onColorChange,
|
| 7 |
+
}: {
|
| 8 |
+
open: boolean;
|
| 9 |
+
onColorChange: (color: string) => void;
|
| 10 |
+
}) {
|
| 11 |
+
const [active, setActive] = useState(false);
|
| 12 |
+
|
| 13 |
+
function onChangeColor(color) {
|
| 14 |
+
onColorChange(color);
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
if (open && !active) {
|
| 18 |
+
setActive(true);
|
| 19 |
+
}
|
| 20 |
+
if (!open && active) {
|
| 21 |
+
setActive(false);
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
useEffect(() => {
|
| 25 |
+
if (active) {
|
| 26 |
+
let color_picker = document.getElementById("changecolor");
|
| 27 |
+
color_picker.style.display = "block";
|
| 28 |
+
color_picker.style.width = null;
|
| 29 |
+
dragElement(color_picker);
|
| 30 |
+
|
| 31 |
+
function dragElement(elmnt) {
|
| 32 |
+
let pos1 = 0,
|
| 33 |
+
pos2 = 0,
|
| 34 |
+
pos3 = 0,
|
| 35 |
+
pos4 = 0;
|
| 36 |
+
if (document.getElementById(elmnt.id + "_header")) {
|
| 37 |
+
// if present, the header is where you move the DIV from:
|
| 38 |
+
document.getElementById(elmnt.id + "_header").onmousedown =
|
| 39 |
+
dragMouseDown;
|
| 40 |
+
} else {
|
| 41 |
+
// otherwise, move the DIV from anywhere inside the DIV:
|
| 42 |
+
elmnt.onmousedown = dragMouseDown;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
function dragMouseDown(e) {
|
| 46 |
+
e = e || window.event;
|
| 47 |
+
e.preventDefault();
|
| 48 |
+
// get the mouse cursor position at startup:
|
| 49 |
+
pos3 = e.clientX;
|
| 50 |
+
pos4 = e.clientY;
|
| 51 |
+
document.onmouseup = closeDragElement;
|
| 52 |
+
// call a function whenever the cursor moves:
|
| 53 |
+
document.onmousemove = elementDrag;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
function elementDrag(e) {
|
| 57 |
+
e = e || window.event;
|
| 58 |
+
e.preventDefault();
|
| 59 |
+
// calculate the new cursor position:
|
| 60 |
+
pos1 = pos3 - e.clientX;
|
| 61 |
+
pos2 = pos4 - e.clientY;
|
| 62 |
+
pos3 = e.clientX;
|
| 63 |
+
pos4 = e.clientY;
|
| 64 |
+
// set the element's new position:
|
| 65 |
+
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
|
| 66 |
+
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
function closeDragElement() {
|
| 70 |
+
// stop moving when mouse button is released:
|
| 71 |
+
document.onmouseup = null;
|
| 72 |
+
document.onmousemove = null;
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
} else {
|
| 76 |
+
document.getElementById("changecolor").style.display = "none";
|
| 77 |
+
}
|
| 78 |
+
}, [active]);
|
| 79 |
+
|
| 80 |
+
return (
|
| 81 |
+
<div id="changecolor">
|
| 82 |
+
<div id="changecolor_header">
|
| 83 |
+
<input
|
| 84 |
+
type="color"
|
| 85 |
+
id="picked_color"
|
| 86 |
+
value="#00ACFF"
|
| 87 |
+
onChange={(e) => {
|
| 88 |
+
let color = e.target.value;
|
| 89 |
+
onChangeColor(color);
|
| 90 |
+
}}
|
| 91 |
+
/>
|
| 92 |
+
</div>
|
| 93 |
+
</div>
|
| 94 |
+
);
|
| 95 |
+
}
|
frontend-components/plotly/src/components/Chart.tsx
ADDED
|
@@ -0,0 +1,902 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// @ts-nocheck
|
| 2 |
+
import clsx from "clsx";
|
| 3 |
+
import { debounce } from "lodash";
|
| 4 |
+
import * as Plotly from "plotly.js-dist-min";
|
| 5 |
+
import { Icons as PlotlyIcons } from "plotly.js-dist-min";
|
| 6 |
+
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
| 7 |
+
import createPlotlyComponent from "react-plotly.js/factory";
|
| 8 |
+
import { init_annotation } from "../utils/addAnnotation";
|
| 9 |
+
import { non_blocking } from "../utils/utils";
|
| 10 |
+
import autoScaling, { isoDateRegex } from "./AutoScaling";
|
| 11 |
+
import ChangeColor from "./ChangeColor";
|
| 12 |
+
import { DARK_CHARTS_TEMPLATE, ICONS, LIGHT_CHARTS_TEMPLATE } from "./Config";
|
| 13 |
+
import AlertDialog from "./Dialogs/AlertDialog";
|
| 14 |
+
import OverlayChartDialog from "./Dialogs/OverlayChartDialog";
|
| 15 |
+
import TextChartDialog from "./Dialogs/TextChartDialog";
|
| 16 |
+
import TitleChartDialog from "./Dialogs/TitleChartDialog";
|
| 17 |
+
import { PlotConfig, hideModebar, ChartHotkeys } from "./PlotlyConfig";
|
| 18 |
+
import ResizeHandler from "./ResizeHandler";
|
| 19 |
+
|
| 20 |
+
// Add logging to help debug why annotations aren't working
|
| 21 |
+
console.log = ((oldLog) => {
|
| 22 |
+
return function(...args) {
|
| 23 |
+
if (args[0] === "plotly_click") {
|
| 24 |
+
console.trace("plotly_click called with:", args[1]);
|
| 25 |
+
}
|
| 26 |
+
return oldLog.apply(console, args);
|
| 27 |
+
};
|
| 28 |
+
})(console.log);
|
| 29 |
+
|
| 30 |
+
const Plot = createPlotlyComponent(Plotly);
|
| 31 |
+
class PlotComponent extends React.Component {
|
| 32 |
+
constructor(props) {
|
| 33 |
+
super(props);
|
| 34 |
+
this.state = {
|
| 35 |
+
data: props.data,
|
| 36 |
+
layout: props.layout,
|
| 37 |
+
frames: props.frames,
|
| 38 |
+
config: props.config,
|
| 39 |
+
useResizeHandler: props.useResizeHandler,
|
| 40 |
+
style: props.style,
|
| 41 |
+
className: props.className,
|
| 42 |
+
divId: props.divId,
|
| 43 |
+
revision: props.revision,
|
| 44 |
+
graphDiv: props.graphDiv,
|
| 45 |
+
debug: props.debug,
|
| 46 |
+
onInitialized: props.onInitialized,
|
| 47 |
+
};
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
render() {
|
| 51 |
+
return (
|
| 52 |
+
<Plot
|
| 53 |
+
data={this.state.data}
|
| 54 |
+
layout={this.state.layout}
|
| 55 |
+
frames={this.state.frames}
|
| 56 |
+
config={this.state.config}
|
| 57 |
+
useResizeHandler={this.state.useResizeHandler}
|
| 58 |
+
style={this.state.style}
|
| 59 |
+
className={this.state.className}
|
| 60 |
+
divId={this.state.divId}
|
| 61 |
+
revision={this.state.revision}
|
| 62 |
+
graphDiv={this.state.graphDiv}
|
| 63 |
+
debug={this.state.debug}
|
| 64 |
+
onInitialized={this.state.onInitialized}
|
| 65 |
+
onUpdate={(figure) => this.setState(figure)}
|
| 66 |
+
onRelayout={(figure) => this.setState(figure)}
|
| 67 |
+
onPurge={(figure) => this.setState(figure)}
|
| 68 |
+
/>
|
| 69 |
+
);
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
// Check if a chart is a scatter plot to handle annotations differently
|
| 74 |
+
function isScatterPlot(data) {
|
| 75 |
+
if (!data || !data.data) return false;
|
| 76 |
+
|
| 77 |
+
// Check if chart is primarily scatter plots
|
| 78 |
+
return data.data.some(trace =>
|
| 79 |
+
(trace.type === 'scatter' || trace.mode === 'markers' || trace.mode === 'lines+markers') &&
|
| 80 |
+
!(trace.type === 'candlestick' || trace.type === 'ohlc')
|
| 81 |
+
);
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
// Debug function to check annotation structure
|
| 85 |
+
function debugAnnotation(annotation, label = "Annotation Debug") {
|
| 86 |
+
console.log(`[${label}]`, {
|
| 87 |
+
text: annotation.text,
|
| 88 |
+
visible: annotation.visible,
|
| 89 |
+
x: annotation.x,
|
| 90 |
+
y: annotation.y,
|
| 91 |
+
layer: annotation.layer,
|
| 92 |
+
font: annotation.font,
|
| 93 |
+
arrowcolor: annotation.arrowcolor
|
| 94 |
+
});
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
// Exported for external use
|
| 98 |
+
window.debugPlotlyAnnotations = function() {
|
| 99 |
+
if (window.Plotly && window.Plotly.d3.select('#plotlyChart').node()._fullLayout) {
|
| 100 |
+
const annotations = window.Plotly.d3.select('#plotlyChart').node()._fullLayout.annotations || [];
|
| 101 |
+
console.log("[All Annotations]", annotations);
|
| 102 |
+
annotations.forEach(a => debugAnnotation(a));
|
| 103 |
+
return annotations;
|
| 104 |
+
}
|
| 105 |
+
return [];
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
export const getXRange = (min: string, max: string) => {
|
| 109 |
+
if (isoDateRegex.test(min.replace(" ", "T").split(".")[0])) {
|
| 110 |
+
const check_min = new Date(min.replace(" ", "T").split(".")[0]);
|
| 111 |
+
const check_max = new Date(max.replace(" ", "T").split(".")[0]);
|
| 112 |
+
check_min.setSeconds(0);
|
| 113 |
+
check_max.setSeconds(0);
|
| 114 |
+
check_min.setMilliseconds(0);
|
| 115 |
+
check_max.setMilliseconds(0);
|
| 116 |
+
|
| 117 |
+
const multiplier =
|
| 118 |
+
[5, 0, 1].includes(check_min.getDay()) ||
|
| 119 |
+
[4, 5, 6].includes(check_max.getDay())
|
| 120 |
+
? 2
|
| 121 |
+
: 0;
|
| 122 |
+
|
| 123 |
+
const x0_min = new Date(check_min.getTime() - 86400000 * multiplier);
|
| 124 |
+
const x1_max = new Date(check_max.getTime() + 86400000 * multiplier);
|
| 125 |
+
|
| 126 |
+
const xrange = [x0_min.toISOString(), x1_max.toISOString()];
|
| 127 |
+
return { x0_min, x1_max, xrange };
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
return { x0_min: min, x1_max: max, xrange: [min, max] };
|
| 131 |
+
};
|
| 132 |
+
|
| 133 |
+
function CreateDataXrange(figure: Figure, xrange?: any) {
|
| 134 |
+
if (figure.frames && figure.frames.length > 0) {
|
| 135 |
+
// Don't filter data for animated charts
|
| 136 |
+
return figure;
|
| 137 |
+
}
|
| 138 |
+
const new_figure = { ...figure };
|
| 139 |
+
const data = new_figure.data;
|
| 140 |
+
if (!xrange) {
|
| 141 |
+
xrange = [
|
| 142 |
+
data[0]?.x[data[0].x.length - 2000],
|
| 143 |
+
data[0]?.x[data[0].x.length - 1],
|
| 144 |
+
];
|
| 145 |
+
}
|
| 146 |
+
const { x0_min, x1_max, range } = getXRange(xrange[0], xrange[1]);
|
| 147 |
+
xrange = range;
|
| 148 |
+
|
| 149 |
+
const new_data = [];
|
| 150 |
+
data.forEach((trace) => {
|
| 151 |
+
const new_trace = { ...trace };
|
| 152 |
+
const data_keys = [
|
| 153 |
+
"x",
|
| 154 |
+
"y",
|
| 155 |
+
"low",
|
| 156 |
+
"high",
|
| 157 |
+
"open",
|
| 158 |
+
"close",
|
| 159 |
+
"text",
|
| 160 |
+
"customdata",
|
| 161 |
+
];
|
| 162 |
+
const xaxis: any[] = trace.x ? trace.x : [];
|
| 163 |
+
const chunks = [];
|
| 164 |
+
for (let i = 0; i < xaxis.length; i++) {
|
| 165 |
+
const xval = xaxis[i];
|
| 166 |
+
|
| 167 |
+
if (isoDateRegex.test(xval)) {
|
| 168 |
+
const x_time = new Date(xval).getTime();
|
| 169 |
+
if (x_time >= x0_min.getTime() && x_time <= x1_max.getTime()) {
|
| 170 |
+
chunks.push(i);
|
| 171 |
+
}
|
| 172 |
+
} else if (xval >= xrange[0] && xval <= xrange[1]) {
|
| 173 |
+
chunks.push(i);
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
data_keys.forEach((key) => {
|
| 177 |
+
if (trace[key] !== undefined && Array.isArray(trace[key])) {
|
| 178 |
+
new_trace[key] = trace[key].filter((_, i) => chunks.includes(i));
|
| 179 |
+
}
|
| 180 |
+
});
|
| 181 |
+
const color_keys = ["marker", "line"];
|
| 182 |
+
color_keys.forEach((key) => {
|
| 183 |
+
if (trace[key]?.color && Array.isArray(trace[key].color)) {
|
| 184 |
+
new_trace[key] = { ...trace[key] };
|
| 185 |
+
new_trace[key].color = trace[key].color.filter((_, i) =>
|
| 186 |
+
chunks.includes(i),
|
| 187 |
+
);
|
| 188 |
+
}
|
| 189 |
+
});
|
| 190 |
+
|
| 191 |
+
if (chunks.length > 0) new_data.push(new_trace);
|
| 192 |
+
});
|
| 193 |
+
|
| 194 |
+
if (new_data.length === 0)
|
| 195 |
+
return {
|
| 196 |
+
...figure,
|
| 197 |
+
layout: {
|
| 198 |
+
...figure.layout,
|
| 199 |
+
xaxis: { ...figure.layout.xaxis, range: xrange },
|
| 200 |
+
},
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
new_figure.layout.xaxis.range = xrange;
|
| 204 |
+
new_figure.data = new_data;
|
| 205 |
+
return new_figure;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
async function DynamicLoad({
|
| 209 |
+
event,
|
| 210 |
+
figure,
|
| 211 |
+
}: {
|
| 212 |
+
event?: any;
|
| 213 |
+
figure: any;
|
| 214 |
+
}) {
|
| 215 |
+
if (figure.frames && figure.frames.length > 0) {
|
| 216 |
+
// Don't filter data for animated charts
|
| 217 |
+
return figure;
|
| 218 |
+
}
|
| 219 |
+
try {
|
| 220 |
+
const XDATA = figure.data.filter(
|
| 221 |
+
(trace) =>
|
| 222 |
+
trace.x !== undefined && trace.x.length > 0 && trace.x[0] !== undefined,
|
| 223 |
+
);
|
| 224 |
+
|
| 225 |
+
if (XDATA.length === 0) return figure;
|
| 226 |
+
// We get the xaxis range, if no event is passed, we get the last 1000 points
|
| 227 |
+
const xaxis_range = event
|
| 228 |
+
? [event["xaxis.range[0]"], event["xaxis.range[1]"]]
|
| 229 |
+
: [
|
| 230 |
+
XDATA[0]?.x[XDATA[0].x.length - 1000],
|
| 231 |
+
XDATA[0]?.x[XDATA[0].x.length - 1],
|
| 232 |
+
];
|
| 233 |
+
|
| 234 |
+
figure = CreateDataXrange(figure, xaxis_range);
|
| 235 |
+
|
| 236 |
+
return figure;
|
| 237 |
+
} catch (e) {
|
| 238 |
+
console.log("error", e);
|
| 239 |
+
}
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
function formatDate(date) {
|
| 243 |
+
const d = new Date(date);
|
| 244 |
+
const month = `${d.getMonth() + 1}`.padStart(2, "0");
|
| 245 |
+
const day = `${d.getDate()}`.padStart(2, "0");
|
| 246 |
+
const year = d.getFullYear();
|
| 247 |
+
const hour = `${d.getHours()}`.padStart(2, "0");
|
| 248 |
+
const minute = `${d.getMinutes()}`.padStart(2, "0");
|
| 249 |
+
const second = `${d.getSeconds()}`.padStart(2, "0");
|
| 250 |
+
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
function Chart({
|
| 254 |
+
json,
|
| 255 |
+
date,
|
| 256 |
+
cmd,
|
| 257 |
+
title,
|
| 258 |
+
globals,
|
| 259 |
+
theme,
|
| 260 |
+
}: {
|
| 261 |
+
// @ts-ignore
|
| 262 |
+
json: Figure;
|
| 263 |
+
date: Date;
|
| 264 |
+
cmd: string;
|
| 265 |
+
title: string;
|
| 266 |
+
globals: any;
|
| 267 |
+
theme: string;
|
| 268 |
+
}) {
|
| 269 |
+
json.layout.width = undefined;
|
| 270 |
+
json.layout.height = undefined;
|
| 271 |
+
if (json.layout?.title?.text) {
|
| 272 |
+
json.layout.title.text = "";
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
const [originalData, setOriginalData] = useState(json);
|
| 276 |
+
const [barButtons, setModeBarButtons] = useState({});
|
| 277 |
+
const [LogYaxis, setLogYaxis] = useState(false);
|
| 278 |
+
const [chartTitle, setChartTitle] = useState(title);
|
| 279 |
+
const [axesTitles, setAxesTitles] = useState({});
|
| 280 |
+
const [plotLoaded, setPlotLoaded] = useState(false);
|
| 281 |
+
const [modal, setModal] = useState({ name: "" });
|
| 282 |
+
const [loading, setLoading] = useState(false);
|
| 283 |
+
const [plotDiv, setPlotDiv] = useState(null);
|
| 284 |
+
const [volumeBars, setVolumeBars] = useState({ old_nticks: {} });
|
| 285 |
+
const [maximizePlot, setMaximizePlot] = useState(false);
|
| 286 |
+
const [dateSliced, setDateSliced] = useState(false);
|
| 287 |
+
|
| 288 |
+
const [plotData, setPlotDataState] = useState(originalData);
|
| 289 |
+
const [annotations, setAnnotations] = useState([]);
|
| 290 |
+
const [changeTheme, setChangeTheme] = useState(false);
|
| 291 |
+
const [darkMode, setDarkMode] = useState(true);
|
| 292 |
+
const [autoScale, setAutoScaling] = useState(false);
|
| 293 |
+
const [changeColor, setChangeColor] = useState(false);
|
| 294 |
+
const [colorActive, setColorActive] = useState(false);
|
| 295 |
+
const [onAnnotationClick, setOnAnnotationClick] = useState({});
|
| 296 |
+
const [ohlcAnnotation, setOhlcAnnotation] = useState([]);
|
| 297 |
+
const [yaxisFixedRange, setYaxisFixedRange] = useState([]); function setPlotData(data: any) {
|
| 298 |
+
data.layout.datarevision = data.layout.datarevision
|
| 299 |
+
? data.layout.datarevision + 1
|
| 300 |
+
: 1;
|
| 301 |
+
|
| 302 |
+
setPlotDataState(data);
|
| 303 |
+
if (plotDiv && plotData) {
|
| 304 |
+
Plotly.react(plotDiv, data.data, data.layout);
|
| 305 |
+
}
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
const onClose = () => setModal({ name: "" });
|
| 309 |
+
|
| 310 |
+
// @ts-ignore
|
| 311 |
+
const onDeleteAnnotation = useCallback(
|
| 312 |
+
(annotation) => {
|
| 313 |
+
console.log("onDeleteAnnotation", annotation);
|
| 314 |
+
const index = plotData?.layout?.annotations?.findIndex(
|
| 315 |
+
(a: any) => a.text === annotation.text,
|
| 316 |
+
);
|
| 317 |
+
console.log("index", index);
|
| 318 |
+
if (index > -1) {
|
| 319 |
+
plotData?.layout?.annotations?.splice(index, 1);
|
| 320 |
+
setPlotData({ ...plotData });
|
| 321 |
+
setAnnotations(plotData?.layout?.annotations);
|
| 322 |
+
}
|
| 323 |
+
},
|
| 324 |
+
[plotData],
|
| 325 |
+
); // @ts-ignore
|
| 326 |
+
const onAddAnnotation = useCallback(
|
| 327 |
+
(data) => {
|
| 328 |
+
console.log("onAddAnnotation being called with data:", data);
|
| 329 |
+
|
| 330 |
+
// Use the standard annotation flow
|
| 331 |
+
init_annotation({
|
| 332 |
+
plotData,
|
| 333 |
+
popupData: data,
|
| 334 |
+
setPlotData,
|
| 335 |
+
setModal,
|
| 336 |
+
setOnAnnotationClick,
|
| 337 |
+
setAnnotations,
|
| 338 |
+
onAnnotationClick,
|
| 339 |
+
ohlcAnnotation,
|
| 340 |
+
setOhlcAnnotation,
|
| 341 |
+
annotations,
|
| 342 |
+
plotDiv,
|
| 343 |
+
});
|
| 344 |
+
},
|
| 345 |
+
[plotData, onAnnotationClick, ohlcAnnotation, annotations, plotDiv],
|
| 346 |
+
); useEffect(() => {
|
| 347 |
+
if (axesTitles && Object.keys(axesTitles).length > 0) {
|
| 348 |
+
const layoutUpdate = {};
|
| 349 |
+
// Update the layout with the new titles
|
| 350 |
+
Object.keys(axesTitles).forEach((k) => {
|
| 351 |
+
plotData.layout[k].title = {
|
| 352 |
+
...(plotData.layout[k].title || {}),
|
| 353 |
+
text: axesTitles[k],
|
| 354 |
+
};
|
| 355 |
+
plotData.layout[k].showticklabels = true;
|
| 356 |
+
layoutUpdate[`${k}.title.text`] = axesTitles[k];
|
| 357 |
+
});
|
| 358 |
+
|
| 359 |
+
if (plotDiv && Object.keys(layoutUpdate).length > 0) {
|
| 360 |
+
Plotly.relayout(plotDiv, layoutUpdate);
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
setAxesTitles({});
|
| 364 |
+
}
|
| 365 |
+
}, [axesTitles, plotDiv]);
|
| 366 |
+
|
| 367 |
+
function onChangeColor(color) {
|
| 368 |
+
// updates the color of the last added shape
|
| 369 |
+
// this function is called when the color picker is used
|
| 370 |
+
// if there are no shapes, we remove the color picker
|
| 371 |
+
const shapes = plotDiv.layout.shapes;
|
| 372 |
+
if (!shapes || shapes.length === 0) {
|
| 373 |
+
return;
|
| 374 |
+
}
|
| 375 |
+
// we change last added shape color
|
| 376 |
+
const last_shape = shapes[shapes.length - 1];
|
| 377 |
+
last_shape.line.color = color;
|
| 378 |
+
Plotly.update(plotDiv, {}, { shapes: shapes });
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
function button_pressed(title, active = false) {
|
| 382 |
+
// changes the style of the button when it is pressed
|
| 383 |
+
// title is the title of the button
|
| 384 |
+
// active is true if the button is active, false otherwise
|
| 385 |
+
|
| 386 |
+
const button =
|
| 387 |
+
barButtons[title] || document.querySelector(`[data-title="${title}"]`);
|
| 388 |
+
if (!active) {
|
| 389 |
+
button.style.border = "1px solid rgba(0, 151, 222, 1.0)";
|
| 390 |
+
button.style.borderRadius = "5px";
|
| 391 |
+
button.style.borderpadding = "5px";
|
| 392 |
+
button.style.boxShadow = "0 0 5px rgba(0, 151, 222, 1.0)";
|
| 393 |
+
} else {
|
| 394 |
+
button.style.border = "transparent";
|
| 395 |
+
button.style.boxShadow = "none";
|
| 396 |
+
}
|
| 397 |
+
setModeBarButtons({ ...barButtons, [title]: button });
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
const debouncedDynamicLoad = async (eventData, figure) => {
|
| 401 |
+
if (dateSliced) {
|
| 402 |
+
const data = { ...figure };
|
| 403 |
+
DynamicLoad({
|
| 404 |
+
event: eventData,
|
| 405 |
+
figure: data,
|
| 406 |
+
}).then(async (toUpdate) => {
|
| 407 |
+
autoScaling(eventData, toUpdate).then((scaled) => {
|
| 408 |
+
if (!scaled.to_update) return;
|
| 409 |
+
setYaxisFixedRange(scaled.yaxis_fixedrange);
|
| 410 |
+
setPlotData({ ...toUpdate, layout: scaled.to_update });
|
| 411 |
+
});
|
| 412 |
+
});
|
| 413 |
+
} else {
|
| 414 |
+
const scaled = await autoScaling(eventData, figure);
|
| 415 |
+
if (!scaled.to_update) return;
|
| 416 |
+
setYaxisFixedRange(scaled.yaxis_fixedrange);
|
| 417 |
+
setPlotData({ ...figure, layout: scaled.to_update });
|
| 418 |
+
}
|
| 419 |
+
};
|
| 420 |
+
|
| 421 |
+
const autoscaleButton = useCallback(() => {
|
| 422 |
+
// We need to check if the button is active or not
|
| 423 |
+
const title = "Auto Scale (Ctrl+Shift+A)";
|
| 424 |
+
const button =
|
| 425 |
+
barButtons[title] || document.querySelector(`[data-title="${title}"]`);
|
| 426 |
+
let active = true;
|
| 427 |
+
|
| 428 |
+
if (button.style.border === "transparent") {
|
| 429 |
+
plotDiv.removeAllListeners("plotly_relayout");
|
| 430 |
+
active = false;
|
| 431 |
+
plotDiv.on("plotly_relayout", async (eventdata) => {
|
| 432 |
+
if (eventdata["xaxis.range[0]"] === undefined) return;
|
| 433 |
+
const debounceTimer = eventdata["relayout"] ? 0 : 300;
|
| 434 |
+
if (
|
| 435 |
+
!eventdata["relayout"] &&
|
| 436 |
+
isoDateRegex.test(
|
| 437 |
+
eventdata["xaxis.range[0]"].toString().replace(" ", "T"),
|
| 438 |
+
)
|
| 439 |
+
) {
|
| 440 |
+
const date1 = new Date(eventdata["xaxis.range[0]"].replace(" ", "T"));
|
| 441 |
+
const date2 = new Date(eventdata["xaxis.range[1]"].replace(" ", "T"));
|
| 442 |
+
|
| 443 |
+
if (date2.getTime() - date1.getTime() < 3600000 * 2) {
|
| 444 |
+
const d1 = new Date(date1.getTime() - 3600000 * 2);
|
| 445 |
+
const d2 = new Date(date2.getTime() + 3600000 * 2);
|
| 446 |
+
|
| 447 |
+
eventdata["xaxis.range[0]"] = formatDate(d1);
|
| 448 |
+
eventdata["xaxis.range[1]"] = formatDate(d2);
|
| 449 |
+
eventdata["relayout"] = true;
|
| 450 |
+
return Plotly.relayout(plotDiv, eventdata);
|
| 451 |
+
}
|
| 452 |
+
}
|
| 453 |
+
debounce(async () => {
|
| 454 |
+
debouncedDynamicLoad(eventdata, originalData);
|
| 455 |
+
}, debounceTimer)();
|
| 456 |
+
});
|
| 457 |
+
}
|
| 458 |
+
// If the button isn't active, we remove the listener so
|
| 459 |
+
// the graphs don't autoscale anymore
|
| 460 |
+
else {
|
| 461 |
+
plotDiv.removeAllListeners("plotly_relayout");
|
| 462 |
+
yaxisFixedRange.forEach((yaxis) => {
|
| 463 |
+
plotDiv.layout[yaxis].fixedrange = false;
|
| 464 |
+
});
|
| 465 |
+
setYaxisFixedRange([]);
|
| 466 |
+
if (dateSliced) {
|
| 467 |
+
plotDiv.on(
|
| 468 |
+
"plotly_relayout",
|
| 469 |
+
debounce(async (eventdata) => {
|
| 470 |
+
if (eventdata["xaxis.range[0]"] === undefined) return;
|
| 471 |
+
debouncedDynamicLoad(eventdata, originalData);
|
| 472 |
+
}, 300),
|
| 473 |
+
);
|
| 474 |
+
}
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
button_pressed(title, active);
|
| 478 |
+
}, [
|
| 479 |
+
barButtons,
|
| 480 |
+
dateSliced,
|
| 481 |
+
debouncedDynamicLoad,
|
| 482 |
+
originalData,
|
| 483 |
+
plotDiv,
|
| 484 |
+
yaxisFixedRange,
|
| 485 |
+
]);
|
| 486 |
+
|
| 487 |
+
function changecolorButton() {
|
| 488 |
+
// We need to check if the button is active or not
|
| 489 |
+
const title = "Edit Color (Ctrl+E)";
|
| 490 |
+
const button =
|
| 491 |
+
barButtons[title] || document.querySelector(`[data-title="${title}"]`);
|
| 492 |
+
let active = true;
|
| 493 |
+
|
| 494 |
+
if (button.style.border === "transparent") {
|
| 495 |
+
active = false;
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
setColorActive(!active);
|
| 499 |
+
button_pressed(title, active);
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
useEffect(() => {
|
| 503 |
+
if (autoScale) {
|
| 504 |
+
const scale = !autoScale;
|
| 505 |
+
console.log("activateAutoScale", scale);
|
| 506 |
+
autoscaleButton();
|
| 507 |
+
setAutoScaling(false);
|
| 508 |
+
}
|
| 509 |
+
}, [autoScale]);
|
| 510 |
+
|
| 511 |
+
useEffect(() => {
|
| 512 |
+
if (changeColor) {
|
| 513 |
+
changecolorButton();
|
| 514 |
+
setChangeColor(false);
|
| 515 |
+
}
|
| 516 |
+
}, [changeColor]);
|
| 517 |
+
|
| 518 |
+
useEffect(() => {
|
| 519 |
+
if (changeTheme) {
|
| 520 |
+
try {
|
| 521 |
+
console.log("changeTheme", changeTheme);
|
| 522 |
+
const TRACES = originalData?.data.filter(
|
| 523 |
+
(trace) => trace?.name?.trim() === "Volume",
|
| 524 |
+
);
|
| 525 |
+
const darkmode = !darkMode;
|
| 526 |
+
|
| 527 |
+
window.document.body.style.backgroundColor = darkmode ? "#000" : "#fff";
|
| 528 |
+
|
| 529 |
+
originalData.layout.font = {
|
| 530 |
+
...(originalData.layout.font || {}),
|
| 531 |
+
color: darkmode ? "#fff" : "#000",
|
| 532 |
+
};
|
| 533 |
+
|
| 534 |
+
const changeIcon = darkmode ? ICONS.sunIcon : ICONS.moonIcon;
|
| 535 |
+
|
| 536 |
+
document
|
| 537 |
+
.querySelector('[data-title="Change Theme"]')
|
| 538 |
+
.getElementsByTagName("path")[0]
|
| 539 |
+
.setAttribute("d", changeIcon.path);
|
| 540 |
+
|
| 541 |
+
document
|
| 542 |
+
.querySelector('[data-title="Change Theme"]')
|
| 543 |
+
.getElementsByTagName("svg")[0]
|
| 544 |
+
.setAttribute("viewBox", changeIcon.viewBox);
|
| 545 |
+
|
| 546 |
+
const volumeColorsDark = {
|
| 547 |
+
"#00ACFF0": "#00ACFF",
|
| 548 |
+
"#e4003a": "#e4003a",
|
| 549 |
+
};
|
| 550 |
+
const volumeColorsLight = {
|
| 551 |
+
"#e4003a": "#e4003a",
|
| 552 |
+
"#00ACFF": "#00ACFF",
|
| 553 |
+
};
|
| 554 |
+
|
| 555 |
+
const volumeColors = darkmode ? volumeColorsDark : volumeColorsLight;
|
| 556 |
+
|
| 557 |
+
TRACES.forEach((trace) => {
|
| 558 |
+
if (trace.type === "bar" && Array.isArray(trace.marker.color))
|
| 559 |
+
trace.marker.color = trace.marker.color.map((color) => {
|
| 560 |
+
return volumeColors[color] || color;
|
| 561 |
+
});
|
| 562 |
+
});
|
| 563 |
+
originalData.layout.template = darkmode
|
| 564 |
+
? DARK_CHARTS_TEMPLATE
|
| 565 |
+
: LIGHT_CHARTS_TEMPLATE;
|
| 566 |
+
|
| 567 |
+
// Preserve existing annotations as-is (no modifications)
|
| 568 |
+
if (plotData.layout.annotations && plotData.layout.annotations.length > 0) {
|
| 569 |
+
originalData.layout.annotations = [...plotData.layout.annotations];
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
setPlotData({ ...originalData });
|
| 573 |
+
setDarkMode(darkmode);
|
| 574 |
+
setChangeTheme(false);
|
| 575 |
+
} catch (e) {
|
| 576 |
+
console.log("error", e);
|
| 577 |
+
}
|
| 578 |
+
}
|
| 579 |
+
}, [changeTheme, plotData.layout.annotations]);
|
| 580 |
+
|
| 581 |
+
useEffect(() => {
|
| 582 |
+
if (plotLoaded) {
|
| 583 |
+
setDarkMode(true);
|
| 584 |
+
setAutoScaling(false);
|
| 585 |
+
const captureButtons = [
|
| 586 |
+
"Overlay chart from CSV",
|
| 587 |
+
"Add Text",
|
| 588 |
+
"Change Titles",
|
| 589 |
+
"Auto Scale (Ctrl+Shift+A)",
|
| 590 |
+
"Reset Axes",
|
| 591 |
+
];
|
| 592 |
+
const autoscale = document.querySelector('[data-title="Autoscale"]');
|
| 593 |
+
if (autoscale) {
|
| 594 |
+
autoscale
|
| 595 |
+
.getElementsByTagName("path")[0]
|
| 596 |
+
.setAttribute("d", PlotlyIcons.home.path);
|
| 597 |
+
autoscale.setAttribute("data-title", "Reset Axes");
|
| 598 |
+
}
|
| 599 |
+
|
| 600 |
+
window.MODEBAR = document.getElementsByClassName(
|
| 601 |
+
"modebar-container",
|
| 602 |
+
)[0] as HTMLElement;
|
| 603 |
+
const modeBarButtons = window.MODEBAR.getElementsByClassName(
|
| 604 |
+
"modebar-btn",
|
| 605 |
+
) as HTMLCollectionOf<HTMLElement>;
|
| 606 |
+
|
| 607 |
+
window.MODEBAR.style.cssText = `${window.MODEBAR.style.cssText}; display:flex;`;
|
| 608 |
+
|
| 609 |
+
// Add annotation click handler to ensure editing works on scatter plots
|
| 610 |
+
if (plotDiv) {
|
| 611 |
+
// When an annotation is clicked, open the edit dialog
|
| 612 |
+
plotDiv.on('plotly_clickannotation', function(data) {
|
| 613 |
+
console.log("Annotation clicked:", data);
|
| 614 |
+
if (data && data.annotation && data.annotation.text) {
|
| 615 |
+
setModal({
|
| 616 |
+
name: "textDialog",
|
| 617 |
+
data: {
|
| 618 |
+
annotation_dict: data.annotation,
|
| 619 |
+
mode: "edit"
|
| 620 |
+
}
|
| 621 |
+
});
|
| 622 |
+
}
|
| 623 |
+
});
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
+
if (modeBarButtons) {
|
| 627 |
+
const barbuttons: any = {};
|
| 628 |
+
for (let i = 0; i < modeBarButtons.length; i++) {
|
| 629 |
+
const btn = modeBarButtons[i];
|
| 630 |
+
if (captureButtons.includes(btn.getAttribute("data-title"))) {
|
| 631 |
+
btn.classList.add("ph-capture");
|
| 632 |
+
}
|
| 633 |
+
btn.style.border = "transparent";
|
| 634 |
+
barbuttons[btn.getAttribute("data-title")] = btn;
|
| 635 |
+
}
|
| 636 |
+
setModeBarButtons(barbuttons);
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
if (plotData?.layout?.yaxis?.type !== undefined) {
|
| 640 |
+
if (plotData.layout.yaxis.type === "log" && !LogYaxis) {
|
| 641 |
+
console.log("yaxis.type changed to log");
|
| 642 |
+
setLogYaxis(true);
|
| 643 |
+
}
|
| 644 |
+
if (plotData.layout.yaxis.type === "linear" && LogYaxis) {
|
| 645 |
+
console.log("yaxis.type changed to linear");
|
| 646 |
+
setLogYaxis(false);
|
| 647 |
+
|
| 648 |
+
// We update the yaxis exponent format to none,
|
| 649 |
+
// set the tickformat to null and the exponentbase to 10
|
| 650 |
+
const layout_update = {
|
| 651 |
+
"yaxis.exponentformat": "none",
|
| 652 |
+
"yaxis.tickformat": null,
|
| 653 |
+
"yaxis.exponentbase": 10,
|
| 654 |
+
};
|
| 655 |
+
Plotly.update(plotDiv, {}, layout_update);
|
| 656 |
+
}
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
window.addEventListener("resize", async function () {
|
| 660 |
+
const update = await ResizeHandler({
|
| 661 |
+
plotData,
|
| 662 |
+
volumeBars,
|
| 663 |
+
setMaximizePlot,
|
| 664 |
+
});
|
| 665 |
+
const layout_update = update.layout_update;
|
| 666 |
+
const newPlotData = update.plotData;
|
| 667 |
+
const volume_update = update.volume_update;
|
| 668 |
+
|
| 669 |
+
if (Object.keys(layout_update).length > 0) {
|
| 670 |
+
setPlotData(newPlotData);
|
| 671 |
+
setVolumeBars(volume_update);
|
| 672 |
+
Plotly.update(plotDiv, {}, layout_update);
|
| 673 |
+
}
|
| 674 |
+
});
|
| 675 |
+
|
| 676 |
+
if (theme !== "dark") {
|
| 677 |
+
setChangeTheme(true);
|
| 678 |
+
}
|
| 679 |
+
}
|
| 680 |
+
}, [plotLoaded]);
|
| 681 |
+
|
| 682 |
+
useEffect(() => {
|
| 683 |
+
// This effect ensures annotations appear correctly on all chart types
|
| 684 |
+
if (plotDiv && plotData?.layout?.annotations?.length > 0) {
|
| 685 |
+
Plotly.relayout(plotDiv, {'annotations': plotData.layout.annotations});
|
| 686 |
+
}
|
| 687 |
+
}, [plotData.layout.annotations, plotDiv]); const plotComponent = useMemo(
|
| 688 |
+
() => (
|
| 689 |
+
<PlotComponent
|
| 690 |
+
onInitialized={(_figure, graphDiv) => {
|
| 691 |
+
if (!plotDiv) {
|
| 692 |
+
if (graphDiv) {
|
| 693 |
+
graphDiv.globals = globals;
|
| 694 |
+
setPlotDiv(graphDiv);
|
| 695 |
+
graphDiv.on('plotly_clickannotation', function(data) {
|
| 696 |
+
if (data && data.annotation && data.annotation.text) {
|
| 697 |
+
setModal({
|
| 698 |
+
name: "textDialog",
|
| 699 |
+
data: {
|
| 700 |
+
annotation_dict: data.annotation,
|
| 701 |
+
mode: "edit"
|
| 702 |
+
}
|
| 703 |
+
});
|
| 704 |
+
}
|
| 705 |
+
});
|
| 706 |
+
}
|
| 707 |
+
}
|
| 708 |
+
if (!plotLoaded) setPlotLoaded(true);
|
| 709 |
+
}}
|
| 710 |
+
className="w-full h-full"
|
| 711 |
+
divId="plotlyChart"
|
| 712 |
+
data={plotData.data}
|
| 713 |
+
layout={plotData.layout}
|
| 714 |
+
frames={plotData.frames}
|
| 715 |
+
config={PlotConfig({
|
| 716 |
+
setModal: setModal,
|
| 717 |
+
changeTheme: setChangeTheme,
|
| 718 |
+
autoScaling: setAutoScaling,
|
| 719 |
+
Loading: setLoading,
|
| 720 |
+
changeColor: setChangeColor,
|
| 721 |
+
})}
|
| 722 |
+
/>
|
| 723 |
+
),
|
| 724 |
+
[
|
| 725 |
+
plotDiv,
|
| 726 |
+
originalData,
|
| 727 |
+
plotLoaded,
|
| 728 |
+
plotData,
|
| 729 |
+
globals,
|
| 730 |
+
setPlotDiv,
|
| 731 |
+
setPlotLoaded,
|
| 732 |
+
setModal,
|
| 733 |
+
setChangeTheme,
|
| 734 |
+
setAutoScaling,
|
| 735 |
+
setLoading,
|
| 736 |
+
onChangeColor,
|
| 737 |
+
],
|
| 738 |
+
);
|
| 739 |
+
|
| 740 |
+
const memoizedAlertDialog = useMemo(() => {
|
| 741 |
+
return (
|
| 742 |
+
<AlertDialog
|
| 743 |
+
title={modal?.data?.title}
|
| 744 |
+
content={modal?.data?.content}
|
| 745 |
+
open={modal?.name === "alertDialog"}
|
| 746 |
+
close={onClose}
|
| 747 |
+
/>
|
| 748 |
+
);
|
| 749 |
+
}, [modal, onClose]);
|
| 750 |
+
|
| 751 |
+
const memoizedOverlayChartDialog = useMemo(() => {
|
| 752 |
+
return (
|
| 753 |
+
<OverlayChartDialog
|
| 754 |
+
addOverlay={(overlay) => {
|
| 755 |
+
console.log(overlay);
|
| 756 |
+
overlay.layout.showlegend = true;
|
| 757 |
+
setOriginalData(overlay);
|
| 758 |
+
setPlotData(overlay);
|
| 759 |
+
}}
|
| 760 |
+
plotlyData={originalData}
|
| 761 |
+
setLoading={setLoading}
|
| 762 |
+
open={modal?.name === "overlayChart"}
|
| 763 |
+
close={onClose}
|
| 764 |
+
/>
|
| 765 |
+
);
|
| 766 |
+
}, [modal, plotData, onClose, setPlotData, setLoading]);
|
| 767 |
+
|
| 768 |
+
const memoizedTitleChartDialog = useMemo(() => {
|
| 769 |
+
return (
|
| 770 |
+
<TitleChartDialog
|
| 771 |
+
updateTitle={(title) => setChartTitle(title)}
|
| 772 |
+
updateAxesTitles={(axesTitles) => setAxesTitles(axesTitles)}
|
| 773 |
+
defaultTitle={chartTitle}
|
| 774 |
+
plotlyData={plotData}
|
| 775 |
+
open={modal?.name === "titleDialog"}
|
| 776 |
+
close={onClose}
|
| 777 |
+
/>
|
| 778 |
+
);
|
| 779 |
+
}, [modal, plotData, chartTitle, onClose]);
|
| 780 |
+
|
| 781 |
+
const memoizedTextChartDialog = useMemo(() => {
|
| 782 |
+
return (
|
| 783 |
+
<TextChartDialog
|
| 784 |
+
popupData={modal?.name === "textDialog" ? modal?.data : null}
|
| 785 |
+
open={modal?.name === "textDialog"}
|
| 786 |
+
close={onClose}
|
| 787 |
+
addAnnotation={(data) => onAddAnnotation(data)}
|
| 788 |
+
deleteAnnotation={(data) => onDeleteAnnotation(data)}
|
| 789 |
+
/>
|
| 790 |
+
);
|
| 791 |
+
}, [
|
| 792 |
+
modal,
|
| 793 |
+
onAddAnnotation,
|
| 794 |
+
onDeleteAnnotation,
|
| 795 |
+
onClose,
|
| 796 |
+
plotData,
|
| 797 |
+
setPlotData,
|
| 798 |
+
]);
|
| 799 |
+
|
| 800 |
+
const memoizedChangeColor = useMemo(() => {
|
| 801 |
+
return <ChangeColor open={colorActive} onColorChange={onChangeColor} />;
|
| 802 |
+
}, [colorActive, onChangeColor]);
|
| 803 |
+
|
| 804 |
+
const memoizedChartHotkeys = useMemo(() => {
|
| 805 |
+
return (
|
| 806 |
+
<ChartHotkeys
|
| 807 |
+
setModal={setModal}
|
| 808 |
+
Loading={setLoading}
|
| 809 |
+
changeColor={setChangeColor}
|
| 810 |
+
/>
|
| 811 |
+
);
|
| 812 |
+
}, [setModal, setLoading, setChangeColor]);
|
| 813 |
+
|
| 814 |
+
return (
|
| 815 |
+
<div className="relative h-full">
|
| 816 |
+
{loading && (
|
| 817 |
+
<div className="absolute inset-0 flex items-center justify-center z-[100]">
|
| 818 |
+
<svg
|
| 819 |
+
className="animate-spin h-20 w-20 text-white"
|
| 820 |
+
xmlns="http://www.w3.org/2000/svg"
|
| 821 |
+
fill="none"
|
| 822 |
+
viewBox="0 0 24 24"
|
| 823 |
+
>
|
| 824 |
+
<circle
|
| 825 |
+
className="opacity-25"
|
| 826 |
+
cx="12"
|
| 827 |
+
cy="12"
|
| 828 |
+
r="10"
|
| 829 |
+
stroke="currentColor"
|
| 830 |
+
strokeWidth="4"
|
| 831 |
+
/>
|
| 832 |
+
<path
|
| 833 |
+
className="opacity-75"
|
| 834 |
+
fill="currentColor"
|
| 835 |
+
d="M4 12a8 8 0 018-8v8z"
|
| 836 |
+
/>
|
| 837 |
+
</svg>
|
| 838 |
+
</div>
|
| 839 |
+
)}
|
| 840 |
+
<div id="loading" className="saving">
|
| 841 |
+
<div id="loading_text" className="loading_text" />
|
| 842 |
+
<div id="loader" className="loader" />
|
| 843 |
+
</div>
|
| 844 |
+
{memoizedAlertDialog}
|
| 845 |
+
{memoizedOverlayChartDialog}
|
| 846 |
+
{memoizedTitleChartDialog}
|
| 847 |
+
{memoizedTextChartDialog}
|
| 848 |
+
{memoizedChangeColor}
|
| 849 |
+
{memoizedChartHotkeys}
|
| 850 |
+
|
| 851 |
+
<div className="relative h-full" id="MainChart">
|
| 852 |
+
<div className="_header relative gap-4 py-2 text-center text-xs flex items-center justify-between px-4 text-white">
|
| 853 |
+
<div className="w-1/3">
|
| 854 |
+
<svg
|
| 855 |
+
xmlns="http://www.w3.org/2000/svg"
|
| 856 |
+
width="64"
|
| 857 |
+
height="40"
|
| 858 |
+
fill="none"
|
| 859 |
+
viewBox="0 0 64 40"
|
| 860 |
+
>
|
| 861 |
+
<path
|
| 862 |
+
fill="#fff"
|
| 863 |
+
d="M61.283 3.965H33.608v27.757h25.699V19.826H37.561v-3.965H63.26V3.965h-1.977zM39.538 23.792h15.815v3.965H37.561v-3.965h1.977zM59.306 9.913v1.983H37.561V7.931h21.745v1.982zM33.606 0h-3.954v3.965H33.606V0zM25.7 3.966H0V15.86h25.7v3.965H3.953v11.896h25.7V3.966h-3.955zm0 21.808v1.983H7.907v-3.965h17.791v1.982zm0-15.86v1.982H3.953V7.931h21.745v1.982zM37.039 35.693v2.952l-.246-.246-.245-.245-.245-.247-.245-.246-.246-.246-.245-.245-.245-.247-.247-.246-.245-.246-.245-.246-.245-.246-.246-.246h-.49v3.936h.49v-3.198l.246.246.245.246.245.246.245.246.246.246.246.246.245.247.246.245.245.246.245.247.245.246.246.245.245.246h.245v-3.936h-.49zM44.938 37.17h-.491v-1.477h-2.944v3.937h3.93v-2.46h-.495zm-2.944-.246v-.739h1.962v.984h-1.962v-.245zm2.944.984v1.23h-2.944V37.66h2.944v.247zM52.835 37.17h-.49v-1.477h-2.946v3.937h3.925v-2.46h-.489zm-2.944-.246v-.739h1.963v.984h-1.965l.002-.245zm2.944.984v1.23H49.89V37.66h2.946v.247zM29.174 35.693H25.739v3.936H29.663v-.491H26.229v-.984h2.943v-.493H26.229v-1.476h3.434v-.492h-.489zM13.37 35.693H9.934v3.937h3.925v-3.937h-.49zm0 .738v2.709h-2.945v-2.955h2.943l.001.246zM21.276 35.693h-3.435v3.937h.491v-1.476h3.434v-2.461h-.49zm0 .738v1.23h-2.944v-1.476h2.944v.246z"
|
| 864 |
+
/>
|
| 865 |
+
</svg>
|
| 866 |
+
</div>
|
| 867 |
+
<p className="font-bold w-1/3 flex flex-col gap-0.5 items-center">
|
| 868 |
+
{chartTitle}
|
| 869 |
+
{/* {source && (
|
| 870 |
+
<span className="font-normal text-[10px]">{`[${source}]`}</span>
|
| 871 |
+
)} */}
|
| 872 |
+
</p>
|
| 873 |
+
<p className="w-1/3 text-right text-xs">
|
| 874 |
+
{new Intl.DateTimeFormat("en-GB", {
|
| 875 |
+
dateStyle: "full",
|
| 876 |
+
timeStyle: "long",
|
| 877 |
+
})
|
| 878 |
+
.format(date)
|
| 879 |
+
.replace(/:\d\d /, " ")}
|
| 880 |
+
<br />
|
| 881 |
+
<span className="text-grey-400">{cmd}</span>
|
| 882 |
+
</p>
|
| 883 |
+
{/* {source && typeof source === "string" && source.includes("*") && (
|
| 884 |
+
<p className="text-[8px] absolute bottom-0 right-4">
|
| 885 |
+
*not affiliated
|
| 886 |
+
</p>
|
| 887 |
+
)} */}
|
| 888 |
+
</div>
|
| 889 |
+
<div
|
| 890 |
+
className={clsx("w-full sm:pb-12", {
|
| 891 |
+
"h-[calc(100%-10px)]": maximizePlot,
|
| 892 |
+
"h-[calc(100%-50px)]": !maximizePlot,
|
| 893 |
+
})}
|
| 894 |
+
>
|
| 895 |
+
{plotComponent}
|
| 896 |
+
</div>
|
| 897 |
+
</div>
|
| 898 |
+
</div>
|
| 899 |
+
);
|
| 900 |
+
}
|
| 901 |
+
|
| 902 |
+
export default React.memo(Chart);
|
frontend-components/plotly/src/components/Config.tsx
ADDED
|
@@ -0,0 +1,800 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export const ICONS = {
|
| 2 |
+
sunIcon: {
|
| 3 |
+
viewBox: "0 0 16 16",
|
| 4 |
+
width: 16,
|
| 5 |
+
height: 16,
|
| 6 |
+
path: "M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z",
|
| 7 |
+
},
|
| 8 |
+
moonIcon: {
|
| 9 |
+
viewBox: "0 0 25 25",
|
| 10 |
+
width: 25,
|
| 11 |
+
height: 25,
|
| 12 |
+
path: "M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z",
|
| 13 |
+
},
|
| 14 |
+
plotCsv: {
|
| 15 |
+
width: 900,
|
| 16 |
+
height: 900,
|
| 17 |
+
path: "M170.666667 106.666667l0.192 736H906.666667v64H149.546667c-23.552 0-42.666667-19.093333-42.666667-42.666667L106.666667 106.666667h64z m686.506666 454.144l13.653334 16.362666a21.333333 21.333333 0 0 1-2.666667 30.058667l-171.157333 143.146667a21.333333 21.333333 0 0 1-21.546667 3.477333l-229.973333-91.285333-113.834667 94.997333a21.333333 21.333333 0 0 1-30.037333-2.709333l-13.653334-16.362667a21.333333 21.333333 0 0 1 2.688-30.058667l133.312-111.274666a21.333333 21.333333 0 0 1 21.546667-3.456l229.930667 91.264 151.68-126.826667a21.333333 21.333333 0 0 1 30.037333 2.666667z m-1.621333-417.962667l16.896 13.013333a21.333333 21.333333 0 0 1 3.925333 29.888L685.802667 433.706667a21.333333 21.333333 0 0 1-20.202667 8.085333l-226.794667-35.413333-150.186666 222.357333a21.333333 21.333333 0 0 1-27.477334 7.018667l-2.133333-1.28-17.685333-11.946667a21.333333 21.333333 0 0 1-5.738667-29.610667l165.354667-244.821333a21.333333 21.333333 0 0 1 20.992-9.130667L650.453333 374.613333l175.146667-227.882666a21.333333 21.333333 0 0 1 29.930667-3.904z",
|
| 18 |
+
},
|
| 19 |
+
addText: {
|
| 20 |
+
path: "M896 928H128a32 32 0 0 1-32-32V128a32 32 0 0 1 32-32h768a32 32 0 0 1 32 32v768a32 32 0 0 1-32 32z m-736-64h704v-704h-704z M704 352H320a32 32 0 0 1 0-64h384a32 32 0 0 1 0 64z M512 736a32 32 0 0 1-32-32V320a32 32 0 0 1 64 0v384a32 32 0 0 1-32 32z",
|
| 21 |
+
width: 950,
|
| 22 |
+
height: 950,
|
| 23 |
+
},
|
| 24 |
+
changeTitle: {
|
| 25 |
+
path: "M122.368 165.888h778.24c-9.216 0-16.384-7.168-16.384-16.384v713.728c0-9.216 7.168-16.384 16.384-16.384h-778.24c9.216 0 16.384 7.168 16.384 16.384V150.016c0 8.192-6.656 15.872-16.384 15.872z m-32.768 684.544c0 26.112 20.992 47.104 47.104 47.104h750.08c26.112 0 47.104-20.992 47.104-47.104V162.304c0-26.112-20.992-47.104-47.104-47.104H136.704c-26.112 0-47.104 20.992-47.104 47.104v688.128z M244.736 656.896h534.016v62.464H244.736z M373.76 358.4H307.2v219.136h-45.568V358.4H192v-41.472H373.76V358.4zM403.968 316.928h44.032v50.176h-44.032v-50.176z m0 67.072h44.032v194.048h-44.032V384zM576.512 541.184l8.704 31.744c-13.312 5.12-26.624 8.192-38.912 8.704-32.768 1.024-48.64-15.36-48.128-48.128V422.912h-26.624V384h26.624v-46.592l44.032-21.504V384h36.352v38.912h-36.352V532.48c-1.024 10.24 3.072 14.848 11.264 13.824 5.12 0 12.8-1.536 23.04-5.12zM619.008 316.928h44.032v260.608h-44.032V316.928zM813.056 509.952l41.472 12.8c-11.776 40.96-37.888 61.44-78.336 60.416-52.736-1.536-80.384-34.304-81.92-98.304 2.56-67.072 29.696-102.4 81.92-105.984 52.224 1.536 78.336 36.864 79.36 105.984v13.824h-117.248c3.584 30.208 15.872 45.568 37.888 46.592 19.968 0.512 32.256-11.264 36.864-35.328z m-72.704-51.712h70.656c-1.024-25.088-12.288-38.4-33.792-38.912-21.504 0.512-33.792 13.824-36.864 38.912z",
|
| 26 |
+
width: 920,
|
| 27 |
+
height: 900,
|
| 28 |
+
},
|
| 29 |
+
changeColor: {
|
| 30 |
+
path: "M8 3C5.79 3 4 4.79 4 7V14C4 15.1 4.9 16 6 16H9V20C9 21.1 9.9 22 11 22H13C14.1 22 15 21.1 15 20V16H18C19.1 16 20 15.1 20 14V3H8M8 5H12V7H14V5H15V9H17V5H18V10H6V7C6 5.9 6.9 5 8 5M6 14V12H18V14H6Z",
|
| 31 |
+
width: 22,
|
| 32 |
+
height: 22,
|
| 33 |
+
},
|
| 34 |
+
uploadImage: {
|
| 35 |
+
path: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5",
|
| 36 |
+
width: 1024,
|
| 37 |
+
height: 1024,
|
| 38 |
+
},
|
| 39 |
+
downloadCsv: {
|
| 40 |
+
path: `M486.2,196.121h-13.164V132.59c0-0.399-0.064-0.795-0.116-1.2c-0.021-2.52-0.824-5-2.551-6.96L364.656,3.677
|
| 41 |
+
c-0.031-0.034-0.064-0.044-0.085-0.075c-0.629-0.707-1.364-1.292-2.141-1.796c-0.231-0.157-0.462-0.286-0.704-0.419
|
| 42 |
+
c-0.672-0.365-1.386-0.672-2.121-0.893c-0.199-0.052-0.377-0.134-0.576-0.188C358.229,0.118,357.4,0,356.562,0H96.757
|
| 43 |
+
C84.893,0,75.256,9.649,75.256,21.502v174.613H62.093c-16.972,0-30.733,13.756-30.733,30.73v159.81
|
| 44 |
+
c0,16.966,13.761,30.736,30.733,30.736h13.163V526.79c0,11.854,9.637,21.501,21.501,21.501h354.777
|
| 45 |
+
c11.853,0,21.502-9.647,21.502-21.501V417.392H486.2c16.966,0,30.729-13.764,30.729-30.731v-159.81
|
| 46 |
+
C516.93,209.872,503.166,196.121,486.2,196.121z M96.757,21.502h249.053v110.006c0,5.94,4.818,10.751,10.751,10.751h94.973v53.861
|
| 47 |
+
H96.757V21.502z M258.618,313.18c-26.68-9.291-44.063-24.053-44.063-47.389c0-27.404,22.861-48.368,60.733-48.368
|
| 48 |
+
c18.107,0,31.447,3.811,40.968,8.107l-8.09,29.3c-6.43-3.107-17.862-7.632-33.59-7.632c-15.717,0-23.339,7.149-23.339,15.485
|
| 49 |
+
c0,10.247,9.047,14.769,29.78,22.632c28.341,10.479,41.681,25.239,41.681,47.874c0,26.909-20.721,49.786-64.792,49.786
|
| 50 |
+
c-18.338,0-36.449-4.776-45.497-9.77l7.38-30.016c9.772,5.014,24.775,10.006,40.264,10.006c16.671,0,25.488-6.908,25.488-17.396
|
| 51 |
+
C285.536,325.789,277.909,320.078,258.618,313.18z M69.474,302.692c0-54.781,39.074-85.269,87.654-85.269
|
| 52 |
+
c18.822,0,33.113,3.811,39.549,7.149l-7.392,28.816c-7.38-3.084-17.632-5.939-30.491-5.939c-28.822,0-51.206,17.375-51.206,53.099
|
| 53 |
+
c0,32.158,19.051,52.4,51.456,52.4c10.947,0,23.097-2.378,30.241-5.238l5.483,28.346c-6.672,3.34-21.674,6.919-41.208,6.919
|
| 54 |
+
C98.06,382.976,69.474,348.424,69.474,302.692z M451.534,520.962H96.757v-103.57h354.777V520.962z M427.518,380.583h-42.399
|
| 55 |
+
l-51.45-160.536h39.787l19.526,67.894c5.479,19.046,10.479,37.386,14.299,57.397h0.709c4.048-19.298,9.045-38.352,14.526-56.693
|
| 56 |
+
l20.487-68.598h38.599L427.518,380.583z`,
|
| 57 |
+
width: 550,
|
| 58 |
+
height: 550,
|
| 59 |
+
transform: "translate(4, 0)",
|
| 60 |
+
},
|
| 61 |
+
downloadImage: {
|
| 62 |
+
path: "M22.71,6.29a1,1,0,0,0-1.42,0L20,7.59V2a1,1,0,0,0-2,0V7.59l-1.29-1.3a1,1,0,0,0-1.42,1.42l3,3a1,1,0,0,0,.33.21.94.94,0,0,0,.76,0,1,1,0,0,0,.33-.21l3-3A1,1,0,0,0,22.71,6.29ZM19,13a1,1,0,0,0-1,1v.38L16.52,12.9a2.79,2.79,0,0,0-3.93,0l-.7.7L9.41,11.12a2.85,2.85,0,0,0-3.93,0L4,12.6V7A1,1,0,0,1,5,6h8a1,1,0,0,0,0-2H5A3,3,0,0,0,2,7V19a3,3,0,0,0,3,3H17a3,3,0,0,0,3-3V14A1,1,0,0,0,19,13ZM5,20a1,1,0,0,1-1-1V15.43l2.9-2.9a.79.79,0,0,1,1.09,0l3.17,3.17,0,0L15.46,20Zm13-1a.89.89,0,0,1-.18.53L13.31,15l.7-.7a.77.77,0,0,1,1.1,0L18,17.21Z",
|
| 63 |
+
width: 21,
|
| 64 |
+
height: 21,
|
| 65 |
+
transform: "translate(-2, -2)",
|
| 66 |
+
},
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
export const DARK_CHARTS_TEMPLATE = {
|
| 70 |
+
line: {
|
| 71 |
+
"up_color": "#0074D9",
|
| 72 |
+
"down_color": "#FF4136",
|
| 73 |
+
"color": "#111111",
|
| 74 |
+
"width": 1.5
|
| 75 |
+
},
|
| 76 |
+
data: {
|
| 77 |
+
candlestick: [
|
| 78 |
+
{
|
| 79 |
+
decreasing: {
|
| 80 |
+
fillcolor: "#e4003a",
|
| 81 |
+
line: {
|
| 82 |
+
color: "#e4003a",
|
| 83 |
+
},
|
| 84 |
+
},
|
| 85 |
+
increasing: {
|
| 86 |
+
fillcolor: "#00ACFF",
|
| 87 |
+
line: {
|
| 88 |
+
color: "#00ACFF",
|
| 89 |
+
},
|
| 90 |
+
},
|
| 91 |
+
type: "candlestick",
|
| 92 |
+
},
|
| 93 |
+
],
|
| 94 |
+
},
|
| 95 |
+
layout: {
|
| 96 |
+
annotationdefaults: {
|
| 97 |
+
showarrow: false,
|
| 98 |
+
},
|
| 99 |
+
autotypenumbers: "strict",
|
| 100 |
+
colorway: [
|
| 101 |
+
"#1f77b4",
|
| 102 |
+
"#ff7f0e",
|
| 103 |
+
"#2ca02c",
|
| 104 |
+
"#d62728",
|
| 105 |
+
"#9467bd",
|
| 106 |
+
"#8c564b",
|
| 107 |
+
"#e377c2",
|
| 108 |
+
"#bcbd22",
|
| 109 |
+
"#17becf",
|
| 110 |
+
"#aec7e8",
|
| 111 |
+
"#ffbb78",
|
| 112 |
+
"#ff9896",
|
| 113 |
+
"#c5b0d5",
|
| 114 |
+
"#f7b6d2",
|
| 115 |
+
"#dbdb8d",
|
| 116 |
+
"#9edae5"
|
| 117 |
+
],
|
| 118 |
+
dragmode: "pan",
|
| 119 |
+
font: {
|
| 120 |
+
family: "Arial, Helvetica, sans-serif",
|
| 121 |
+
size: 16,
|
| 122 |
+
},
|
| 123 |
+
hoverlabel: {
|
| 124 |
+
align: "left",
|
| 125 |
+
font: {
|
| 126 |
+
family: "Arial, Helvetica, sans-serif",
|
| 127 |
+
size: 14,
|
| 128 |
+
},
|
| 129 |
+
},
|
| 130 |
+
mapbox: {
|
| 131 |
+
style: "dark",
|
| 132 |
+
},
|
| 133 |
+
hovermode: "x",
|
| 134 |
+
legend: {
|
| 135 |
+
bgcolor: "rgba(0, 0, 0, 0)",
|
| 136 |
+
x: 1,
|
| 137 |
+
xanchor: "right",
|
| 138 |
+
y: 0.99,
|
| 139 |
+
yanchor: "bottom",
|
| 140 |
+
font: {
|
| 141 |
+
family: "Arial, Helvetica, sans-serif",
|
| 142 |
+
size: 14,
|
| 143 |
+
},
|
| 144 |
+
},
|
| 145 |
+
paper_bgcolor: "#000000",
|
| 146 |
+
plot_bgcolor: "#000000",
|
| 147 |
+
xaxis: {
|
| 148 |
+
automargin: true,
|
| 149 |
+
autorange: true,
|
| 150 |
+
rangeslider: {
|
| 151 |
+
visible: false,
|
| 152 |
+
},
|
| 153 |
+
showgrid: true,
|
| 154 |
+
showline: true,
|
| 155 |
+
tickfont: {
|
| 156 |
+
family: "Arial, Helvetica, sans-serif",
|
| 157 |
+
size: 14,
|
| 158 |
+
},
|
| 159 |
+
zeroline: false,
|
| 160 |
+
tick0: 1,
|
| 161 |
+
title: {
|
| 162 |
+
standoff: 20,
|
| 163 |
+
text: "",
|
| 164 |
+
font: {
|
| 165 |
+
family: "Arial, Helvetica, sans-serif",
|
| 166 |
+
size: 16,
|
| 167 |
+
},
|
| 168 |
+
},
|
| 169 |
+
gridcolor: "#283442",
|
| 170 |
+
linecolor: "#F5EFF3",
|
| 171 |
+
mirror: true,
|
| 172 |
+
ticks: "outside",
|
| 173 |
+
},
|
| 174 |
+
yaxis: {
|
| 175 |
+
anchor: "x",
|
| 176 |
+
automargin: true,
|
| 177 |
+
fixedrange: false,
|
| 178 |
+
zeroline: false,
|
| 179 |
+
showgrid: true,
|
| 180 |
+
showline: true,
|
| 181 |
+
side: "right",
|
| 182 |
+
tick0: 0.5,
|
| 183 |
+
tickfont: {
|
| 184 |
+
family: "Arial, Helvetica, sans-serif",
|
| 185 |
+
size: 14,
|
| 186 |
+
},
|
| 187 |
+
title: {
|
| 188 |
+
standoff: 20,
|
| 189 |
+
text: "",
|
| 190 |
+
font: {
|
| 191 |
+
family: "Arial, Helvetica, sans-serif",
|
| 192 |
+
size: 16,
|
| 193 |
+
},
|
| 194 |
+
},
|
| 195 |
+
gridcolor: "#283442",
|
| 196 |
+
linecolor: "#F5EFF3",
|
| 197 |
+
mirror: true,
|
| 198 |
+
ticks: "outside",
|
| 199 |
+
},
|
| 200 |
+
},
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
export const LIGHT_CHARTS_TEMPLATE = {
|
| 204 |
+
line: {
|
| 205 |
+
"up_color": "#0074D9",
|
| 206 |
+
"down_color": "#FF4136",
|
| 207 |
+
"color": "#111111",
|
| 208 |
+
"width": 1.5
|
| 209 |
+
},
|
| 210 |
+
data: {
|
| 211 |
+
barpolar: [
|
| 212 |
+
{
|
| 213 |
+
marker: {
|
| 214 |
+
line: {
|
| 215 |
+
color: "white",
|
| 216 |
+
width: 0.5,
|
| 217 |
+
},
|
| 218 |
+
pattern: {
|
| 219 |
+
fillmode: "overlay",
|
| 220 |
+
size: 10,
|
| 221 |
+
solidity: 0.2,
|
| 222 |
+
},
|
| 223 |
+
},
|
| 224 |
+
type: "barpolar",
|
| 225 |
+
},
|
| 226 |
+
],
|
| 227 |
+
bar: [
|
| 228 |
+
{
|
| 229 |
+
error_x: {
|
| 230 |
+
color: "#2a3f5f",
|
| 231 |
+
},
|
| 232 |
+
error_y: {
|
| 233 |
+
color: "#2a3f5f",
|
| 234 |
+
},
|
| 235 |
+
marker: {
|
| 236 |
+
line: {
|
| 237 |
+
color: "white",
|
| 238 |
+
width: 0.5,
|
| 239 |
+
},
|
| 240 |
+
pattern: {
|
| 241 |
+
fillmode: "overlay",
|
| 242 |
+
size: 10,
|
| 243 |
+
solidity: 0.2,
|
| 244 |
+
},
|
| 245 |
+
},
|
| 246 |
+
type: "bar",
|
| 247 |
+
},
|
| 248 |
+
],
|
| 249 |
+
carpet: [
|
| 250 |
+
{
|
| 251 |
+
aaxis: {
|
| 252 |
+
endlinecolor: "#2a3f5f",
|
| 253 |
+
gridcolor: "#C8D4E3",
|
| 254 |
+
linecolor: "#C8D4E3",
|
| 255 |
+
minorgridcolor: "#C8D4E3",
|
| 256 |
+
startlinecolor: "#2a3f5f",
|
| 257 |
+
},
|
| 258 |
+
baxis: {
|
| 259 |
+
endlinecolor: "#2a3f5f",
|
| 260 |
+
gridcolor: "#C8D4E3",
|
| 261 |
+
linecolor: "#C8D4E3",
|
| 262 |
+
minorgridcolor: "#C8D4E3",
|
| 263 |
+
startlinecolor: "#2a3f5f",
|
| 264 |
+
},
|
| 265 |
+
type: "carpet",
|
| 266 |
+
},
|
| 267 |
+
],
|
| 268 |
+
choropleth: [
|
| 269 |
+
{
|
| 270 |
+
colorbar: {
|
| 271 |
+
outlinewidth: 0,
|
| 272 |
+
ticks: "",
|
| 273 |
+
},
|
| 274 |
+
type: "choropleth",
|
| 275 |
+
},
|
| 276 |
+
],
|
| 277 |
+
contourcarpet: [
|
| 278 |
+
{
|
| 279 |
+
colorbar: {
|
| 280 |
+
outlinewidth: 0,
|
| 281 |
+
ticks: "",
|
| 282 |
+
},
|
| 283 |
+
type: "contourcarpet",
|
| 284 |
+
},
|
| 285 |
+
],
|
| 286 |
+
contour: [
|
| 287 |
+
{
|
| 288 |
+
colorbar: {
|
| 289 |
+
outlinewidth: 0,
|
| 290 |
+
ticks: "",
|
| 291 |
+
},
|
| 292 |
+
colorscale: [
|
| 293 |
+
[0.0, "#0d0887"],
|
| 294 |
+
[0.1111111111111111, "#46039f"],
|
| 295 |
+
[0.2222222222222222, "#7201a8"],
|
| 296 |
+
[0.3333333333333333, "#9c179e"],
|
| 297 |
+
[0.4444444444444444, "#bd3786"],
|
| 298 |
+
[0.5555555555555556, "#d8576b"],
|
| 299 |
+
[0.6666666666666666, "#ed7953"],
|
| 300 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 301 |
+
[0.8888888888888888, "#fdca26"],
|
| 302 |
+
[1.0, "#f0f921"],
|
| 303 |
+
],
|
| 304 |
+
type: "contour",
|
| 305 |
+
},
|
| 306 |
+
],
|
| 307 |
+
heatmap: [
|
| 308 |
+
{
|
| 309 |
+
colorbar: {
|
| 310 |
+
outlinewidth: 0,
|
| 311 |
+
ticks: "",
|
| 312 |
+
},
|
| 313 |
+
colorscale: [
|
| 314 |
+
[0.0, "#0d0887"],
|
| 315 |
+
[0.1111111111111111, "#46039f"],
|
| 316 |
+
[0.2222222222222222, "#7201a8"],
|
| 317 |
+
[0.3333333333333333, "#9c179e"],
|
| 318 |
+
[0.4444444444444444, "#bd3786"],
|
| 319 |
+
[0.5555555555555556, "#d8576b"],
|
| 320 |
+
[0.6666666666666666, "#ed7953"],
|
| 321 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 322 |
+
[0.8888888888888888, "#fdca26"],
|
| 323 |
+
[1.0, "#f0f921"],
|
| 324 |
+
],
|
| 325 |
+
type: "heatmap",
|
| 326 |
+
},
|
| 327 |
+
],
|
| 328 |
+
histogram2dcontour: [
|
| 329 |
+
{
|
| 330 |
+
colorbar: {
|
| 331 |
+
outlinewidth: 0,
|
| 332 |
+
ticks: "",
|
| 333 |
+
},
|
| 334 |
+
colorscale: [
|
| 335 |
+
[0.0, "#0d0887"],
|
| 336 |
+
[0.1111111111111111, "#46039f"],
|
| 337 |
+
[0.2222222222222222, "#7201a8"],
|
| 338 |
+
[0.3333333333333333, "#9c179e"],
|
| 339 |
+
[0.4444444444444444, "#bd3786"],
|
| 340 |
+
[0.5555555555555556, "#d8576b"],
|
| 341 |
+
[0.6666666666666666, "#ed7953"],
|
| 342 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 343 |
+
[0.8888888888888888, "#fdca26"],
|
| 344 |
+
[1.0, "#f0f921"],
|
| 345 |
+
],
|
| 346 |
+
type: "histogram2dcontour",
|
| 347 |
+
},
|
| 348 |
+
],
|
| 349 |
+
histogram2d: [
|
| 350 |
+
{
|
| 351 |
+
colorbar: {
|
| 352 |
+
outlinewidth: 0,
|
| 353 |
+
ticks: "",
|
| 354 |
+
},
|
| 355 |
+
colorscale: [
|
| 356 |
+
[0.0, "#0d0887"],
|
| 357 |
+
[0.1111111111111111, "#46039f"],
|
| 358 |
+
[0.2222222222222222, "#7201a8"],
|
| 359 |
+
[0.3333333333333333, "#9c179e"],
|
| 360 |
+
[0.4444444444444444, "#bd3786"],
|
| 361 |
+
[0.5555555555555556, "#d8576b"],
|
| 362 |
+
[0.6666666666666666, "#ed7953"],
|
| 363 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 364 |
+
[0.8888888888888888, "#fdca26"],
|
| 365 |
+
[1.0, "#f0f921"],
|
| 366 |
+
],
|
| 367 |
+
type: "histogram2d",
|
| 368 |
+
},
|
| 369 |
+
],
|
| 370 |
+
histogram: [
|
| 371 |
+
{
|
| 372 |
+
marker: {
|
| 373 |
+
pattern: {
|
| 374 |
+
fillmode: "overlay",
|
| 375 |
+
size: 10,
|
| 376 |
+
solidity: 0.2,
|
| 377 |
+
},
|
| 378 |
+
},
|
| 379 |
+
type: "histogram",
|
| 380 |
+
},
|
| 381 |
+
],
|
| 382 |
+
mesh3d: [
|
| 383 |
+
{
|
| 384 |
+
colorbar: {
|
| 385 |
+
outlinewidth: 0,
|
| 386 |
+
ticks: "",
|
| 387 |
+
},
|
| 388 |
+
type: "mesh3d",
|
| 389 |
+
},
|
| 390 |
+
],
|
| 391 |
+
parcoords: [
|
| 392 |
+
{
|
| 393 |
+
line: {
|
| 394 |
+
colorbar: {
|
| 395 |
+
outlinewidth: 0,
|
| 396 |
+
ticks: "",
|
| 397 |
+
},
|
| 398 |
+
},
|
| 399 |
+
type: "parcoords",
|
| 400 |
+
},
|
| 401 |
+
],
|
| 402 |
+
pie: [
|
| 403 |
+
{
|
| 404 |
+
automargin: true,
|
| 405 |
+
type: "pie",
|
| 406 |
+
},
|
| 407 |
+
],
|
| 408 |
+
scatter3d: [
|
| 409 |
+
{
|
| 410 |
+
line: {
|
| 411 |
+
colorbar: {
|
| 412 |
+
outlinewidth: 0,
|
| 413 |
+
ticks: "",
|
| 414 |
+
},
|
| 415 |
+
},
|
| 416 |
+
marker: {
|
| 417 |
+
colorbar: {
|
| 418 |
+
outlinewidth: 0,
|
| 419 |
+
ticks: "",
|
| 420 |
+
},
|
| 421 |
+
},
|
| 422 |
+
type: "scatter3d",
|
| 423 |
+
},
|
| 424 |
+
],
|
| 425 |
+
scattercarpet: [
|
| 426 |
+
{
|
| 427 |
+
marker: {
|
| 428 |
+
colorbar: {
|
| 429 |
+
outlinewidth: 0,
|
| 430 |
+
ticks: "",
|
| 431 |
+
},
|
| 432 |
+
},
|
| 433 |
+
type: "scattercarpet",
|
| 434 |
+
},
|
| 435 |
+
],
|
| 436 |
+
scattergeo: [
|
| 437 |
+
{
|
| 438 |
+
marker: {
|
| 439 |
+
colorbar: {
|
| 440 |
+
outlinewidth: 0,
|
| 441 |
+
ticks: "",
|
| 442 |
+
},
|
| 443 |
+
},
|
| 444 |
+
type: "scattergeo",
|
| 445 |
+
},
|
| 446 |
+
],
|
| 447 |
+
scattergl: [
|
| 448 |
+
{
|
| 449 |
+
marker: {
|
| 450 |
+
colorbar: {
|
| 451 |
+
outlinewidth: 0,
|
| 452 |
+
ticks: "",
|
| 453 |
+
},
|
| 454 |
+
},
|
| 455 |
+
type: "scattergl",
|
| 456 |
+
},
|
| 457 |
+
],
|
| 458 |
+
scattermapbox: [
|
| 459 |
+
{
|
| 460 |
+
marker: {
|
| 461 |
+
colorbar: {
|
| 462 |
+
outlinewidth: 0,
|
| 463 |
+
ticks: "",
|
| 464 |
+
},
|
| 465 |
+
},
|
| 466 |
+
type: "scattermapbox",
|
| 467 |
+
},
|
| 468 |
+
],
|
| 469 |
+
scatterpolargl: [
|
| 470 |
+
{
|
| 471 |
+
marker: {
|
| 472 |
+
colorbar: {
|
| 473 |
+
outlinewidth: 0,
|
| 474 |
+
ticks: "",
|
| 475 |
+
},
|
| 476 |
+
},
|
| 477 |
+
type: "scatterpolargl",
|
| 478 |
+
},
|
| 479 |
+
],
|
| 480 |
+
scatterpolar: [
|
| 481 |
+
{
|
| 482 |
+
marker: {
|
| 483 |
+
colorbar: {
|
| 484 |
+
outlinewidth: 0,
|
| 485 |
+
ticks: "",
|
| 486 |
+
},
|
| 487 |
+
},
|
| 488 |
+
type: "scatterpolar",
|
| 489 |
+
},
|
| 490 |
+
],
|
| 491 |
+
scatter: [
|
| 492 |
+
{
|
| 493 |
+
fillpattern: {
|
| 494 |
+
fillmode: "overlay",
|
| 495 |
+
size: 10,
|
| 496 |
+
solidity: 0.2,
|
| 497 |
+
},
|
| 498 |
+
type: "scatter",
|
| 499 |
+
},
|
| 500 |
+
],
|
| 501 |
+
scatterternary: [
|
| 502 |
+
{
|
| 503 |
+
marker: {
|
| 504 |
+
colorbar: {
|
| 505 |
+
outlinewidth: 0,
|
| 506 |
+
ticks: "",
|
| 507 |
+
},
|
| 508 |
+
},
|
| 509 |
+
type: "scatterternary",
|
| 510 |
+
},
|
| 511 |
+
],
|
| 512 |
+
surface: [
|
| 513 |
+
{
|
| 514 |
+
colorbar: {
|
| 515 |
+
outlinewidth: 0,
|
| 516 |
+
ticks: "",
|
| 517 |
+
},
|
| 518 |
+
colorscale: [
|
| 519 |
+
[0.0, "#0d0887"],
|
| 520 |
+
[0.1111111111111111, "#46039f"],
|
| 521 |
+
[0.2222222222222222, "#7201a8"],
|
| 522 |
+
[0.3333333333333333, "#9c179e"],
|
| 523 |
+
[0.4444444444444444, "#bd3786"],
|
| 524 |
+
[0.5555555555555556, "#d8576b"],
|
| 525 |
+
[0.6666666666666666, "#ed7953"],
|
| 526 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 527 |
+
[0.8888888888888888, "#fdca26"],
|
| 528 |
+
[1.0, "#f0f921"],
|
| 529 |
+
],
|
| 530 |
+
type: "surface",
|
| 531 |
+
},
|
| 532 |
+
],
|
| 533 |
+
table: [
|
| 534 |
+
{
|
| 535 |
+
cells: {
|
| 536 |
+
fill: {
|
| 537 |
+
color: "#EBF0F8",
|
| 538 |
+
},
|
| 539 |
+
line: {
|
| 540 |
+
color: "white",
|
| 541 |
+
},
|
| 542 |
+
},
|
| 543 |
+
header: {
|
| 544 |
+
fill: {
|
| 545 |
+
color: "#C8D4E3",
|
| 546 |
+
},
|
| 547 |
+
line: {
|
| 548 |
+
color: "white",
|
| 549 |
+
},
|
| 550 |
+
},
|
| 551 |
+
type: "table",
|
| 552 |
+
},
|
| 553 |
+
],
|
| 554 |
+
candlestick: [
|
| 555 |
+
{
|
| 556 |
+
"decreasing": {
|
| 557 |
+
"fillcolor": "#e4003a",
|
| 558 |
+
"line": {
|
| 559 |
+
"color": "#e4003a"
|
| 560 |
+
}
|
| 561 |
+
},
|
| 562 |
+
"increasing": {
|
| 563 |
+
"fillcolor": "#00ACFF",
|
| 564 |
+
"line": {
|
| 565 |
+
"color": "#00ACFF"
|
| 566 |
+
}
|
| 567 |
+
},
|
| 568 |
+
"type": "candlestick"
|
| 569 |
+
}
|
| 570 |
+
],
|
| 571 |
+
},
|
| 572 |
+
layout: {
|
| 573 |
+
annotationdefaults: {
|
| 574 |
+
arrowcolor: "#2a3f5f",
|
| 575 |
+
arrowhead: 0,
|
| 576 |
+
arrowwidth: 1,
|
| 577 |
+
showarrow: false,
|
| 578 |
+
},
|
| 579 |
+
autotypenumbers: "strict",
|
| 580 |
+
coloraxis: {
|
| 581 |
+
colorbar: {
|
| 582 |
+
outlinewidth: 0,
|
| 583 |
+
ticks: "",
|
| 584 |
+
},
|
| 585 |
+
},
|
| 586 |
+
colorscale: {
|
| 587 |
+
diverging: [
|
| 588 |
+
[0, "#8e0152"],
|
| 589 |
+
[0.1, "#c51b7d"],
|
| 590 |
+
[0.2, "#de77ae"],
|
| 591 |
+
[0.3, "#f1b6da"],
|
| 592 |
+
[0.4, "#fde0ef"],
|
| 593 |
+
[0.5, "#f7f7f7"],
|
| 594 |
+
[0.6, "#e6f5d0"],
|
| 595 |
+
[0.7, "#b8e186"],
|
| 596 |
+
[0.8, "#7fbc41"],
|
| 597 |
+
[0.9, "#4d9221"],
|
| 598 |
+
[1, "#276419"],
|
| 599 |
+
],
|
| 600 |
+
sequential: [
|
| 601 |
+
[0.0, "#0d0887"],
|
| 602 |
+
[0.1111111111111111, "#46039f"],
|
| 603 |
+
[0.2222222222222222, "#7201a8"],
|
| 604 |
+
[0.3333333333333333, "#9c179e"],
|
| 605 |
+
[0.4444444444444444, "#bd3786"],
|
| 606 |
+
[0.5555555555555556, "#d8576b"],
|
| 607 |
+
[0.6666666666666666, "#ed7953"],
|
| 608 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 609 |
+
[0.8888888888888888, "#fdca26"],
|
| 610 |
+
[1.0, "#f0f921"],
|
| 611 |
+
],
|
| 612 |
+
sequentialminus: [
|
| 613 |
+
[0.0, "#0d0887"],
|
| 614 |
+
[0.1111111111111111, "#46039f"],
|
| 615 |
+
[0.2222222222222222, "#7201a8"],
|
| 616 |
+
[0.3333333333333333, "#9c179e"],
|
| 617 |
+
[0.4444444444444444, "#bd3786"],
|
| 618 |
+
[0.5555555555555556, "#d8576b"],
|
| 619 |
+
[0.6666666666666666, "#ed7953"],
|
| 620 |
+
[0.7777777777777778, "#fb9f3a"],
|
| 621 |
+
[0.8888888888888888, "#fdca26"],
|
| 622 |
+
[1.0, "#f0f921"],
|
| 623 |
+
],
|
| 624 |
+
},
|
| 625 |
+
colorway: [
|
| 626 |
+
"#1f77b4",
|
| 627 |
+
"#ff7f0e",
|
| 628 |
+
"#2ca02c",
|
| 629 |
+
"#d62728",
|
| 630 |
+
"#9467bd",
|
| 631 |
+
"#8c564b",
|
| 632 |
+
"#e377c2",
|
| 633 |
+
"#bcbd22",
|
| 634 |
+
"#17becf",
|
| 635 |
+
"#aec7e8",
|
| 636 |
+
"#ffbb78",
|
| 637 |
+
"#ff9896",
|
| 638 |
+
"#c5b0d5",
|
| 639 |
+
"#f7b6d2",
|
| 640 |
+
"#dbdb8d",
|
| 641 |
+
"#9edae5"
|
| 642 |
+
],
|
| 643 |
+
font: {
|
| 644 |
+
family: "Arial, Helvetica, sans-serif",
|
| 645 |
+
size: 16,
|
| 646 |
+
},
|
| 647 |
+
geo: {
|
| 648 |
+
bgcolor: "white",
|
| 649 |
+
lakecolor: "white",
|
| 650 |
+
landcolor: "white",
|
| 651 |
+
showlakes: true,
|
| 652 |
+
showland: true,
|
| 653 |
+
subunitcolor: "#C8D4E3",
|
| 654 |
+
},
|
| 655 |
+
hoverlabel: {
|
| 656 |
+
align: "left",
|
| 657 |
+
font: {
|
| 658 |
+
family: "Arial, Helvetica, sans-serif",
|
| 659 |
+
size: 14,
|
| 660 |
+
},
|
| 661 |
+
},
|
| 662 |
+
hovermode: "x",
|
| 663 |
+
mapbox: {
|
| 664 |
+
style: "light",
|
| 665 |
+
},
|
| 666 |
+
paper_bgcolor: "#FFFFFF",
|
| 667 |
+
plot_bgcolor: "#FFFFFF",
|
| 668 |
+
polar: {
|
| 669 |
+
angularaxis: {
|
| 670 |
+
gridcolor: "#EBF0F8",
|
| 671 |
+
linecolor: "#EBF0F8",
|
| 672 |
+
ticks: "",
|
| 673 |
+
},
|
| 674 |
+
bgcolor: "white",
|
| 675 |
+
radialaxis: {
|
| 676 |
+
gridcolor: "#EBF0F8",
|
| 677 |
+
linecolor: "#EBF0F8",
|
| 678 |
+
ticks: "",
|
| 679 |
+
},
|
| 680 |
+
},
|
| 681 |
+
scene: {
|
| 682 |
+
xaxis: {
|
| 683 |
+
backgroundcolor: "white",
|
| 684 |
+
gridcolor: "#DFE8F3",
|
| 685 |
+
gridwidth: 2,
|
| 686 |
+
linecolor: "#EBF0F8",
|
| 687 |
+
showbackground: true,
|
| 688 |
+
ticks: "",
|
| 689 |
+
zerolinecolor: "#EBF0F8",
|
| 690 |
+
},
|
| 691 |
+
yaxis: {
|
| 692 |
+
backgroundcolor: "white",
|
| 693 |
+
gridcolor: "#DFE8F3",
|
| 694 |
+
gridwidth: 2,
|
| 695 |
+
linecolor: "#EBF0F8",
|
| 696 |
+
showbackground: true,
|
| 697 |
+
ticks: "",
|
| 698 |
+
zerolinecolor: "#EBF0F8",
|
| 699 |
+
},
|
| 700 |
+
zaxis: {
|
| 701 |
+
backgroundcolor: "white",
|
| 702 |
+
gridcolor: "#DFE8F3",
|
| 703 |
+
gridwidth: 2,
|
| 704 |
+
linecolor: "#EBF0F8",
|
| 705 |
+
showbackground: true,
|
| 706 |
+
ticks: "",
|
| 707 |
+
zerolinecolor: "#EBF0F8",
|
| 708 |
+
},
|
| 709 |
+
},
|
| 710 |
+
shapedefaults: {
|
| 711 |
+
line: {
|
| 712 |
+
color: "#2a3f5f",
|
| 713 |
+
},
|
| 714 |
+
},
|
| 715 |
+
ternary: {
|
| 716 |
+
aaxis: {
|
| 717 |
+
gridcolor: "#DFE8F3",
|
| 718 |
+
linecolor: "#A2B1C6",
|
| 719 |
+
ticks: "",
|
| 720 |
+
},
|
| 721 |
+
baxis: {
|
| 722 |
+
gridcolor: "#DFE8F3",
|
| 723 |
+
linecolor: "#A2B1C6",
|
| 724 |
+
ticks: "",
|
| 725 |
+
},
|
| 726 |
+
bgcolor: "white",
|
| 727 |
+
caxis: {
|
| 728 |
+
gridcolor: "#DFE8F3",
|
| 729 |
+
linecolor: "#A2B1C6",
|
| 730 |
+
ticks: "",
|
| 731 |
+
},
|
| 732 |
+
},
|
| 733 |
+
title: {
|
| 734 |
+
x: 0.05,
|
| 735 |
+
},
|
| 736 |
+
xaxis: {
|
| 737 |
+
automargin: true,
|
| 738 |
+
autorange: true,
|
| 739 |
+
rangeslider: {
|
| 740 |
+
visible: false
|
| 741 |
+
},
|
| 742 |
+
showgrid: true,
|
| 743 |
+
showline: true,
|
| 744 |
+
tickfont: {
|
| 745 |
+
family: "Arial, Helvetica, sans-serif",
|
| 746 |
+
size: 14,
|
| 747 |
+
},
|
| 748 |
+
zeroline: false,
|
| 749 |
+
tick0: 1,
|
| 750 |
+
title: {
|
| 751 |
+
standoff: 20,
|
| 752 |
+
font: {
|
| 753 |
+
family: "Arial, Helvetica, sans-serif",
|
| 754 |
+
size: 16,
|
| 755 |
+
},
|
| 756 |
+
},
|
| 757 |
+
gridcolor: "#283442",
|
| 758 |
+
linecolor: "#A9A9A9",
|
| 759 |
+
mirror: true,
|
| 760 |
+
ticks: "outside"
|
| 761 |
+
},
|
| 762 |
+
yaxis: {
|
| 763 |
+
anchor: "x",
|
| 764 |
+
automargin: true,
|
| 765 |
+
fixedrange: false,
|
| 766 |
+
zeroline: false,
|
| 767 |
+
showgrid: true,
|
| 768 |
+
showline: true,
|
| 769 |
+
side: "right",
|
| 770 |
+
tick0: 0.5,
|
| 771 |
+
tickfont: {
|
| 772 |
+
family: "Arial, Helvetica, sans-serif",
|
| 773 |
+
size: 14,
|
| 774 |
+
},
|
| 775 |
+
title: {
|
| 776 |
+
standoff: 20,
|
| 777 |
+
font: {
|
| 778 |
+
family: "Arial, Helvetica, sans-serif",
|
| 779 |
+
size: 16,
|
| 780 |
+
},
|
| 781 |
+
},
|
| 782 |
+
gridcolor: "rgba(128, 128, 128, 0.33)",
|
| 783 |
+
linecolor: "#A9A9A9",
|
| 784 |
+
mirror: true,
|
| 785 |
+
ticks: "outside"
|
| 786 |
+
},
|
| 787 |
+
dragmode: "pan",
|
| 788 |
+
legend: {
|
| 789 |
+
bgcolor: "rgba(255, 255, 255, 0)",
|
| 790 |
+
x: 1,
|
| 791 |
+
xanchor: "right",
|
| 792 |
+
y: 1.02,
|
| 793 |
+
yanchor: "bottom",
|
| 794 |
+
font: {
|
| 795 |
+
family: "Arial, Helvetica, sans-serif",
|
| 796 |
+
size: 14,
|
| 797 |
+
},
|
| 798 |
+
},
|
| 799 |
+
},
|
| 800 |
+
};
|
frontend-components/plotly/src/components/Dialogs/AlertDialog.tsx
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import CommonDialog from "../Dialogs/CommonDialog";
|
| 2 |
+
|
| 3 |
+
export default function AlertDialog({
|
| 4 |
+
title,
|
| 5 |
+
content,
|
| 6 |
+
open,
|
| 7 |
+
close,
|
| 8 |
+
}: {
|
| 9 |
+
title: string;
|
| 10 |
+
content: string;
|
| 11 |
+
open: boolean;
|
| 12 |
+
close: () => void;
|
| 13 |
+
}) {
|
| 14 |
+
return (
|
| 15 |
+
<CommonDialog title={title} description="" open={open} close={close}>
|
| 16 |
+
<div
|
| 17 |
+
id="popup_title"
|
| 18 |
+
className="popup_content"
|
| 19 |
+
style={{ padding: "0px 2px 2px 5px", marginTop: 5 }}
|
| 20 |
+
>
|
| 21 |
+
<div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
|
| 22 |
+
<div>
|
| 23 |
+
<label htmlFor="title_text">{content}</label>
|
| 24 |
+
</div>
|
| 25 |
+
</div>
|
| 26 |
+
<div style={{ float: "right", marginTop: 20 }}>
|
| 27 |
+
<button
|
| 28 |
+
type="button"
|
| 29 |
+
className="_btn"
|
| 30 |
+
style={{
|
| 31 |
+
padding: "8px 16px",
|
| 32 |
+
width: "100%",
|
| 33 |
+
}}
|
| 34 |
+
onClick={close}
|
| 35 |
+
>
|
| 36 |
+
Close
|
| 37 |
+
</button>
|
| 38 |
+
</div>
|
| 39 |
+
</div>
|
| 40 |
+
</CommonDialog>
|
| 41 |
+
);
|
| 42 |
+
}
|
frontend-components/plotly/src/components/Dialogs/CommonDialog.tsx
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
| 2 |
+
import CloseIcon from "../Icons/Close";
|
| 3 |
+
import { ReactNode } from "react";
|
| 4 |
+
|
| 5 |
+
export const styleDialog = {
|
| 6 |
+
margin: "2px 0px 2px 10px",
|
| 7 |
+
padding: "5px 2px 2px 5px",
|
| 8 |
+
};
|
| 9 |
+
|
| 10 |
+
export default function CommonDialog({
|
| 11 |
+
open,
|
| 12 |
+
close,
|
| 13 |
+
title,
|
| 14 |
+
description,
|
| 15 |
+
children,
|
| 16 |
+
}: {
|
| 17 |
+
open: boolean;
|
| 18 |
+
close: () => void;
|
| 19 |
+
title: string;
|
| 20 |
+
description: string;
|
| 21 |
+
children: ReactNode;
|
| 22 |
+
}) {
|
| 23 |
+
return (
|
| 24 |
+
<DialogPrimitive.Root open={open} onOpenChange={close}>
|
| 25 |
+
<DialogPrimitive.Overlay onClick={close} className="_modal-overlay" />
|
| 26 |
+
<DialogPrimitive.Content className="_modal">
|
| 27 |
+
<DialogPrimitive.Title className="_modal-title">
|
| 28 |
+
{title}
|
| 29 |
+
</DialogPrimitive.Title>
|
| 30 |
+
<DialogPrimitive.Description className="_modal_description">
|
| 31 |
+
{description}
|
| 32 |
+
</DialogPrimitive.Description>
|
| 33 |
+
<DialogPrimitive.Close>
|
| 34 |
+
<CloseIcon />
|
| 35 |
+
</DialogPrimitive.Close>
|
| 36 |
+
{children}
|
| 37 |
+
<DialogPrimitive.Close className="_modal-close" onClick={close}>
|
| 38 |
+
<CloseIcon className="w-6 h-6" />
|
| 39 |
+
</DialogPrimitive.Close>
|
| 40 |
+
</DialogPrimitive.Content>
|
| 41 |
+
</DialogPrimitive.Root>
|
| 42 |
+
);
|
| 43 |
+
}
|
frontend-components/plotly/src/components/Dialogs/OverlayChartDialog.tsx
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { useState } from "react";
|
| 2 |
+
import CommonDialog, { styleDialog } from "../Dialogs/CommonDialog";
|
| 3 |
+
|
| 4 |
+
const reader = new FileReader();
|
| 5 |
+
|
| 6 |
+
const layout_defaults = {
|
| 7 |
+
overlaying: "y",
|
| 8 |
+
side: "left",
|
| 9 |
+
tickfont: { size: 12 },
|
| 10 |
+
tickpadding: 5,
|
| 11 |
+
showgrid: false,
|
| 12 |
+
showline: false,
|
| 13 |
+
showticklabels: true,
|
| 14 |
+
showlegend: true,
|
| 15 |
+
zeroline: false,
|
| 16 |
+
anchor: "x",
|
| 17 |
+
type: "linear",
|
| 18 |
+
autorange: true,
|
| 19 |
+
};
|
| 20 |
+
|
| 21 |
+
export default function OverlayChartDialog({
|
| 22 |
+
open,
|
| 23 |
+
close,
|
| 24 |
+
setLoading,
|
| 25 |
+
addOverlay,
|
| 26 |
+
plotlyData,
|
| 27 |
+
}: {
|
| 28 |
+
open: boolean;
|
| 29 |
+
close: () => void;
|
| 30 |
+
setLoading: (loading: boolean) => void;
|
| 31 |
+
addOverlay: (data: any) => void;
|
| 32 |
+
plotlyData: any;
|
| 33 |
+
}) {
|
| 34 |
+
const [traceType, setTraceType] = useState("scatter");
|
| 35 |
+
const [traceColor, setTraceColor] = useState("#FFDD00");
|
| 36 |
+
const [increasingColor, setIncreasingColor] = useState("#00ACFF");
|
| 37 |
+
const [decreasingColor, setDecreasingColor] = useState("#FF0000");
|
| 38 |
+
const [traceName, setTraceName] = useState("");
|
| 39 |
+
const [csvData, setCsvData] = useState<any[]>([]);
|
| 40 |
+
const [csvColumns, setCsvColumns] = useState<string[]>([]);
|
| 41 |
+
const [yaxisOptions, setYaxisOptions] = useState<any>({});
|
| 42 |
+
const optionIds = ["x", "open", "high", "low", "close"];
|
| 43 |
+
|
| 44 |
+
const traceTypes: any = {
|
| 45 |
+
scatter: "Scatter (Line)",
|
| 46 |
+
candlestick: "Candlestick",
|
| 47 |
+
bar: "Bar",
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
const [options, setOptions] = useState<any>({});
|
| 51 |
+
|
| 52 |
+
function onClose() {
|
| 53 |
+
close();
|
| 54 |
+
setTraceType("scatter");
|
| 55 |
+
setTraceName("");
|
| 56 |
+
setCsvData([]);
|
| 57 |
+
setCsvColumns([]);
|
| 58 |
+
setOptions({});
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
function onSubmit() {
|
| 62 |
+
if (csvData.length === 0) {
|
| 63 |
+
document.getElementById("csv_file")?.focus();
|
| 64 |
+
document
|
| 65 |
+
.getElementById("csv_file")
|
| 66 |
+
?.style.setProperty("border", "1px solid red");
|
| 67 |
+
document.getElementById("csv_file_warning")!.style.display = "block";
|
| 68 |
+
return;
|
| 69 |
+
}
|
| 70 |
+
const newPlotydata = CSVonSubmit({
|
| 71 |
+
csvData: csvData,
|
| 72 |
+
plotlyData: plotlyData,
|
| 73 |
+
yaxisOptions: yaxisOptions,
|
| 74 |
+
traceType: traceType,
|
| 75 |
+
traceColor: traceColor,
|
| 76 |
+
traceName: traceName,
|
| 77 |
+
options: options,
|
| 78 |
+
increasingColor: increasingColor,
|
| 79 |
+
decreasingColor: decreasingColor,
|
| 80 |
+
});
|
| 81 |
+
addOverlay(newPlotydata);
|
| 82 |
+
onClose();
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
return (
|
| 86 |
+
<CommonDialog
|
| 87 |
+
title="Overlay Chart"
|
| 88 |
+
description="Upload a CSV file to overlay a chart on the main chart."
|
| 89 |
+
open={open}
|
| 90 |
+
close={close}
|
| 91 |
+
>
|
| 92 |
+
<div id="popup_csv" className="popup_content">
|
| 93 |
+
<div>
|
| 94 |
+
<label htmlFor="csv_file">
|
| 95 |
+
<b>CSV file:</b>
|
| 96 |
+
<div
|
| 97 |
+
id="csv_file_warning"
|
| 98 |
+
className="popup_warning"
|
| 99 |
+
style={{ marginLeft: "80px", marginBottom: "10px" }}
|
| 100 |
+
>
|
| 101 |
+
CSV file is required.
|
| 102 |
+
</div>
|
| 103 |
+
</label>
|
| 104 |
+
<input
|
| 105 |
+
onChange={(e) => {
|
| 106 |
+
if (!e.target.files) {
|
| 107 |
+
return;
|
| 108 |
+
} else if (e.target.files[0].type !== "text/csv") {
|
| 109 |
+
document.getElementById("csv_file")?.focus();
|
| 110 |
+
document
|
| 111 |
+
.getElementById("csv_file")
|
| 112 |
+
?.style.setProperty("border", "1px solid red");
|
| 113 |
+
document.getElementById("csv_file_warning")!.style.display =
|
| 114 |
+
"block";
|
| 115 |
+
return;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
if (csvColumns.length > 0) {
|
| 119 |
+
setCsvColumns([]);
|
| 120 |
+
setOptions({});
|
| 121 |
+
setTraceType("scatter");
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
reader.onload = (filebytes) => {
|
| 125 |
+
if (
|
| 126 |
+
!filebytes.target?.result ||
|
| 127 |
+
typeof filebytes.target.result !== "string"
|
| 128 |
+
) {
|
| 129 |
+
return;
|
| 130 |
+
}
|
| 131 |
+
const lines = filebytes.target.result
|
| 132 |
+
.split("\n")
|
| 133 |
+
.map((x) => x.replace(/\r/g, ""));
|
| 134 |
+
|
| 135 |
+
const headers = lines[0].split(",");
|
| 136 |
+
const headers_lower = headers.map((x) =>
|
| 137 |
+
x.trim().toLowerCase(),
|
| 138 |
+
);
|
| 139 |
+
|
| 140 |
+
const updateOptions: { [key: string]: any } = {};
|
| 141 |
+
|
| 142 |
+
if (headers.length > 1) {
|
| 143 |
+
updateOptions.x = headers[0];
|
| 144 |
+
updateOptions.y = headers[1];
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
for (let i = 0; i < optionIds.length; i++) {
|
| 148 |
+
if (headers_lower.includes(optionIds[i])) {
|
| 149 |
+
updateOptions[optionIds[i]] =
|
| 150 |
+
headers[headers_lower.indexOf(optionIds[i])];
|
| 151 |
+
} else if (
|
| 152 |
+
optionIds[i] === "x" &&
|
| 153 |
+
headers_lower.includes("date")
|
| 154 |
+
) {
|
| 155 |
+
updateOptions[optionIds[i]] =
|
| 156 |
+
headers[headers_lower.indexOf("date")];
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
const candle_cols = ["open", "high", "low", "close"];
|
| 161 |
+
const candle_cols_present = candle_cols.every((x) =>
|
| 162 |
+
headers_lower.includes(x),
|
| 163 |
+
);
|
| 164 |
+
if (candle_cols_present) {
|
| 165 |
+
setTraceType("candlestick");
|
| 166 |
+
} else if (headers_lower.length >= 5) {
|
| 167 |
+
candle_cols.forEach((x) => {
|
| 168 |
+
updateOptions[x] = headers[candle_cols.indexOf(x) + 1];
|
| 169 |
+
});
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
if (headers_lower.includes("close")) {
|
| 173 |
+
setOptions({
|
| 174 |
+
...options,
|
| 175 |
+
y: headers[headers_lower.indexOf("close")],
|
| 176 |
+
});
|
| 177 |
+
updateOptions.y = headers[headers_lower.indexOf("close")];
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
const data = [];
|
| 181 |
+
|
| 182 |
+
for (let i = 1; i < lines.length; i++) {
|
| 183 |
+
const obj = {};
|
| 184 |
+
const currentline = lines[i].split(",");
|
| 185 |
+
for (let j = 0; j < headers.length; j++) {
|
| 186 |
+
//@ts-ignore
|
| 187 |
+
obj[headers[j]] = currentline[j];
|
| 188 |
+
}
|
| 189 |
+
data.push(obj);
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
//@ts-ignore
|
| 193 |
+
let filename = e.target.files[0].name.split(".")[0];
|
| 194 |
+
|
| 195 |
+
try {
|
| 196 |
+
if (filename.includes("_")) {
|
| 197 |
+
const name_parts = filename
|
| 198 |
+
.replace(/_{2,}/g, "_")
|
| 199 |
+
.split("_");
|
| 200 |
+
const date_regex = new RegExp("^[0-9]{8}$");
|
| 201 |
+
|
| 202 |
+
if (name_parts.length > 2) {
|
| 203 |
+
// we check if the first 2 parts are date and time
|
| 204 |
+
if (date_regex.test(name_parts[0])) {
|
| 205 |
+
name_parts.splice(0, 2);
|
| 206 |
+
}
|
| 207 |
+
// we check if the last 2 parts are date and time
|
| 208 |
+
else if (
|
| 209 |
+
date_regex.test(name_parts[name_parts.length - 2])
|
| 210 |
+
) {
|
| 211 |
+
name_parts.splice(name_parts.length - 2, 2);
|
| 212 |
+
}
|
| 213 |
+
filename = name_parts.join("_").replace(/openbb_/g, "");
|
| 214 |
+
}
|
| 215 |
+
}
|
| 216 |
+
} catch (e) {
|
| 217 |
+
console.log(e);
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
setTraceName(filename);
|
| 221 |
+
setOptions(updateOptions);
|
| 222 |
+
setCsvColumns(headers);
|
| 223 |
+
setCsvData(data);
|
| 224 |
+
};
|
| 225 |
+
reader.readAsText(e.target.files[0]);
|
| 226 |
+
}}
|
| 227 |
+
type="file"
|
| 228 |
+
id="csv_file"
|
| 229 |
+
accept=".csv"
|
| 230 |
+
style={{ marginLeft: 10 }}
|
| 231 |
+
/>
|
| 232 |
+
</div>
|
| 233 |
+
<div style={{ marginTop: 15 }}>
|
| 234 |
+
<label htmlFor="csv_trace_type">
|
| 235 |
+
<b>Display data type:</b>
|
| 236 |
+
</label>
|
| 237 |
+
<select
|
| 238 |
+
onChange={(e) => {
|
| 239 |
+
setTraceType(e.target.value);
|
| 240 |
+
}}
|
| 241 |
+
id="csv_trace_type"
|
| 242 |
+
style={styleDialog}
|
| 243 |
+
defaultValue={traceTypes[traceType]}
|
| 244 |
+
>
|
| 245 |
+
{traceType && (
|
| 246 |
+
<option key={traceType} value={traceType}>
|
| 247 |
+
{traceTypes[traceType]}
|
| 248 |
+
</option>
|
| 249 |
+
)}
|
| 250 |
+
{Object.keys(traceTypes).map(
|
| 251 |
+
(x) =>
|
| 252 |
+
traceType !== x && (
|
| 253 |
+
<option key={x} value={x}>
|
| 254 |
+
{traceTypes[x]}
|
| 255 |
+
</option>
|
| 256 |
+
),
|
| 257 |
+
)}
|
| 258 |
+
</select>
|
| 259 |
+
</div>
|
| 260 |
+
<div style={{ marginTop: 12 }}>
|
| 261 |
+
<label htmlFor="csv_name">
|
| 262 |
+
<b>Trace Name:</b>
|
| 263 |
+
</label>
|
| 264 |
+
<textarea
|
| 265 |
+
id="csv_name"
|
| 266 |
+
value={traceName}
|
| 267 |
+
onChange={(e) => {
|
| 268 |
+
setTraceName(e.target.value);
|
| 269 |
+
}}
|
| 270 |
+
style={{
|
| 271 |
+
padding: "5px 2px 2px 5px",
|
| 272 |
+
width: "100%",
|
| 273 |
+
maxWidth: "100%",
|
| 274 |
+
maxHeight: 200,
|
| 275 |
+
marginTop: 2,
|
| 276 |
+
}}
|
| 277 |
+
rows={2}
|
| 278 |
+
cols={20}
|
| 279 |
+
placeholder="Enter a name to give this trace"
|
| 280 |
+
/>
|
| 281 |
+
</div>
|
| 282 |
+
{csvColumns.length > 0 && (
|
| 283 |
+
<>
|
| 284 |
+
{["scatter", "bar"].includes(traceType) && (
|
| 285 |
+
<div
|
| 286 |
+
style={{ marginTop: 15, marginBottom: 10 }}
|
| 287 |
+
id="csv_columns"
|
| 288 |
+
className="csv_column_container"
|
| 289 |
+
>
|
| 290 |
+
{["x", "y"].map((key) => (
|
| 291 |
+
<div
|
| 292 |
+
key={key}
|
| 293 |
+
style={{
|
| 294 |
+
marginTop: 10,
|
| 295 |
+
display: "flex",
|
| 296 |
+
alignItems: "center",
|
| 297 |
+
justifyContent: "space-between",
|
| 298 |
+
}}
|
| 299 |
+
>
|
| 300 |
+
<label htmlFor={`csv_${key}`} style={{ width: "100px" }}>
|
| 301 |
+
{key.toUpperCase()} Axis
|
| 302 |
+
</label>
|
| 303 |
+
<select
|
| 304 |
+
onChange={(e) => {
|
| 305 |
+
setOptions({
|
| 306 |
+
...options,
|
| 307 |
+
[key]: e.target.value,
|
| 308 |
+
});
|
| 309 |
+
}}
|
| 310 |
+
id={`csv_${key}`}
|
| 311 |
+
style={{ width: "100%" }}
|
| 312 |
+
defaultValue={options[key]}
|
| 313 |
+
>
|
| 314 |
+
{csvColumns.map((column) => (
|
| 315 |
+
<option key={column} value={column}>
|
| 316 |
+
{column}
|
| 317 |
+
</option>
|
| 318 |
+
))}
|
| 319 |
+
</select>
|
| 320 |
+
</div>
|
| 321 |
+
))}
|
| 322 |
+
</div>
|
| 323 |
+
)}
|
| 324 |
+
{traceType === "candlestick" && (
|
| 325 |
+
<div
|
| 326 |
+
id="csv_columns"
|
| 327 |
+
className="csv_column_container"
|
| 328 |
+
style={{ marginTop: 15 }}
|
| 329 |
+
>
|
| 330 |
+
{["x", "open", "high", "low", "close"].map((key) => (
|
| 331 |
+
<div
|
| 332 |
+
key={key}
|
| 333 |
+
style={{
|
| 334 |
+
marginTop: 10,
|
| 335 |
+
display: "flex",
|
| 336 |
+
alignItems: "center",
|
| 337 |
+
justifyContent: "space-between",
|
| 338 |
+
}}
|
| 339 |
+
>
|
| 340 |
+
<label htmlFor={`csv_${key}`} style={{ width: "100px" }}>
|
| 341 |
+
{key.charAt(0).toUpperCase() + key.slice(1)}
|
| 342 |
+
</label>
|
| 343 |
+
<select
|
| 344 |
+
onChange={(e) => {
|
| 345 |
+
setOptions({
|
| 346 |
+
...options,
|
| 347 |
+
[key]: e.target.value,
|
| 348 |
+
});
|
| 349 |
+
}}
|
| 350 |
+
id={`csv_${key}`}
|
| 351 |
+
style={{ width: "100%" }}
|
| 352 |
+
defaultValue={options[key]}
|
| 353 |
+
>
|
| 354 |
+
{csvColumns.map((column) => (
|
| 355 |
+
<option key={column} value={column}>
|
| 356 |
+
{column}
|
| 357 |
+
</option>
|
| 358 |
+
))}
|
| 359 |
+
</select>
|
| 360 |
+
</div>
|
| 361 |
+
))}
|
| 362 |
+
</div>
|
| 363 |
+
)}
|
| 364 |
+
<div style={{ marginTop: 20 }} id="csv_colors">
|
| 365 |
+
{["scatter", "bar"].includes(traceType) && (
|
| 366 |
+
<div>
|
| 367 |
+
<label htmlFor="csv_color">{`${traceType
|
| 368 |
+
.charAt(0)
|
| 369 |
+
.toUpperCase()}${traceType.slice(1)} color`}</label>
|
| 370 |
+
<input
|
| 371 |
+
type="color"
|
| 372 |
+
id="csv_color"
|
| 373 |
+
defaultValue="#FFDD00"
|
| 374 |
+
style={{ margin: "2px 2px 2px 10px" }}
|
| 375 |
+
onChange={(e) => {
|
| 376 |
+
console.log(e.target.value);
|
| 377 |
+
setTraceColor(e.target.value);
|
| 378 |
+
}}
|
| 379 |
+
/>
|
| 380 |
+
</div>
|
| 381 |
+
)}
|
| 382 |
+
{traceType === "candlestick" && (
|
| 383 |
+
<>
|
| 384 |
+
<label htmlFor="csv_increasing">Increasing color</label>
|
| 385 |
+
<input
|
| 386 |
+
type="color"
|
| 387 |
+
id="csv_increasing"
|
| 388 |
+
defaultValue="#00ACFF"
|
| 389 |
+
style={{ margin: "2px 0px 2px 10px" }}
|
| 390 |
+
onChange={(e) => {
|
| 391 |
+
setIncreasingColor(e.target.value);
|
| 392 |
+
}}
|
| 393 |
+
/>
|
| 394 |
+
<label htmlFor="csv_decreasing" style={{ marginLeft: 15 }}>
|
| 395 |
+
Decreasing color
|
| 396 |
+
</label>
|
| 397 |
+
<input
|
| 398 |
+
style={{ margin: "2px 0px 2px 10px" }}
|
| 399 |
+
type="color"
|
| 400 |
+
id="csv_decreasing"
|
| 401 |
+
defaultValue="#FF0000"
|
| 402 |
+
onChange={(e) => {
|
| 403 |
+
setDecreasingColor(e.target.value);
|
| 404 |
+
}}
|
| 405 |
+
/>
|
| 406 |
+
</>
|
| 407 |
+
)}
|
| 408 |
+
</div>
|
| 409 |
+
<div style={{ marginTop: 20 }} id="csv_plot_yaxis_options">
|
| 410 |
+
{traceType !== "candlestick" && (
|
| 411 |
+
<>
|
| 412 |
+
<input
|
| 413 |
+
type="checkbox"
|
| 414 |
+
id="csv_percent_change"
|
| 415 |
+
name="csv_plot_yaxis_check"
|
| 416 |
+
style={{ marginBottom: 2 }}
|
| 417 |
+
onChange={(e) => {
|
| 418 |
+
setYaxisOptions({
|
| 419 |
+
...yaxisOptions,
|
| 420 |
+
percentChange: e.target.checked,
|
| 421 |
+
sameYaxis: false,
|
| 422 |
+
});
|
| 423 |
+
}}
|
| 424 |
+
checked={
|
| 425 |
+
!yaxisOptions.sameYaxis && yaxisOptions.percentChange
|
| 426 |
+
}
|
| 427 |
+
/>
|
| 428 |
+
<label htmlFor="csv_percent_change" style={{ marginLeft: 5 }}>
|
| 429 |
+
Plot as percent change from first value
|
| 430 |
+
</label>
|
| 431 |
+
<br />
|
| 432 |
+
</>
|
| 433 |
+
)}
|
| 434 |
+
<input
|
| 435 |
+
style={{ marginTop: 2 }}
|
| 436 |
+
type="checkbox"
|
| 437 |
+
id="csv_same_yaxis"
|
| 438 |
+
name="csv_plot_yaxis_check"
|
| 439 |
+
onChange={(e) => {
|
| 440 |
+
setYaxisOptions({
|
| 441 |
+
...yaxisOptions,
|
| 442 |
+
sameYaxis: e.target.checked,
|
| 443 |
+
percentChange: false,
|
| 444 |
+
});
|
| 445 |
+
}}
|
| 446 |
+
checked={!yaxisOptions.percentChange && yaxisOptions.sameYaxis}
|
| 447 |
+
/>
|
| 448 |
+
<label htmlFor="csv_same_yaxis" style={{ marginLeft: 5 }}>
|
| 449 |
+
Share Y-axis
|
| 450 |
+
</label>
|
| 451 |
+
|
| 452 |
+
{traceType === "bar" && (
|
| 453 |
+
<div style={{ marginTop: 2 }} id="csv_bar_orientation">
|
| 454 |
+
<input
|
| 455 |
+
type="checkbox"
|
| 456 |
+
id="csv_bar_horizontal"
|
| 457 |
+
onChange={(e) => {
|
| 458 |
+
setOptions({
|
| 459 |
+
...options,
|
| 460 |
+
orientation: e.target.checked ? "h" : "v",
|
| 461 |
+
});
|
| 462 |
+
}}
|
| 463 |
+
/>
|
| 464 |
+
<label htmlFor="csv_bar_horizontal" style={{ marginLeft: 5 }}>
|
| 465 |
+
Plot horizontally
|
| 466 |
+
</label>
|
| 467 |
+
</div>
|
| 468 |
+
)}
|
| 469 |
+
</div>
|
| 470 |
+
</>
|
| 471 |
+
)}
|
| 472 |
+
|
| 473 |
+
<br />
|
| 474 |
+
<div style={{ float: "right", marginTop: 20 }}>
|
| 475 |
+
<button className="_btn-tertiary" id="csv_cancel" onClick={onClose}>
|
| 476 |
+
Cancel
|
| 477 |
+
</button>
|
| 478 |
+
<button className="_btn" id="csv_submit" onClick={onSubmit}>
|
| 479 |
+
Submit
|
| 480 |
+
</button>
|
| 481 |
+
</div>
|
| 482 |
+
</div>
|
| 483 |
+
</CommonDialog>
|
| 484 |
+
);
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
export function CSVonSubmit({
|
| 488 |
+
csvData,
|
| 489 |
+
plotlyData,
|
| 490 |
+
yaxisOptions,
|
| 491 |
+
traceType,
|
| 492 |
+
traceColor,
|
| 493 |
+
traceName,
|
| 494 |
+
options,
|
| 495 |
+
increasingColor,
|
| 496 |
+
decreasingColor,
|
| 497 |
+
}: {
|
| 498 |
+
csvData: any[];
|
| 499 |
+
plotlyData: any;
|
| 500 |
+
yaxisOptions: any;
|
| 501 |
+
traceType: string;
|
| 502 |
+
traceColor: string;
|
| 503 |
+
traceName: string;
|
| 504 |
+
options: any;
|
| 505 |
+
increasingColor: string;
|
| 506 |
+
decreasingColor: string;
|
| 507 |
+
}) {
|
| 508 |
+
console.log("options", options);
|
| 509 |
+
const main_trace = plotlyData.data[0] || {};
|
| 510 |
+
if (main_trace.xaxis === undefined) {
|
| 511 |
+
main_trace.xaxis = "x";
|
| 512 |
+
}
|
| 513 |
+
if (main_trace.yaxis === undefined) {
|
| 514 |
+
main_trace.yaxis = "y";
|
| 515 |
+
}
|
| 516 |
+
let yaxis_id = main_trace.yaxis;
|
| 517 |
+
let yaxis: string;
|
| 518 |
+
|
| 519 |
+
const left_yaxis_ticks = Object.keys(plotlyData.layout)
|
| 520 |
+
.filter((k) => k.startsWith("yaxis"))
|
| 521 |
+
.map((k) => plotlyData.layout[k])
|
| 522 |
+
.filter(
|
| 523 |
+
(yaxis) =>
|
| 524 |
+
yaxis.side === "left" &&
|
| 525 |
+
(yaxis.overlaying === "y" ||
|
| 526 |
+
(yaxis.fixedrange !== undefined && yaxis.fixedrange === true)),
|
| 527 |
+
).length;
|
| 528 |
+
|
| 529 |
+
const ticksuffix = left_yaxis_ticks > 0 ? " " : "";
|
| 530 |
+
|
| 531 |
+
if (yaxisOptions.sameYaxis !== true) {
|
| 532 |
+
const yaxes = Object.keys(plotlyData.layout)
|
| 533 |
+
.filter((k) => k.startsWith("yaxis"))
|
| 534 |
+
.map((k) => plotlyData.layout[k]);
|
| 535 |
+
|
| 536 |
+
yaxis = `y${yaxes.length + 1}`;
|
| 537 |
+
yaxis_id = `yaxis${yaxes.length + 1}`;
|
| 538 |
+
plotlyData.layout[yaxis_id] = {
|
| 539 |
+
...layout_defaults,
|
| 540 |
+
title: {
|
| 541 |
+
text: traceName,
|
| 542 |
+
font: {
|
| 543 |
+
size: 14,
|
| 544 |
+
},
|
| 545 |
+
standoff: 0,
|
| 546 |
+
},
|
| 547 |
+
ticksuffix: ticksuffix,
|
| 548 |
+
layer: "below traces",
|
| 549 |
+
};
|
| 550 |
+
} else {
|
| 551 |
+
// Plot on the same yaxis
|
| 552 |
+
yaxis = main_trace.yaxis.replace("yaxis", "y");
|
| 553 |
+
}
|
| 554 |
+
|
| 555 |
+
const traceBase: any = {
|
| 556 |
+
type: traceType,
|
| 557 |
+
name: traceName,
|
| 558 |
+
showlegend: true,
|
| 559 |
+
yaxis: yaxis,
|
| 560 |
+
};
|
| 561 |
+
|
| 562 |
+
let trace: any = {};
|
| 563 |
+
|
| 564 |
+
if (["scatter", "bar"].includes(traceType)) {
|
| 565 |
+
if (!csvData || csvData.length === 0) return plotlyData;
|
| 566 |
+
const non_null = csvData.findIndex(
|
| 567 |
+
(x: any) => x[options.y] !== null && x[options.y] !== 0,
|
| 568 |
+
);
|
| 569 |
+
|
| 570 |
+
if (non_null === -1) {
|
| 571 |
+
return plotlyData;
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
const scatter_data: { [key: string]: any[] } = {
|
| 575 |
+
x: [],
|
| 576 |
+
y: [],
|
| 577 |
+
customdata: [],
|
| 578 |
+
};
|
| 579 |
+
|
| 580 |
+
csvData.forEach((row: any) => {
|
| 581 |
+
let y = row[options.y];
|
| 582 |
+
scatter_data.customdata.push(y);
|
| 583 |
+
if (
|
| 584 |
+
yaxisOptions.percentChange &&
|
| 585 |
+
(traceType === "scatter" || traceType === "line")
|
| 586 |
+
) {
|
| 587 |
+
y =
|
| 588 |
+
(row[options.y] - csvData[non_null][options.y]) /
|
| 589 |
+
csvData[non_null][options.y];
|
| 590 |
+
}
|
| 591 |
+
scatter_data.x.push(row[options.x]);
|
| 592 |
+
scatter_data.y.push(y);
|
| 593 |
+
});
|
| 594 |
+
|
| 595 |
+
trace = {
|
| 596 |
+
...traceBase,
|
| 597 |
+
x: scatter_data.x,
|
| 598 |
+
y: scatter_data.y,
|
| 599 |
+
customdata: scatter_data.customdata,
|
| 600 |
+
hovertemplate: "%{customdata:.2f}",
|
| 601 |
+
connectgaps: true,
|
| 602 |
+
marker: { color: traceColor },
|
| 603 |
+
};
|
| 604 |
+
|
| 605 |
+
if (traceType === "bar") {
|
| 606 |
+
trace.orientation = options.orientation;
|
| 607 |
+
trace.marker.opacity = 0.7;
|
| 608 |
+
trace.connectgaps = undefined;
|
| 609 |
+
trace.hovertemplate = undefined;
|
| 610 |
+
trace.customdata = undefined;
|
| 611 |
+
}
|
| 612 |
+
} else if (traceType === "candlestick") {
|
| 613 |
+
const candlestick_data: { [key: string]: any[] } = {
|
| 614 |
+
x: [],
|
| 615 |
+
open: [],
|
| 616 |
+
high: [],
|
| 617 |
+
low: [],
|
| 618 |
+
close: [],
|
| 619 |
+
};
|
| 620 |
+
|
| 621 |
+
csvData.forEach((row: any) => {
|
| 622 |
+
candlestick_data.x.push(row[options.x]);
|
| 623 |
+
candlestick_data.open.push(row[options.open]);
|
| 624 |
+
candlestick_data.high.push(row[options.high]);
|
| 625 |
+
candlestick_data.low.push(row[options.low]);
|
| 626 |
+
candlestick_data.close.push(row[options.close]);
|
| 627 |
+
});
|
| 628 |
+
|
| 629 |
+
trace = {
|
| 630 |
+
...traceBase,
|
| 631 |
+
x: candlestick_data.x,
|
| 632 |
+
open: candlestick_data.open,
|
| 633 |
+
high: candlestick_data.high,
|
| 634 |
+
low: candlestick_data.low,
|
| 635 |
+
close: candlestick_data.close,
|
| 636 |
+
increasing: {
|
| 637 |
+
line: { color: increasingColor, width: 0.8 },
|
| 638 |
+
fillcolor: increasingColor,
|
| 639 |
+
},
|
| 640 |
+
decreasing: {
|
| 641 |
+
line: { color: decreasingColor, width: 0.8 },
|
| 642 |
+
fillcolor: decreasingColor,
|
| 643 |
+
},
|
| 644 |
+
};
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
return {
|
| 648 |
+
...plotlyData,
|
| 649 |
+
data: [...plotlyData.data, trace],
|
| 650 |
+
};
|
| 651 |
+
}
|
frontend-components/plotly/src/components/Dialogs/TextChartDialog.tsx
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import CommonDialog from "./CommonDialog";
|
| 2 |
+
import { useState, useEffect, useRef } from "react";
|
| 3 |
+
|
| 4 |
+
const style = {
|
| 5 |
+
padding: "5px 2px 2px 5px",
|
| 6 |
+
margin: "2px 0",
|
| 7 |
+
};
|
| 8 |
+
|
| 9 |
+
export default function TextChartDialog({
|
| 10 |
+
open,
|
| 11 |
+
close,
|
| 12 |
+
addAnnotation,
|
| 13 |
+
deleteAnnotation,
|
| 14 |
+
popupData,
|
| 15 |
+
}: {
|
| 16 |
+
plotlyData: any;
|
| 17 |
+
open: boolean;
|
| 18 |
+
close: () => void;
|
| 19 |
+
addAnnotation: (annotation: any) => void;
|
| 20 |
+
updateAnnotation?: (annotation: any) => void;
|
| 21 |
+
deleteAnnotation: (annotation: any) => void;
|
| 22 |
+
popupData: any | null;
|
| 23 |
+
}) {
|
| 24 |
+
// Prevent multiple renderings
|
| 25 |
+
const hasLoaded = useRef(false);
|
| 26 |
+
|
| 27 |
+
const defaultPopupData = {
|
| 28 |
+
text: "",
|
| 29 |
+
color: "#0088CC",
|
| 30 |
+
size: 18,
|
| 31 |
+
bordercolor: "#822661",
|
| 32 |
+
arrowcolor: "#822661",
|
| 33 |
+
bgcolor: "#000000",
|
| 34 |
+
arrowsize: 1,
|
| 35 |
+
arrowwidth: 2,
|
| 36 |
+
yanchor: "above",
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
// Use a single state object to hold all form data
|
| 40 |
+
const [formData, setFormData] = useState<any>(defaultPopupData);
|
| 41 |
+
const [editMode, setEditMode] = useState(false);
|
| 42 |
+
|
| 43 |
+
// Handle initialization when dialog opens
|
| 44 |
+
useEffect(() => {
|
| 45 |
+
if (open && popupData?.annotation && !hasLoaded.current) {
|
| 46 |
+
const annotation = popupData.annotation;
|
| 47 |
+
|
| 48 |
+
// Get properties from annotation for editing
|
| 49 |
+
let data = {
|
| 50 |
+
text: annotation.text || "",
|
| 51 |
+
color: annotation.font?.color || defaultPopupData.color,
|
| 52 |
+
size: annotation.font?.size || defaultPopupData.size,
|
| 53 |
+
bordercolor: annotation.bordercolor || defaultPopupData.bordercolor,
|
| 54 |
+
bgcolor: annotation.bgcolor || defaultPopupData.bgcolor,
|
| 55 |
+
arrowcolor: annotation.arrowcolor || defaultPopupData.arrowcolor,
|
| 56 |
+
arrowsize: annotation.arrowsize || defaultPopupData.arrowsize,
|
| 57 |
+
arrowwidth: annotation.arrowwidth || defaultPopupData.arrowwidth,
|
| 58 |
+
yanchor: "above",
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
// Determine position based on annotation coordinates
|
| 62 |
+
if (annotation.y !== undefined && annotation.ay !== undefined) {
|
| 63 |
+
data.yanchor = annotation.y < annotation.ay ? "above" : "below";
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
setFormData(data);
|
| 67 |
+
setEditMode(true);
|
| 68 |
+
hasLoaded.current = true;
|
| 69 |
+
} else if (!open) {
|
| 70 |
+
// Reset when dialog closes
|
| 71 |
+
setFormData(defaultPopupData);
|
| 72 |
+
setEditMode(false);
|
| 73 |
+
hasLoaded.current = false;
|
| 74 |
+
} else if (open && !popupData?.annotation) {
|
| 75 |
+
// Reset for new annotations
|
| 76 |
+
setFormData(defaultPopupData);
|
| 77 |
+
setEditMode(false);
|
| 78 |
+
}
|
| 79 |
+
}, [open, popupData]);
|
| 80 |
+
|
| 81 |
+
function onChange(e: any) {
|
| 82 |
+
const name = e.target.id.replace("addtext_", "");
|
| 83 |
+
let value = e.target.value;
|
| 84 |
+
|
| 85 |
+
// Convert numeric values
|
| 86 |
+
if (name === "size" || name === "arrowsize" || name === "arrowwidth") {
|
| 87 |
+
value = parseFloat(value);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
setFormData((prev: any) => ({
|
| 91 |
+
...prev,
|
| 92 |
+
[name]: value
|
| 93 |
+
}));
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
function onClose() {
|
| 97 |
+
close();
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
function onSubmit() {
|
| 101 |
+
if (formData.text) {
|
| 102 |
+
const dataToSubmit = { ...formData };
|
| 103 |
+
|
| 104 |
+
// Add the annotation reference for editing
|
| 105 |
+
if (editMode && popupData?.annotation) {
|
| 106 |
+
dataToSubmit.annotation = popupData.annotation;
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
addAnnotation(dataToSubmit);
|
| 110 |
+
close();
|
| 111 |
+
} else {
|
| 112 |
+
if (document.getElementById("popup_textarea_warning")) {
|
| 113 |
+
document.getElementById("popup_textarea_warning")!.style.display = "block";
|
| 114 |
+
}
|
| 115 |
+
if (document.getElementById("addtext_text")) {
|
| 116 |
+
document.getElementById("addtext_text")!.style.border = "1px solid red";
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
function onDelete() {
|
| 122 |
+
if (editMode && popupData) {
|
| 123 |
+
deleteAnnotation(popupData);
|
| 124 |
+
}
|
| 125 |
+
close();
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
return (
|
| 129 |
+
<CommonDialog
|
| 130 |
+
title={editMode ? "Edit Annotation" : "Add Text to Chart"}
|
| 131 |
+
description="Add or edit text annotations on the chart."
|
| 132 |
+
open={open}
|
| 133 |
+
close={onClose}
|
| 134 |
+
>
|
| 135 |
+
<div id="popup_title" className="popup_content">
|
| 136 |
+
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
| 137 |
+
<div style={{ marginBottom: 20 }}>
|
| 138 |
+
<label htmlFor="popup_text">
|
| 139 |
+
<b>Text:</b>
|
| 140 |
+
<div id="popup_textarea_warning" className="popup_warning" style={{display: "none"}}>
|
| 141 |
+
Text is required
|
| 142 |
+
</div>
|
| 143 |
+
</label>
|
| 144 |
+
<textarea
|
| 145 |
+
id="addtext_text"
|
| 146 |
+
style={{
|
| 147 |
+
...style,
|
| 148 |
+
width: "100%",
|
| 149 |
+
maxWidth: "100%",
|
| 150 |
+
maxHeight: "200px",
|
| 151 |
+
marginTop: "8px",
|
| 152 |
+
}}
|
| 153 |
+
rows={4}
|
| 154 |
+
cols={50}
|
| 155 |
+
placeholder="Enter text here"
|
| 156 |
+
onChange={onChange}
|
| 157 |
+
value={formData.text || ""}
|
| 158 |
+
></textarea>
|
| 159 |
+
</div>
|
| 160 |
+
|
| 161 |
+
<div
|
| 162 |
+
style={{
|
| 163 |
+
display: "grid",
|
| 164 |
+
gridTemplateColumns: "1fr 1fr",
|
| 165 |
+
gap: "12px",
|
| 166 |
+
marginBottom: 20,
|
| 167 |
+
}}
|
| 168 |
+
>
|
| 169 |
+
{/* Row 1 */}
|
| 170 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 171 |
+
<label htmlFor="addtext_color">
|
| 172 |
+
<b>Font color</b>
|
| 173 |
+
</label>
|
| 174 |
+
<input
|
| 175 |
+
type="color"
|
| 176 |
+
id="addtext_color"
|
| 177 |
+
style={{ margin: "2px 0" }}
|
| 178 |
+
value={formData.color}
|
| 179 |
+
onChange={onChange}
|
| 180 |
+
/>
|
| 181 |
+
</div>
|
| 182 |
+
|
| 183 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 184 |
+
<label htmlFor="addtext_size">
|
| 185 |
+
<b>Font size</b>
|
| 186 |
+
</label>
|
| 187 |
+
<input
|
| 188 |
+
style={{ width: "52px" }}
|
| 189 |
+
type="number"
|
| 190 |
+
id="addtext_size"
|
| 191 |
+
value={formData.size}
|
| 192 |
+
onChange={onChange}
|
| 193 |
+
/>
|
| 194 |
+
</div>
|
| 195 |
+
|
| 196 |
+
{/* Row 2 */}
|
| 197 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 198 |
+
<label htmlFor="addtext_bgcolor">
|
| 199 |
+
<b>Background</b>
|
| 200 |
+
</label>
|
| 201 |
+
<input
|
| 202 |
+
type="color"
|
| 203 |
+
id="addtext_bgcolor"
|
| 204 |
+
style={{ margin: "2px 0" }}
|
| 205 |
+
value={formData.bgcolor}
|
| 206 |
+
onChange={onChange}
|
| 207 |
+
/>
|
| 208 |
+
</div>
|
| 209 |
+
|
| 210 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 211 |
+
<label htmlFor="addtext_bordercolor">
|
| 212 |
+
<b>Border color</b>
|
| 213 |
+
</label>
|
| 214 |
+
<input
|
| 215 |
+
type="color"
|
| 216 |
+
id="addtext_bordercolor"
|
| 217 |
+
style={{ margin: "2px 0" }}
|
| 218 |
+
value={formData.bordercolor}
|
| 219 |
+
onChange={onChange}
|
| 220 |
+
/>
|
| 221 |
+
</div>
|
| 222 |
+
|
| 223 |
+
{/* Row 3 */}
|
| 224 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 225 |
+
<label htmlFor="addtext_arrowcolor">
|
| 226 |
+
<b>Arrow color</b>
|
| 227 |
+
</label>
|
| 228 |
+
<input
|
| 229 |
+
type="color"
|
| 230 |
+
id="addtext_arrowcolor"
|
| 231 |
+
style={{ margin: "2px 0" }}
|
| 232 |
+
value={formData.arrowcolor}
|
| 233 |
+
onChange={onChange}
|
| 234 |
+
/>
|
| 235 |
+
</div>
|
| 236 |
+
|
| 237 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 238 |
+
<label htmlFor="addtext_arrowsize">
|
| 239 |
+
<b>Arrow size</b>
|
| 240 |
+
</label>
|
| 241 |
+
<input
|
| 242 |
+
style={{ width: "52px" }}
|
| 243 |
+
type="number"
|
| 244 |
+
id="addtext_arrowsize"
|
| 245 |
+
min="0.1"
|
| 246 |
+
max="5"
|
| 247 |
+
step="0.1"
|
| 248 |
+
value={formData.arrowsize}
|
| 249 |
+
onChange={onChange}
|
| 250 |
+
/>
|
| 251 |
+
</div>
|
| 252 |
+
|
| 253 |
+
{/* Row 4 */}
|
| 254 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 255 |
+
<label htmlFor="addtext_arrowwidth">
|
| 256 |
+
<b>Arrow width</b>
|
| 257 |
+
</label>
|
| 258 |
+
<input
|
| 259 |
+
style={{ width: "52px" }}
|
| 260 |
+
type="number"
|
| 261 |
+
id="addtext_arrowwidth"
|
| 262 |
+
min="1"
|
| 263 |
+
max="10"
|
| 264 |
+
value={formData.arrowwidth}
|
| 265 |
+
onChange={onChange}
|
| 266 |
+
/>
|
| 267 |
+
</div>
|
| 268 |
+
|
| 269 |
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
| 270 |
+
<label htmlFor="addtext_yanchor">
|
| 271 |
+
<b>Position</b>
|
| 272 |
+
</label>
|
| 273 |
+
<select
|
| 274 |
+
id="addtext_yanchor"
|
| 275 |
+
name="yanchor"
|
| 276 |
+
style={{ width: "100px" }}
|
| 277 |
+
value={formData.yanchor}
|
| 278 |
+
onChange={onChange}
|
| 279 |
+
>
|
| 280 |
+
<option value="above">Above</option>
|
| 281 |
+
<option value="below">Below</option>
|
| 282 |
+
</select>
|
| 283 |
+
</div>
|
| 284 |
+
</div>
|
| 285 |
+
</div>
|
| 286 |
+
|
| 287 |
+
<div style={{ float: "right", marginTop: 20 }}>
|
| 288 |
+
<button
|
| 289 |
+
className="_btn-tertiary ph-capture"
|
| 290 |
+
id="title_cancel"
|
| 291 |
+
onClick={onClose}
|
| 292 |
+
>
|
| 293 |
+
Cancel
|
| 294 |
+
</button>
|
| 295 |
+
{editMode && (
|
| 296 |
+
<button
|
| 297 |
+
className="_btn ph-capture"
|
| 298 |
+
id="title_delete"
|
| 299 |
+
onClick={onDelete}
|
| 300 |
+
>
|
| 301 |
+
Delete
|
| 302 |
+
</button>
|
| 303 |
+
)}
|
| 304 |
+
<button
|
| 305 |
+
className="_btn ph-capture"
|
| 306 |
+
id="title_submit"
|
| 307 |
+
onClick={onSubmit}
|
| 308 |
+
>
|
| 309 |
+
Submit
|
| 310 |
+
</button>
|
| 311 |
+
</div>
|
| 312 |
+
</div>
|
| 313 |
+
</CommonDialog>
|
| 314 |
+
);
|
| 315 |
+
}
|
frontend-components/plotly/src/components/Dialogs/TitleChartDialog.tsx
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import CommonDialog, { styleDialog } from "../Dialogs/CommonDialog";
|
| 2 |
+
import { useState } from "react";
|
| 3 |
+
|
| 4 |
+
export default function TitleChartDialog({
|
| 5 |
+
plotlyData,
|
| 6 |
+
open,
|
| 7 |
+
close,
|
| 8 |
+
defaultTitle,
|
| 9 |
+
updateTitle,
|
| 10 |
+
updateAxesTitles,
|
| 11 |
+
}: {
|
| 12 |
+
plotlyData?: any;
|
| 13 |
+
open: boolean;
|
| 14 |
+
close: () => void;
|
| 15 |
+
defaultTitle: string;
|
| 16 |
+
updateTitle: (title: string) => void;
|
| 17 |
+
updateAxesTitles: (axesTitles: any) => void;
|
| 18 |
+
}) {
|
| 19 |
+
const [title, setTitle] = useState(defaultTitle);
|
| 20 |
+
|
| 21 |
+
const yAxes = Object.keys(plotlyData.layout || {}).filter(
|
| 22 |
+
(k) => k.startsWith("yaxis") && plotlyData.layout[k].range != undefined
|
| 23 |
+
);
|
| 24 |
+
const xAxes = Object.keys(plotlyData.layout || {}).filter(
|
| 25 |
+
(k) =>
|
| 26 |
+
k.startsWith("xaxis") &&
|
| 27 |
+
plotlyData.layout[k].showticklabels != undefined &&
|
| 28 |
+
plotlyData.layout[k]?.anchor
|
| 29 |
+
);
|
| 30 |
+
|
| 31 |
+
const [axesTitles, setAxesTitles] = useState<any>({});
|
| 32 |
+
|
| 33 |
+
return (
|
| 34 |
+
<CommonDialog
|
| 35 |
+
title="Chart Titles"
|
| 36 |
+
description="Change the titles on the chart."
|
| 37 |
+
open={open}
|
| 38 |
+
close={close}
|
| 39 |
+
>
|
| 40 |
+
<div id="popup_title" className="popup_content">
|
| 41 |
+
<div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
|
| 42 |
+
<div>
|
| 43 |
+
<label htmlFor="title_text">
|
| 44 |
+
<b>Title:</b>
|
| 45 |
+
</label>
|
| 46 |
+
<textarea
|
| 47 |
+
id="title_text"
|
| 48 |
+
style={{
|
| 49 |
+
...styleDialog,
|
| 50 |
+
width: "100%",
|
| 51 |
+
maxWidth: "100%",
|
| 52 |
+
maxHeight: "200px",
|
| 53 |
+
marginTop: "8px",
|
| 54 |
+
marginLeft: "0px",
|
| 55 |
+
}}
|
| 56 |
+
rows={2}
|
| 57 |
+
cols={20}
|
| 58 |
+
value={title}
|
| 59 |
+
onChange={(e) => setTitle(e.target.value)}
|
| 60 |
+
></textarea>
|
| 61 |
+
</div>
|
| 62 |
+
<div
|
| 63 |
+
id="xaxis_div"
|
| 64 |
+
className="csv_column_container"
|
| 65 |
+
style={{ marginTop: 5, marginBottom: -5 }}
|
| 66 |
+
>
|
| 67 |
+
{xAxes.map((x, i) => (
|
| 68 |
+
<div key={x} style={{ marginTop: 5, marginBottom: 5 }}>
|
| 69 |
+
<label htmlFor={`title_${x}`}>
|
| 70 |
+
{i === 0 ? <b>X axis:</b> : <b>X axis {i + 1}:</b>}
|
| 71 |
+
</label>
|
| 72 |
+
<input
|
| 73 |
+
id={`title_${x}`}
|
| 74 |
+
style={{ marginLeft: "0px", padding: "5px 2px 2px 5px" }}
|
| 75 |
+
type="text"
|
| 76 |
+
defaultValue={plotlyData?.layout[x]?.title?.text || ""}
|
| 77 |
+
onChange={(e) => {
|
| 78 |
+
setAxesTitles({
|
| 79 |
+
...axesTitles,
|
| 80 |
+
[x]: e.target.value,
|
| 81 |
+
});
|
| 82 |
+
}}
|
| 83 |
+
/>
|
| 84 |
+
</div>
|
| 85 |
+
))}
|
| 86 |
+
</div>
|
| 87 |
+
<div
|
| 88 |
+
id="yaxis_div"
|
| 89 |
+
className="csv_column_container"
|
| 90 |
+
style={{ marginTop: 5, marginBottom: 5 }}
|
| 91 |
+
>
|
| 92 |
+
{yAxes.map((y, i) => (
|
| 93 |
+
<div key={y} style={{ marginTop: 10 }}>
|
| 94 |
+
<label htmlFor={`title_${y}`}>
|
| 95 |
+
{i === 0 ? <b>Y axis:</b> : <b>Y axis {i + 1}:</b>}
|
| 96 |
+
</label>
|
| 97 |
+
<input
|
| 98 |
+
id={`title_${y}`}
|
| 99 |
+
style={{ marginLeft: "0px", padding: "5px 2px 2px 5px" }}
|
| 100 |
+
type="text"
|
| 101 |
+
defaultValue={plotlyData?.layout[y]?.title?.text || ""}
|
| 102 |
+
onChange={(e) => {
|
| 103 |
+
setAxesTitles({
|
| 104 |
+
...axesTitles,
|
| 105 |
+
[y]: e.target.value,
|
| 106 |
+
});
|
| 107 |
+
}}
|
| 108 |
+
/>
|
| 109 |
+
</div>
|
| 110 |
+
))}
|
| 111 |
+
</div>
|
| 112 |
+
</div>
|
| 113 |
+
|
| 114 |
+
<div style={{ float: "right", marginTop: 20 }}>
|
| 115 |
+
<button
|
| 116 |
+
className="_btn-tertiary ph-capture"
|
| 117 |
+
id="title_cancel"
|
| 118 |
+
onClick={close}
|
| 119 |
+
>
|
| 120 |
+
Cancel
|
| 121 |
+
</button>
|
| 122 |
+
<button
|
| 123 |
+
className="_btn ph-capture"
|
| 124 |
+
id="title_submit"
|
| 125 |
+
onClick={() => {
|
| 126 |
+
// Update parent state - this will trigger the useEffect in Chart.tsx
|
| 127 |
+
updateTitle(title);
|
| 128 |
+
updateAxesTitles(axesTitles);
|
| 129 |
+
|
| 130 |
+
// Force an immediate update to the plotly chart directly
|
| 131 |
+
if (window.Plotly && document.getElementById('plotlyChart')) {
|
| 132 |
+
const chart = document.getElementById('plotlyChart');
|
| 133 |
+
|
| 134 |
+
// Only update axis titles, not the main chart title
|
| 135 |
+
const updateObj: { [key: string]: string } = {};
|
| 136 |
+
|
| 137 |
+
// Add all axis title changes
|
| 138 |
+
Object.entries(axesTitles).forEach(([axis, text]) => {
|
| 139 |
+
updateObj[`${axis}.title.text`] = String(text);
|
| 140 |
+
});
|
| 141 |
+
|
| 142 |
+
if (Object.keys(updateObj).length > 0) {
|
| 143 |
+
console.log("Applying immediate axis title updates:", updateObj);
|
| 144 |
+
window.Plotly.relayout(chart, updateObj);
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
close();
|
| 149 |
+
}}
|
| 150 |
+
>
|
| 151 |
+
Submit
|
| 152 |
+
</button>
|
| 153 |
+
</div>
|
| 154 |
+
</div>
|
| 155 |
+
</CommonDialog>
|
| 156 |
+
);
|
| 157 |
+
}
|
frontend-components/plotly/src/components/Icons/Close.tsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import type { SVGProps } from "react";
|
| 2 |
+
interface SVGRProps {
|
| 3 |
+
title?: string;
|
| 4 |
+
titleId?: string;
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
const CloseIcon = ({
|
| 8 |
+
title,
|
| 9 |
+
titleId,
|
| 10 |
+
...props
|
| 11 |
+
}: SVGProps<SVGSVGElement> & SVGRProps) => (
|
| 12 |
+
<svg
|
| 13 |
+
xmlns="http://www.w3.org/2000/svg"
|
| 14 |
+
fill="none"
|
| 15 |
+
viewBox="0 0 24 24"
|
| 16 |
+
stroke="currentColor"
|
| 17 |
+
strokeWidth={1.5}
|
| 18 |
+
{...props}
|
| 19 |
+
>
|
| 20 |
+
<path
|
| 21 |
+
strokeLinecap="round"
|
| 22 |
+
strokeLinejoin="round"
|
| 23 |
+
d="M6 18L18 6M6 6l12 12"
|
| 24 |
+
/>
|
| 25 |
+
</svg>
|
| 26 |
+
);
|
| 27 |
+
|
| 28 |
+
export default CloseIcon;
|