Spaces:
Sleeping
Sleeping
File size: 8,942 Bytes
955a169 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
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.") |