Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import plotly.graph_objects as go | |
| from datetime import datetime, timedelta | |
| import pandas as pd | |
| import numpy as np | |
| from utils.patterns import identify_patterns, calculate_technical_indicators | |
| from utils.predictions import predict_movement | |
| from utils.trading import fetch_market_data, is_market_open | |
| # Page configuration | |
| st.set_page_config( | |
| page_title="Trading Pattern Analysis", | |
| page_icon="📈", | |
| layout="wide" | |
| ) | |
| # Load custom CSS | |
| with open('styles/custom.css') as f: | |
| st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True) | |
| # Pattern descriptions from the uploaded file | |
| PATTERN_DESCRIPTIONS = { | |
| 'HAMMER': 'Small body near the top with long lower wick, indicating buying pressure overcoming selling pressure.', | |
| 'INVERTED_HAMMER': 'Small body with long upper wick after downtrend, indicating resistance but potential upward movement.', | |
| 'PIERCING_LINE': 'Two-candlestick pattern where second closes above midpoint of first, signaling bullish shift.', | |
| 'BULLISH_ENGULFING': 'Small bearish candle followed by larger bullish candle that engulfs previous one.', | |
| 'MORNING_STAR': 'Three-candlestick pattern with bearish, small-bodied, and bullish candle indicating reversal.', | |
| 'THREE_WHITE_SOLDIERS': 'Three consecutive long bullish candles with small/no wicks, showing strong buying pressure.', | |
| 'BULLISH_HARAMI': 'Small bullish candle within body of preceding large bearish candle.', | |
| 'HANGING_MAN': 'Small body at top with long lower wick, signaling potential reversal.', | |
| 'DARK_CLOUD_COVER': 'Two-candlestick pattern with bearish closing below midpoint of previous bullish.', | |
| 'BEARISH_ENGULFING': 'Small bullish candle followed by larger bearish candle that engulfs it.', | |
| 'EVENING_STAR': 'Three-candlestick pattern with bullish, small-bodied, and bearish candle.', | |
| 'THREE_BLACK_CROWS': 'Three consecutive bearish candles showing strong selling.', | |
| 'SHOOTING_STAR': 'Small body with long upper wick, signaling resistance.', | |
| 'DOJI': 'Small body with wicks, showing market indecision.', | |
| 'DRAGONFLY_DOJI': 'Doji with long lower wick, showing buying pressure at bottom.', | |
| 'GRAVESTONE_DOJI': 'Doji with long upper wick, showing selling pressure at top.' | |
| } | |
| # Sidebar | |
| st.sidebar.title("Trading Controls") | |
| # Market Status Indicator | |
| market_open = is_market_open() | |
| status_color = "🟢" if market_open else "🔴" | |
| market_status = "Market Open" if market_open else "Market Closed" | |
| st.sidebar.write(f"{status_color} {market_status}") | |
| symbol = st.sidebar.text_input("Symbol", value="AAPL", help="Enter a valid stock symbol (e.g., AAPL, MSFT)") | |
| timeframe = st.sidebar.selectbox( | |
| "Timeframe", | |
| ["30m", "1h", "2h", "4h"], | |
| index=0, | |
| help="Select analysis timeframe (each candle represents 15 minutes)" | |
| ) | |
| # Add auto-refresh option | |
| auto_refresh = st.sidebar.checkbox("Auto-refresh data", value=True) | |
| if auto_refresh: | |
| st.sidebar.write("Updates every minute") | |
| st.rerun() # Use st.rerun() instead of experimental_rerun() | |
| # Main content | |
| st.title("Trading Pattern Analysis") | |
| try: | |
| # Fetch and process data | |
| with st.spinner('Fetching market data...'): | |
| df = fetch_market_data(symbol, period='1d', interval='15m') | |
| if len(df) >= 2: | |
| df = calculate_technical_indicators(df) | |
| patterns = identify_patterns(df) | |
| # Create candlestick chart | |
| fig = go.Figure(data=[go.Candlestick( | |
| x=df.index, | |
| open=df['Open'], | |
| high=df['High'], | |
| low=df['Low'], | |
| close=df['Close'] | |
| )]) | |
| # Update layout for dark theme | |
| fig.update_layout( | |
| template="plotly_dark", | |
| plot_bgcolor="#252525", | |
| paper_bgcolor="#252525", | |
| xaxis_rangeslider_visible=False, | |
| height=600, | |
| title=f"{symbol} - Live Market Data ({timeframe} timeframe)" | |
| ) | |
| # Display chart | |
| st.plotly_chart(fig, use_container_width=True) | |
| # Pattern Analysis | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("Pattern Analysis") | |
| if not patterns.empty and len(patterns) > 0: | |
| latest_patterns = patterns.iloc[-1] | |
| detected_patterns = latest_patterns[latest_patterns == 1].index.tolist() | |
| if detected_patterns: | |
| st.write("Detected Patterns:") | |
| for pattern in detected_patterns: | |
| st.markdown(f""" | |
| <div class="pattern-container"> | |
| <h4>• {pattern.replace('_', ' ')}</h4> | |
| <p>{PATTERN_DESCRIPTIONS.get(pattern, '')}</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| else: | |
| st.info("No patterns detected in current timeframe") | |
| else: | |
| st.write("No pattern data available") | |
| with col2: | |
| st.subheader("Prediction") | |
| if len(df) >= 30: | |
| prediction, probability = predict_movement(df) | |
| if prediction is not None and probability is not None: | |
| direction = "Upward" if prediction else "Downward" | |
| confidence = probability[1] if prediction else probability[0] | |
| direction_class = "profit" if direction == "Upward" else "loss" | |
| st.markdown(f""" | |
| <div class="prediction-container"> | |
| <h3 class="{direction_class}">Predicted Movement: {direction}</h3> | |
| <p>Confidence: {confidence:.2%}</p> | |
| <p>(Next 15-minute prediction)</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| else: | |
| st.write("Could not generate prediction") | |
| else: | |
| st.write("Insufficient data for prediction") | |
| # Technical Indicators | |
| st.subheader("Technical Indicators") | |
| col3, col4, col5 = st.columns(3) | |
| with col3: | |
| last_rsi = df['RSI'].iloc[-1] if 'RSI' in df else None | |
| prev_rsi = df['RSI'].iloc[-2] if 'RSI' in df and len(df) > 1 else None | |
| if last_rsi is not None and prev_rsi is not None: | |
| delta = last_rsi - prev_rsi | |
| delta_color = "profit" if delta > 0 else "loss" | |
| st.markdown(f""" | |
| <div class="metric-container"> | |
| <h4>RSI</h4> | |
| <p>{last_rsi:.2f}</p> | |
| <p class="{delta_color}">({delta:+.2f})</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with col4: | |
| last_macd = df['MACD'].iloc[-1] if 'MACD' in df else None | |
| prev_macd = df['MACD'].iloc[-2] if 'MACD' in df and len(df) > 1 else None | |
| if last_macd is not None and prev_macd is not None: | |
| delta = last_macd - prev_macd | |
| delta_color = "profit" if delta > 0 else "loss" | |
| st.markdown(f""" | |
| <div class="metric-container"> | |
| <h4>MACD</h4> | |
| <p>{last_macd:.2f}</p> | |
| <p class="{delta_color}">({delta:+.2f})</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with col5: | |
| last_sma = df['SMA_20'].iloc[-1] if 'SMA_20' in df else None | |
| last_close = df['Close'].iloc[-1] if len(df) > 0 else None | |
| if last_sma is not None and last_close is not None: | |
| delta = last_close - last_sma | |
| delta_color = "profit" if delta > 0 else "loss" | |
| st.markdown(f""" | |
| <div class="metric-container"> | |
| <h4>15-min SMA</h4> | |
| <p>{last_sma:.2f}</p> | |
| <p class="{delta_color}">({delta:+.2f})</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| else: | |
| st.warning("Insufficient data points. This could be because the market is closed or the selected timeframe is too short.") | |
| except Exception as e: | |
| st.error(f"Error: {str(e)}") | |
| if "Connection Error" in str(e): | |
| st.warning("Unable to connect to market data. Please check your internet connection and try again.") | |
| elif "not found" in str(e): | |
| st.warning("Invalid symbol. Please enter a valid stock symbol.") | |
| else: | |
| st.info("If the market is closed, you can still view the most recent trading data.") |