Created
February 25, 2025 05:47
-
-
Save darrenjrobinson/bf5e038ffbc26b5f4f0519edca796184 to your computer and use it in GitHub Desktop.
dalle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Storytelling - Unlocking Insights from Company Data\n", | |
"## AI Hackathon Scenario 2\n", | |
"\n", | |
"\n", | |
"Welcome to the AI Hackathon! This event challenges participants to leverage Azure AI Services to transform raw corporate data into compelling and insightful presentations. \n", | |
"\n", | |
"## Key Objectives\n", | |
"1. **Text Analysis**: Extract key insights and trends from text, such as financial performance, strategic initiatives, and market sentiment.\n", | |
"2. **Machine Learning**: Use historical share price data and company announcements to train models that predict future stock performance.\n", | |
"3. **Generative AI**: Use Azure OpenAI to create unique and relevant images, charts, and infographics that enhance the visual appeal of the PowerPoint slides.\n", | |
"\n", | |
"## Enabling Services\n", | |
"- **Azure Cognitive Services - Language**: Analyse the sentiment, key phrases, and entities in company reports and announcements.\n", | |
"- **Azure Machine Learning**: Build predictive models to analyse share price movements and forecast future trends.\n", | |
"- **Azure OpenAI**: Analysis of reports and generation of custom graphics and visuals for the presentation.\n", | |
"\n", | |
"Participants will define the public organization and data to use for the AI-driven analysis, obtain the data, and use Azure AI Services to perform the analysis and assist with creating a summary narrative. The goal is to summarize the analysis using Azure AI, generate presentation graphics, and share your learnings and the presentation generated.\n" | |
], | |
"metadata": { | |
"nteract": { | |
"transient": { | |
"deleting": false | |
} | |
} | |
} | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# 1. Get Public Stock Data Information - ASX Stock Price Analysis\n", | |
"\n", | |
"This following example helps you analyse the stock performance of companies listed on the Australian Securities Exchange (ASX). It uses the `yfinance` library to get stock data from Yahoo Finance, and then performs calculations and creates visualizations to help you understand the stock's recent activity.\n", | |
"\n", | |
"Here's a breakdown of what the script does:\n", | |
"\n", | |
"1. **Input Ticker:** You enter the ASX ticker symbol of the company you want to analyse (e.g., XRO.AX for Xero). The `.AX` part is optional; the script will add it if you forget.\n", | |
"\n", | |
"2. **Fetch Data:** The script fetches historical stock price data (for the past year by default) from Yahoo Finance using the provided ticker. This includes daily open, high, low, and close prices, as well as trading volume.\n", | |
"\n", | |
"3. **Analyse Data:** The script calculates several key metrics:\n", | |
" * **Price Change:** The percentage change in stock price over the analysed period.\n", | |
" * **Volatility:** A measure of how much the stock price fluctuates (standard deviation of daily returns).\n", | |
" * **Trading Volume:** Average and maximum daily trading volume.\n", | |
" * **Moving Averages:** 50-day and 200-day moving averages, which help smooth out price fluctuations and identify trends.\n", | |
" * **Highest and Lowest Prices:** The highest and lowest prices reached during the period, and the dates they occurred.\n", | |
"\n", | |
"4. **Display Results:** The results are displayed in a clear and organized way:\n", | |
" * **Summary:** Starting and ending prices, overall percentage change (color-coded green for gains, red for losses), highest and lowest prices, volatility, and trading volume.\n", | |
" * **Interactive Chart:** A candlestick chart shows the daily price movements, along with the 50-day and 200-day moving averages. A separate bar chart displays the daily trading volume. These charts are interactive, allowing you to zoom and pan.\n", | |
" * **Additional Charts:** Histograms of daily returns and cumulative returns provide further insights into the stock's performance.\n", | |
" * **Key Insights:** The script provides some basic interpretations, such as whether the 50-day moving average is above or below the 200-day moving average (a common indicator used by traders). It also compares the stock's performance to the ASX 200 index.\n", | |
"\n", | |
"5. **Challenges:** The notebook concludes with some challenges to encourage further exploration, such as investigating news related to price changes, calculating beta, using other technical indicators, and comparing the stock to competitors.\n", | |
"\n", | |
"**Key Libraries Used:**\n", | |
"\n", | |
"* `pandas`: For data manipulation and analysis.\n", | |
"* `numpy`: For numerical calculations.\n", | |
"* `matplotlib` and `seaborn`: For creating static charts.\n", | |
"* `yfinance`: For downloading stock data from Yahoo Finance.\n", | |
"* `plotly`: For creating interactive charts.\n", | |
"* `ipywidgets`: For creating interactive elements like text input and buttons within the notebook.\n", | |
"\n", | |
"**How to Use:**\n", | |
"\n", | |
"1. Enter the ASX ticker symbol in the text box.\n", | |
"2. Click the \"Analyse\" button.\n", | |
"3. The results, charts, and insights will be displayed below.\n", | |
"\n", | |
"**Important Notes:**\n", | |
"\n", | |
"* ASX tickers typically end with `.AX`.\n", | |
"* The default analysis period is one year.\n", | |
"* This is a basic analysis. More in-depth research is recommended before making any investment decisions.\n", | |
"* Modify the script for different time periods or analysis\n" | |
], | |
"metadata": { | |
"nteract": { | |
"transient": { | |
"deleting": false | |
} | |
} | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# ASX Stock Price Analysis Tutorial\n", | |
"# Azure Machine Learning Notebook\n", | |
"\n", | |
"# Import necessary libraries\n", | |
"import pandas as pd\n", | |
"import numpy as np\n", | |
"import matplotlib.pyplot as plt\n", | |
"import seaborn as sns\n", | |
"import yfinance as yf\n", | |
"from datetime import datetime, timedelta\n", | |
"import ipywidgets as widgets\n", | |
"from IPython.display import display, HTML, clear_output\n", | |
"import plotly.graph_objects as go\n", | |
"from plotly.subplots import make_subplots\n", | |
"\n", | |
"# Set plotting styles\n", | |
"plt.style.use('ggplot')\n", | |
"sns.set_theme()\n", | |
"\n", | |
"# Title and introduction\n", | |
"print(\"# ASX Stock Price Performance Analysis\")\n", | |
"print(\"In this tutorial, you will analyse the recent stock performance of an ASX-listed company of your choice.\")\n", | |
"print(\"You'll learn how to fetch stock data, perform basic analysis, and visualize the results.\")\n", | |
"\n", | |
"# Store data in a global cache\n", | |
"\n", | |
"class DataCache:\n", | |
" \"\"\"Global cache to store analysis results between cells\"\"\"\n", | |
" def __init__(self):\n", | |
" self.stock_data = None\n", | |
" self.results = None\n", | |
" \n", | |
" def update(self, stock_data, results):\n", | |
" self.stock_data = stock_data\n", | |
" self.results = results\n", | |
" \n", | |
" def has_data(self):\n", | |
" return self.stock_data is not None and self.results is not None\n", | |
"\n", | |
"# Create a global instance of the cache\n", | |
"global_cache = DataCache()\n", | |
"\n", | |
"\n", | |
"# Create an input field for the user to enter an ASX ticker symbol\n", | |
"ticker_input = widgets.Text(\n", | |
" value='',\n", | |
" placeholder='Enter ASX ticker symbol (e.g., XRO.AX)',\n", | |
" description='Ticker:',\n", | |
" disabled=False\n", | |
")\n", | |
"\n", | |
"# Create a button to trigger the analysis\n", | |
"analyze_button = widgets.Button(\n", | |
" description='Analyse',\n", | |
" disabled=False,\n", | |
" button_style='primary',\n", | |
" tooltip='Click to analyse the stock',\n", | |
" icon='check'\n", | |
")\n", | |
"\n", | |
"# Create output area for displaying results\n", | |
"output_area = widgets.Output()\n", | |
"\n", | |
"# Function to validate ASX ticker symbol\n", | |
"def validate_ticker(ticker):\n", | |
" if not ticker.endswith('.AX'):\n", | |
" ticker = ticker + '.AX'\n", | |
" return ticker\n", | |
"\n", | |
"# Function to fetch stock data\n", | |
"def fetch_stock_data(ticker, period='1y'):\n", | |
" ticker = validate_ticker(ticker)\n", | |
" try:\n", | |
" stock_data = yf.download(ticker, period=period)\n", | |
" if len(stock_data) == 0: # Use len() instead of .empty property\n", | |
" return None\n", | |
" return stock_data\n", | |
" except Exception as e:\n", | |
" print(f\"Error fetching data: {e}\")\n", | |
" return None\n", | |
"\n", | |
"# Function to format datetime index to string safely\n", | |
"def format_date_safely(dt_index):\n", | |
" try:\n", | |
" if hasattr(dt_index, 'strftime'):\n", | |
" return dt_index.strftime('%Y-%m-%d')\n", | |
" else:\n", | |
" return str(dt_index)\n", | |
" except:\n", | |
" return 'N/A'\n", | |
"\n", | |
"# Helper function to safely extract scalar values\n", | |
"def safe_scalar(series_or_value):\n", | |
" if isinstance(series_or_value, pd.Series):\n", | |
" if len(series_or_value) > 0:\n", | |
" return series_or_value.iloc[0]\n", | |
" else:\n", | |
" return np.nan\n", | |
" return series_or_value\n", | |
"\n", | |
"# Function to analyze stock performance\n", | |
"def analyze_stock(ticker, stock_data):\n", | |
" if stock_data is None or len(stock_data) == 0: # Use len() instead of .empty property\n", | |
" print(f\"No data available for {ticker}\")\n", | |
" return None, None\n", | |
" \n", | |
" # Calculate key metrics as scalars to avoid Series comparisons\n", | |
" start_price = float(stock_data['Close'].iloc[0])\n", | |
" end_price = float(stock_data['Close'].iloc[-1])\n", | |
" percent_change = ((end_price - start_price) / start_price) * 100\n", | |
" \n", | |
" # Calculate daily returns\n", | |
" stock_data['Daily_Return'] = stock_data['Close'].pct_change() * 100\n", | |
" \n", | |
" # Calculate moving averages\n", | |
" stock_data['MA50'] = stock_data['Close'].rolling(window=50).mean()\n", | |
" stock_data['MA200'] = stock_data['Close'].rolling(window=200).mean()\n", | |
" \n", | |
" # Calculate volatility (standard deviation of returns)\n", | |
" volatility = float(stock_data['Daily_Return'].std())\n", | |
" \n", | |
" # Calculate trading volume metrics (as scalars)\n", | |
" avg_volume = float(stock_data['Volume'].mean())\n", | |
" max_volume = float(stock_data['Volume'].max())\n", | |
" \n", | |
" # Get date information safely\n", | |
" start_date = format_date_safely(stock_data.index[0])\n", | |
" end_date = format_date_safely(stock_data.index[-1])\n", | |
" \n", | |
" # Get dates for key metrics safely \n", | |
" max_volume_idx = stock_data['Volume'].idxmax()\n", | |
" max_volume_date = format_date_safely(max_volume_idx)\n", | |
" \n", | |
" highest_idx = stock_data['Close'].idxmax()\n", | |
" highest_date = format_date_safely(highest_idx)\n", | |
" \n", | |
" lowest_idx = stock_data['Close'].idxmin()\n", | |
" lowest_date = format_date_safely(lowest_idx)\n", | |
" \n", | |
" # Use float for highest/lowest price to ensure scalar values\n", | |
" highest_price = float(stock_data['Close'].max())\n", | |
" lowest_price = float(stock_data['Close'].min())\n", | |
" \n", | |
" # Prepare results dictionary with scalar values\n", | |
" results = {\n", | |
" 'ticker': ticker,\n", | |
" 'start_date': start_date,\n", | |
" 'end_date': end_date,\n", | |
" 'start_price': start_price,\n", | |
" 'end_price': end_price,\n", | |
" 'percent_change': percent_change,\n", | |
" 'volatility': volatility,\n", | |
" 'avg_volume': avg_volume,\n", | |
" 'max_volume': max_volume,\n", | |
" 'max_volume_date': max_volume_date,\n", | |
" 'highest_price': highest_price,\n", | |
" 'highest_date': highest_date,\n", | |
" 'lowest_price': lowest_price,\n", | |
" 'lowest_date': lowest_date\n", | |
" }\n", | |
" \n", | |
" return results, stock_data\n", | |
"\n", | |
"# Function to display results\n", | |
"def display_results(results, stock_data):\n", | |
" if results is None or stock_data is None or len(stock_data) == 0:\n", | |
" print(\"Unable to display results. No data available.\")\n", | |
" return\n", | |
" \n", | |
" # Create title with company information\n", | |
" ticker_name = results['ticker'].replace('.AX', '')\n", | |
" \n", | |
" # Display summary information\n", | |
" print(f\"## Analysis Results for {ticker_name}\")\n", | |
" print(f\"Period: {results['start_date']} to {results['end_date']}\")\n", | |
" print(\"\\n### Performance Summary\")\n", | |
" print(f\"Starting Price: ${results['start_price']:.2f}\")\n", | |
" print(f\"Ending Price: ${results['end_price']:.2f}\")\n", | |
" \n", | |
" # Display performance with color-coded text\n", | |
" # Use scalar comparison\n", | |
" percent_change = float(results['percent_change'])\n", | |
" if percent_change > 0:\n", | |
" print(f\"Overall Change: <span style='color:green'>+{percent_change:.2f}%</span>\")\n", | |
" else:\n", | |
" print(f\"Overall Change: <span style='color:red'>{percent_change:.2f}%</span>\")\n", | |
" \n", | |
" print(f\"\\nHighest Price: ${results['highest_price']:.2f} on {results['highest_date']}\")\n", | |
" print(f\"Lowest Price: ${results['lowest_price']:.2f} on {results['lowest_date']}\")\n", | |
" print(f\"Volatility (Std Dev of Daily Returns): {results['volatility']:.2f}%\")\n", | |
" print(f\"Average Daily Trading Volume: {int(results['avg_volume']):,} shares\")\n", | |
" print(f\"Highest Trading Volume: {int(results['max_volume']):,} shares on {results['max_volume_date']}\")\n", | |
" \n", | |
" # Create interactive price chart using plotly\n", | |
" fig = make_subplots(rows=2, cols=1, shared_xaxes=True, \n", | |
" vertical_spacing=0.1, \n", | |
" subplot_titles=('Price and Moving Averages', 'Volume'),\n", | |
" row_heights=[0.7, 0.3])\n", | |
" \n", | |
" # Add candlestick chart\n", | |
" fig.add_trace(\n", | |
" go.Candlestick(\n", | |
" x=stock_data.index,\n", | |
" open=stock_data['Open'],\n", | |
" high=stock_data['High'],\n", | |
" low=stock_data['Low'],\n", | |
" close=stock_data['Close'],\n", | |
" name='Price'\n", | |
" ),\n", | |
" row=1, col=1\n", | |
" )\n", | |
" \n", | |
" # Add moving averages\n", | |
" fig.add_trace(\n", | |
" go.Scatter(\n", | |
" x=stock_data.index,\n", | |
" y=stock_data['MA50'],\n", | |
" name='50-Day MA',\n", | |
" line=dict(color='blue', width=1)\n", | |
" ),\n", | |
" row=1, col=1\n", | |
" )\n", | |
" \n", | |
" fig.add_trace(\n", | |
" go.Scatter(\n", | |
" x=stock_data.index,\n", | |
" y=stock_data['MA200'],\n", | |
" name='200-Day MA',\n", | |
" line=dict(color='red', width=1)\n", | |
" ),\n", | |
" row=1, col=1\n", | |
" )\n", | |
" \n", | |
" # Add volume chart with scalar comparisons per row\n", | |
" # Use a list comprehension with scalar comparison for each row\n", | |
" colors = []\n", | |
" for idx, row in stock_data.iterrows():\n", | |
" close_val = float(row['Close'])\n", | |
" open_val = float(row['Open'])\n", | |
" colors.append('green' if close_val >= open_val else 'red')\n", | |
" \n", | |
" fig.add_trace(\n", | |
" go.Bar(\n", | |
" x=stock_data.index,\n", | |
" y=stock_data['Volume'],\n", | |
" name='Volume',\n", | |
" marker=dict(color=colors)\n", | |
" ),\n", | |
" row=2, col=1\n", | |
" )\n", | |
" \n", | |
" # Update layout\n", | |
" fig.update_layout(\n", | |
" title=f'{ticker_name} Stock Price Performance',\n", | |
" xaxis_title='Date',\n", | |
" yaxis_title='Price (AUD)',\n", | |
" height=600,\n", | |
" width=900,\n", | |
" showlegend=True,\n", | |
" xaxis_rangeslider_visible=False\n", | |
" )\n", | |
" \n", | |
" fig.update_yaxes(title_text=\"Volume\", row=2, col=1)\n", | |
" fig.update_yaxes(title_text=\"Price (AUD)\", row=1, col=1)\n", | |
" \n", | |
" fig.show()\n", | |
" \n", | |
" # Create additional analysis plots\n", | |
" plt.figure(figsize=(14, 6))\n", | |
" \n", | |
" # Daily returns histogram\n", | |
" plt.subplot(1, 2, 1)\n", | |
" sns.histplot(stock_data['Daily_Return'].dropna(), kde=True)\n", | |
" plt.title(f'{ticker_name} Daily Returns Distribution')\n", | |
" plt.xlabel('Daily Return (%)')\n", | |
" plt.ylabel('Frequency')\n", | |
" \n", | |
" # Cumulative returns\n", | |
" plt.subplot(1, 2, 2)\n", | |
" cumulative_returns = (1 + stock_data['Daily_Return'].dropna()/100).cumprod() - 1\n", | |
" cumulative_returns.plot()\n", | |
" plt.title(f'{ticker_name} Cumulative Returns')\n", | |
" plt.xlabel('Date')\n", | |
" plt.ylabel('Cumulative Return')\n", | |
" plt.tight_layout()\n", | |
" plt.show()\n", | |
" \n", | |
" # Print insights - careful to extract scalars when making comparisons\n", | |
" print(\"\\n### Key Insights\")\n", | |
" \n", | |
" # Extract scalar values for moving average comparison\n", | |
" try:\n", | |
" if len(stock_data) >= 200: # Ensure we have enough data\n", | |
" last_ma50 = float(stock_data['MA50'].iloc[-1])\n", | |
" last_ma200 = float(stock_data['MA200'].iloc[-1])\n", | |
" \n", | |
" if not np.isnan(last_ma50) and not np.isnan(last_ma200):\n", | |
" if last_ma50 > last_ma200:\n", | |
" print(\"* The 50-day moving average is above the 200-day moving average, which is typically considered a bullish signal.\")\n", | |
" else:\n", | |
" print(\"* The 50-day moving average is below the 200-day moving average, which is typically considered a bearish signal.\")\n", | |
" else:\n", | |
" print(\"* Moving average analysis not available (insufficient data)\")\n", | |
" else:\n", | |
" print(\"* Moving average analysis not available (insufficient data points)\")\n", | |
" except:\n", | |
" print(\"* Moving average analysis not available (calculation error)\")\n", | |
" \n", | |
" # Check if enough data for trend analysis\n", | |
" try:\n", | |
" if len(stock_data) >= 60:\n", | |
" recent_mean = float(stock_data['Close'].iloc[-30:].mean())\n", | |
" previous_mean = float(stock_data['Close'].iloc[-60:-30].mean())\n", | |
" \n", | |
" if not np.isnan(recent_mean) and not np.isnan(previous_mean):\n", | |
" recent_trend = recent_mean - previous_mean\n", | |
" if recent_trend > 0:\n", | |
" print(f\"* The stock has been trending upward over the last 30 days (compared to the previous 30 days).\")\n", | |
" else:\n", | |
" print(f\"* The stock has been trending downward over the last 30 days (compared to the previous 30 days).\")\n", | |
" else:\n", | |
" print(\"* Trend analysis not available (missing data)\")\n", | |
" else:\n", | |
" print(\"* Trend analysis not available (insufficient historical data)\")\n", | |
" except:\n", | |
" print(\"* Trend analysis not available (calculation error)\")\n", | |
" \n", | |
" # Market comparison - ASX 200 (Using ^AXJO as a proxy for ASX 200)\n", | |
" try:\n", | |
" asx200 = yf.download('^AXJO', start=stock_data.index[0], end=stock_data.index[-1])\n", | |
" if len(asx200) > 0: # Check if data is available\n", | |
" asx_start = float(asx200['Close'].iloc[0])\n", | |
" asx_end = float(asx200['Close'].iloc[-1])\n", | |
" asx_return = ((asx_end - asx_start) / asx_start) * 100\n", | |
" \n", | |
" stock_return = float(results['percent_change'])\n", | |
" \n", | |
" if stock_return > asx_return:\n", | |
" print(f\"* {ticker_name} outperformed the ASX 200 index ({stock_return:.2f}% vs {asx_return:.2f}%)\")\n", | |
" else:\n", | |
" print(f\"* {ticker_name} underperformed the ASX 200 index ({stock_return:.2f}% vs {asx_return:.2f}%)\")\n", | |
" else:\n", | |
" print(\"* Unable to compare with ASX 200 index (no data available)\")\n", | |
" except Exception as e:\n", | |
" print(f\"* Unable to compare with ASX 200 index ({str(e)})\")\n", | |
" \n", | |
" # Challenge for students\n", | |
" print(\"\\n### Student Challenges\")\n", | |
" print(\"1. Try to identify any news or events that coincide with significant price or volume changes\")\n", | |
" print(\"2. Calculate and interpret the stock's beta relative to the ASX 200\")\n", | |
" print(\"3. Perform a simple technical analysis using additional indicators like RSI or MACD\")\n", | |
" print(\"4. Compare this stock with another company in the same sector\")\n", | |
" print(\"5. Create a prediction model for future stock price movements\")\n", | |
"\n", | |
"# Function to handle button click\n", | |
"def on_button_click(b):\n", | |
" with output_area:\n", | |
" clear_output()\n", | |
" ticker = ticker_input.value.strip().upper()\n", | |
" \n", | |
" if not ticker:\n", | |
" print(\"Please enter a valid ASX ticker symbol\")\n", | |
" return\n", | |
" \n", | |
" ticker = validate_ticker(ticker)\n", | |
" print(f\"Analyzing {ticker}...\")\n", | |
" \n", | |
" # Fetch stock data\n", | |
" stock_data = fetch_stock_data(ticker)\n", | |
" \n", | |
" if stock_data is None or len(stock_data) == 0:\n", | |
" print(f\"Could not find data for {ticker}. Please check the ticker symbol and try again.\")\n", | |
" return\n", | |
" \n", | |
" # Analyze stock data\n", | |
" results, updated_stock_data = analyze_stock(ticker, stock_data)\n", | |
" \n", | |
" # Store in global cache\n", | |
" global_cache.update(updated_stock_data, results)\n", | |
" \n", | |
" # Display results\n", | |
" display_results(results, updated_stock_data)\n", | |
"\n", | |
"# Make sure to update your analyze_button to use this function\n", | |
"analyze_button.on_click(on_button_click)\n", | |
"\n", | |
"# Display the UI elements\n", | |
"print(\"\\n## Enter an ASX-listed company ticker to analyse\")\n", | |
"print(\"Examples: WTC.AX (WiseTech Global), MIN.AX (Mineral Resources), FMG.AX (Fortescue Metals)\")\n", | |
"display(widgets.HBox([ticker_input, analyze_button]))\n", | |
"display(output_area)\n", | |
"\n", | |
"# Additional tips and instructions for students\n", | |
"print(\"\\n## Notes for Students\")\n", | |
"print(\"1. ASX tickers should end with '.AX' (this will be added automatically if you don't include it)\")\n", | |
"print(\"2. Some common ASX tech and resources companies include:\")\n", | |
"print(\" - WTC.AX (WiseTech Global - Software)\")\n", | |
"print(\" - XRO.AX (Xero - Cloud accounting)\")\n", | |
"print(\" - APX.AX (Appen - AI datasets)\")\n", | |
"print(\" - FMG.AX (Fortescue Metals - Iron ore)\")\n", | |
"print(\" - MIN.AX (Mineral Resources - Mining services)\")\n", | |
"print(\" - RIO.AX (Rio Tinto - Mining)\")\n", | |
"print(\"3. The analysis covers a one-year period by default\")\n", | |
"print(\"4. For more comprehensive analysis, consider exploring the company's financial statements\")\n", | |
"print(\"\\nHappy analysing!\")" | |
], | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": "Analyzing WTC.AX...\n## Analysis Results for WTC\nPeriod: 2024-02-26 to 2025-02-25\n\n### Performance Summary\nStarting Price: $89.00\nEnding Price: $94.93\nOverall Change: <span style='color:green'>+6.66%</span>\n\nHighest Price: $138.93 on Ticker\nWTC.AX 2024-11-21\ndtype: datetime64[ns]\nLowest Price: $84.20 on Ticker\nWTC.AX 2024-08-05\ndtype: datetime64[ns]\nVolatility (Std Dev of Daily Returns): 3.01%\nAverage Daily Trading Volume: 599,552 shares\nHighest Trading Volume: 4,850,307 shares on Ticker\nWTC.AX 2025-02-24\ndtype: datetime64[ns]\n" | |
}, | |
{ | |
"output_type": "display_data", | |
"data": { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment