Darshan03 commited on
Commit
1310b26
·
verified ·
1 Parent(s): e349125

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -95
app.py CHANGED
@@ -14,6 +14,7 @@ import base64
14
  from xhtml2pdf import pisa
15
  import logging
16
  import json
 
17
 
18
  # Load environment variables
19
  load_dotenv()
@@ -408,23 +409,24 @@ def get_unique_output_dir(base_dir, ticker):
408
  return output_dir
409
 
410
  def get_stock_symbols(file_path):
411
- """
412
- Reads stock symbols from a JSON file.
413
-
414
- Args:
415
- file_path (str): The path to the JSON file.
416
-
417
- Returns:
418
- list: A list of stock symbols.
419
- """
420
- try:
421
- with open(file_path, 'r') as f:
422
- data = json.load(f)
423
- symbols = [stock["symbol"] for stock in data.values()]
424
- return symbols
425
- except Exception as e:
426
- st.error(f"Error reading stock symbols: {e}")
427
- return []
 
428
 
429
  # --------------------- Streamlit App ---------------------
430
 
@@ -447,87 +449,205 @@ def main():
447
  except Exception as e:
448
  st.error(f"An error occurred while processing the uploaded file: {e}")
449
 
450
- # Dropdown to select the stock
451
- selected_stock = st.selectbox("Select a stock for analysis:", stock_symbols)
452
 
453
  # Period selection
454
- period = st.selectbox("Select the time period for analysis:", ["1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max"])
455
-
456
- if st.button("Analyze"):
457
- with st.spinner("Performing technical analysis..."):
458
- try:
459
- # Create a unique output directory
460
- output_dir = get_unique_output_dir(Config.OUTPUT_DIR, selected_stock)
461
-
462
- # Fetch and process data
463
- stock_data = fetch_data(selected_stock, period=period)
464
- stock_data = calculate_moving_averages(stock_data)
465
- stock_data = calculate_ema(stock_data)
466
- stock_data = calculate_macd(stock_data)
467
- stock_data = calculate_rsi(stock_data)
468
- stock_data = calculate_adx(stock_data)
469
- stock_data = calculate_atr(stock_data)
470
- stock_data = calculate_bollinger_bands(stock_data)
471
- stock_data = calculate_stochastic(stock_data)
472
-
473
- # Get analysis output
474
- analysis_output = print_indicator_outputs(stock_data, selected_stock, output_dir)
475
-
476
- # Plot and save charts
477
- plot_stock_and_indicators(stock_data, selected_stock, output_dir)
478
- plot_volatility_indicators(stock_data, selected_stock, output_dir)
479
-
480
- # Generate prompt for LLM
481
- image_paths = [os.path.join(output_dir, file) for file in os.listdir(output_dir) if file.endswith(('.png', '.jpg', '.jpeg'))]
482
- image_paths = "\n".join(image_paths)
483
- prompt = generate_prompt(analysis_output, image_paths)
484
-
485
- # Save the prompt to a file
486
- prompt_filename = os.path.join(output_dir, f"{selected_stock}_prompt.txt")
487
- with open(prompt_filename, 'w') as f:
488
- f.write(prompt)
489
- logging.info(f"Saved LLM prompt to: {prompt_filename}")
490
-
491
- # Configure and create LLM model
492
- genai.configure(api_key=Config.GOOGLE_API_KEY)
493
- generation_config = {
494
- "temperature": 0.9,
495
- "top_p": 0.95,
496
- "top_k": 40,
497
- "max_output_tokens": 8192,
498
- }
499
- model = genai.GenerativeModel(
500
- model_name="gemini-pro", # Use "gemini-pro" for text-only
501
- generation_config=generation_config,
502
- )
503
- chat_session = model.start_chat()
504
-
505
- # Get LLM response
506
- llm_response = get_response(chat_session, prompt)
507
-
508
- if llm_response:
509
- # Generate PDF
510
- pdf_filename = os.path.join(output_dir, f"technical_analysis_{selected_stock}.pdf")
511
- markdown_to_pdf_xhtml2pdf(llm_response.text, pdf_filename)
512
-
513
- # Offer PDF for download
514
- with open(pdf_filename, "rb") as pdf_file:
515
- pdf_bytes = pdf_file.read()
516
- st.download_button(
517
- label="Download Analysis PDF",
518
- data=pdf_bytes,
519
- file_name=f"technical_analysis_{selected_stock}.pdf",
520
- mime="application/pdf"
521
  )
522
- # Display the PDF using an iframe
523
- b64 = base64.b64encode(pdf_bytes).decode()
524
- pdf_display = f'<iframe src="data:application/pdf;base64,{b64}" width="700" height="1000" type="application/pdf"></iframe>'
525
- st.markdown(pdf_display, unsafe_allow_html=True)
526
- else:
527
- st.error("Could not generate PDF. LLM response is empty.")
528
-
529
- except Exception as e:
530
- st.error(f"An error occurred during analysis: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
 
532
  if __name__ == "__main__":
533
  main()
 
14
  from xhtml2pdf import pisa
15
  import logging
16
  import json
17
+ import streamlit.components.v1 as components
18
 
19
  # Load environment variables
20
  load_dotenv()
 
409
  return output_dir
410
 
411
  def get_stock_symbols(file_path):
412
+ """
413
+ Reads stock symbols from a JSON file.
414
+
415
+ Args:
416
+ file_path (str): The path to the JSON file.
417
+
418
+ Returns:
419
+ list: A list of stock symbols.
420
+ """
421
+ try:
422
+ with open(file_path, 'r') as f:
423
+ data = json.load(f)
424
+ # Extract symbols directly from the JSON structure
425
+ symbols = [details["symbol"] for details in data.values()]
426
+ return symbols
427
+ except Exception as e:
428
+ st.error(f"Error reading stock symbols: {e}")
429
+ return []
430
 
431
  # --------------------- Streamlit App ---------------------
432
 
 
449
  except Exception as e:
450
  st.error(f"An error occurred while processing the uploaded file: {e}")
451
 
452
+ # Use the uploaded symbols for dynamic selection
453
+ selected_symbol = st.sidebar.selectbox("Select a stock for analysis:", stock_symbols)
454
 
455
  # Period selection
456
+ period = st.sidebar.selectbox("Select the time period for analysis:", ["1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max"])
457
+
458
+ # Button to trigger analysis
459
+ if st.sidebar.button("Analyze"):
460
+ if selected_symbol: # Check if a symbol is selected
461
+ with st.spinner("Performing technical analysis..."):
462
+ try:
463
+ # Create a unique output directory
464
+ output_dir = get_unique_output_dir(Config.OUTPUT_DIR, selected_symbol)
465
+
466
+ # Fetch and process data
467
+ stock_data = fetch_data(selected_symbol, period=period)
468
+ stock_data = calculate_moving_averages(stock_data)
469
+ stock_data = calculate_ema(stock_data)
470
+ stock_data = calculate_macd(stock_data)
471
+ stock_data = calculate_rsi(stock_data)
472
+ stock_data = calculate_adx(stock_data)
473
+ stock_data = calculate_atr(stock_data)
474
+ stock_data = calculate_bollinger_bands(stock_data)
475
+ stock_data = calculate_stochastic(stock_data)
476
+
477
+ # Get analysis output
478
+ analysis_output = print_indicator_outputs(stock_data, selected_symbol, output_dir)
479
+
480
+ # Plot and save charts
481
+ plot_stock_and_indicators(stock_data, selected_symbol, output_dir)
482
+ plot_volatility_indicators(stock_data, selected_symbol, output_dir)
483
+
484
+ # Generate prompt for LLM
485
+ image_paths = [os.path.join(output_dir, file) for file in os.listdir(output_dir) if file.endswith(('.png', '.jpg', '.jpeg'))]
486
+ image_paths = "\n".join(image_paths)
487
+ prompt = generate_prompt(analysis_output, image_paths)
488
+
489
+ # Save the prompt to a file
490
+ prompt_filename = os.path.join(output_dir, f"{selected_symbol}_prompt.txt")
491
+ with open(prompt_filename, 'w') as f:
492
+ f.write(prompt)
493
+ logging.info(f"Saved LLM prompt to: {prompt_filename}")
494
+
495
+ # Configure and create LLM model
496
+ genai.configure(api_key=Config.GOOGLE_API_KEY)
497
+ generation_config = {
498
+ "temperature": 0.9,
499
+ "top_p": 0.95,
500
+ "top_k": 40,
501
+ "max_output_tokens": 8192,
502
+ }
503
+ model = genai.GenerativeModel(
504
+ model_name="gemini-pro", # Use "gemini-pro" for text-only
505
+ generation_config=generation_config,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  )
507
+ chat_session = model.start_chat()
508
+
509
+ # Get LLM response
510
+ llm_response = get_response(chat_session, prompt)
511
+
512
+ if llm_response:
513
+ # Generate PDF
514
+ pdf_filename = os.path.join(output_dir, f"technical_analysis_{selected_symbol}.pdf")
515
+ markdown_to_pdf_xhtml2pdf(llm_response.text, pdf_filename)
516
+
517
+ # Offer PDF for download
518
+ with open(pdf_filename, "rb") as pdf_file:
519
+ pdf_bytes = pdf_file.read()
520
+ st.download_button(
521
+ label="Download Analysis PDF",
522
+ data=pdf_bytes,
523
+ file_name=f"technical_analysis_{selected_symbol}.pdf",
524
+ mime="application/pdf"
525
+ )
526
+ # Display the PDF using an iframe
527
+ b64 = base64.b64encode(pdf_bytes).decode()
528
+ pdf_display = f'<iframe src="data:application/pdf;base64,{b64}" width="700" height="1000" type="application/pdf"></iframe>'
529
+ st.markdown(pdf_display, unsafe_allow_html=True)
530
+ else:
531
+ st.error("Could not generate PDF. LLM response is empty.")
532
+
533
+ except Exception as e:
534
+ st.error(f"An error occurred during analysis: {e}")
535
+ else:
536
+ st.sidebar.error("Please select a stock symbol.")
537
+
538
+ # Placeholder for the TradingView widget
539
+ st.header("TradingView Widget")
540
+ tradingview_placeholder = st.empty() # Create an empty placeholder
541
+
542
+ # --- TradingView Widget Code ---
543
+ tradingview_widget_code = f"""
544
+ <!-- TradingView Widget BEGIN -->
545
+ <div class="tradingview-widget-container" style="height:100%; width:100%">
546
+ <div id="tradingview_a1b2c" style="height:calc(100% - 32px); width:100%"></div>
547
+ <div class="tradingview-widget-copyright">
548
+ <a href="https://www.tradingview.com/" rel="noopener nofollow" target="_blank">
549
+ <span class="blue-text">Track all markets on TradingView</span>
550
+ </a>
551
+ </div>
552
+ <script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
553
+ <script type="text/javascript">
554
+ new TradingView.widget(
555
+ {{
556
+ "autosize": true,
557
+ "symbol": "{selected_symbol}",
558
+ "interval": "D",
559
+ "timezone": "Etc/UTC",
560
+ "theme": "light",
561
+ "style": "1",
562
+ "locale": "en",
563
+ "toolbar_bg": "#f1f3f6",
564
+ "enable_publishing": false,
565
+ "allow_symbol_change": true,
566
+ "container_id": "tradingview_a1b2c"
567
+ }}
568
+ );
569
+ </script>
570
+ </div>
571
+ <!-- TradingView Widget END -->
572
+ """
573
+ # ----------------------------------
574
+
575
+ # HTML, CSS, and JavaScript for Resizing (outside the if condition)
576
+ html_code = f"""
577
+ <style>
578
+ /* Make the container resizable */
579
+ #resizable-container {{
580
+ position: relative;
581
+ width: 700px; /* Initial width */
582
+ height: 600px; /* Initial height */
583
+ border: 2px solid #ccc;
584
+ overflow: hidden; /* Important for clipping the widget during resize */
585
+ }}
586
+
587
+ /* Style the resize handle (optional) */
588
+ .resize-handle {{
589
+ position: absolute;
590
+ width: 10px;
591
+ height: 10px;
592
+ background-color: #007bff; /* Example color */
593
+ cursor: se-resize; /* Diagonal resize cursor */
594
+ }}
595
+
596
+ /* Position the resize handle at the bottom-right corner */
597
+ #resize-handle-se {{
598
+ bottom: 0;
599
+ right: 0;
600
+ }}
601
+ </style>
602
+
603
+ <div id="resizable-container">
604
+ {tradingview_widget_code}
605
+ <div id="resize-handle-se" class="resize-handle"></div>
606
+ </div>
607
+
608
+ <script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
609
+ <script>
610
+ // Target the resize handle
611
+ interact('#resize-handle-se')
612
+ .draggable({{
613
+ // Restrict movement to the bounds of the container
614
+ modifiers: [
615
+ interact.modifiers.restrictRect({{
616
+ restriction: 'parent',
617
+ endOnly: true
618
+ }})
619
+ ],
620
+ inertia: true,
621
+ }})
622
+ .on('dragmove', function (event) {{
623
+ const container = document.getElementById('resizable-container');
624
+
625
+ // Update width and height based on drag movement
626
+ let newWidth = container.offsetWidth + event.dx;
627
+ let newHeight = container.offsetHeight + event.dy;
628
+
629
+ // Set minimum dimensions (adjust as needed)
630
+ const minWidth = 300;
631
+ const minHeight = 300;
632
+ if (newWidth < minWidth) {{
633
+ newWidth = minWidth;
634
+ }}
635
+ if (newHeight < minHeight) {{
636
+ newHeight = minHeight;
637
+ }}
638
+
639
+ container.style.width = newWidth + 'px';
640
+ container.style.height = newHeight + 'px';
641
+
642
+ // Trigger TradingView resize (if necessary - see note below)
643
+ // window.dispatchEvent(new Event('resize')); // You might not need this
644
+ }});
645
+ </script>
646
+ """
647
+
648
+ # Embed the HTML code using components.html
649
+ with tradingview_placeholder:
650
+ components.html(html_code, height=600, width=700, scrolling=False)
651
 
652
  if __name__ == "__main__":
653
  main()