Hemaambika commited on
Commit
cc50687
1 Parent(s): 8eca612

update pytrade.py

Browse files
Files changed (1) hide show
  1. pytrade.py +362 -2
pytrade.py CHANGED
@@ -12,7 +12,6 @@ import jwt # PyJWT
12
  from flask import Flask, request, jsonify, Response, make_response
13
  from flask_cors import CORS
14
 
15
- # --- Your modules ---
16
  # --- Your modules ---
17
  from analysestock import analysestock
18
  from list import (
@@ -26,6 +25,7 @@ from signin import get_db_connection, ensure_user_table_exists # <- NOTE: from
26
  import bcrypt # pip install bcrypt
27
  from typing import Tuple
28
  from werkzeug.security import generate_password_hash, check_password_hash
 
29
 
30
  # ------------------------------------------------------------------------------
31
  # App, ENV, CORS
@@ -47,6 +47,7 @@ FRONTEND_ORIGIN = os.environ.get(
47
  "FRONTEND_ORIGIN",
48
  "https://pykara-py-trade.static.hf.space,https://localhost:4200"
49
  )
 
50
  allowed = [o.strip() for o in FRONTEND_ORIGIN.split(",") if o.strip()]
51
  CORS(
52
  app,
@@ -524,7 +525,7 @@ def create_community_post():
524
  if not row or row[0] is None:
525
  return jsonify({"error": "Failed to retrieve new post id"}), 500
526
 
527
- new_id = int(row[0])
528
 
529
  return jsonify({
530
  "id": new_id,
@@ -616,6 +617,365 @@ def list_community_posts():
616
  except:
617
  pass
618
  conn.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
  # ------------------------------------------------------------------------------
620
  # Run
621
  # ------------------------------------------------------------------------------
 
12
  from flask import Flask, request, jsonify, Response, make_response
13
  from flask_cors import CORS
14
 
 
15
  # --- Your modules ---
16
  from analysestock import analysestock
17
  from list import (
 
25
  import bcrypt # pip install bcrypt
26
  from typing import Tuple
27
  from werkzeug.security import generate_password_hash, check_password_hash
28
+ import yfinance as yf
29
 
30
  # ------------------------------------------------------------------------------
31
  # App, ENV, CORS
 
47
  "FRONTEND_ORIGIN",
48
  "https://pykara-py-trade.static.hf.space,https://localhost:4200"
49
  )
50
+
51
  allowed = [o.strip() for o in FRONTEND_ORIGIN.split(",") if o.strip()]
52
  CORS(
53
  app,
 
525
  if not row or row[0] is None:
526
  return jsonify({"error": "Failed to retrieve new post id"}), 500
527
 
528
+ new_id = int(row[0]);
529
 
530
  return jsonify({
531
  "id": new_id,
 
617
  except:
618
  pass
619
  conn.close()
620
+
621
+
622
+ # ------------------------------------------------------------------------------
623
+ # Market overview values (uses yfinance)
624
+ # ------------------------------------------------------------------------------
625
+ @app.get("/getmarketcards")
626
+ def get_market_cards():
627
+ """
628
+ Returns a list of market overview items with live prices fetched from yfinance.
629
+ Each item: { title, price, chg, chgPct }
630
+ """
631
+ # map of friendly title -> yfinance symbol
632
+ tickers = {
633
+ 'Gold': 'GC=F',
634
+ 'Silver': 'SI=F',
635
+ 'Crude Oil (Brent)': 'BZ=F',
636
+ 'Crude Oil (WTI)': 'CL=F',
637
+ 'Natural Gas': 'NG=F',
638
+ 'USD/INR': 'INR=X',
639
+ 'EUR/USD': 'EURUSD=X',
640
+ 'GBP/USD': 'GBPUSD=X',
641
+ 'Bitcoin': 'BTC-USD',
642
+ 'Ethereum': 'ETH-USD',
643
+ 'S&P 500': '^GSPC',
644
+ 'NASDAQ': '^IXIC',
645
+ 'DAX': '^GDAXI',
646
+ 'Nikkei': '^N225',
647
+ 'Copper': 'HG=F'
648
+ }
649
+
650
+ out = []
651
+ for title, symbol in tickers.items():
652
+ try:
653
+ t = yf.Ticker(symbol)
654
+ # try to get recent close prices
655
+ hist = None
656
+ try:
657
+ hist = t.history(period="2d")
658
+ except Exception:
659
+ hist = None
660
+
661
+ price = None
662
+ chg = None
663
+ chg_pct = None
664
+
665
+ if hist is not None and hasattr(hist, 'empty') and not hist.empty:
666
+ closes = list(hist['Close'].values)
667
+ if len(closes) >= 2:
668
+ last = float(closes[-1])
669
+ prev = float(closes[-2])
670
+ else:
671
+ last = float(closes[-1])
672
+ prev = last
673
+ price = last
674
+ chg = last - prev
675
+ chg_pct = (chg / prev * 100) if prev != 0 else 0.0
676
+ else:
677
+ # fallback: try fast info lookup
678
+ info = {}
679
+ try:
680
+ info = t.info or {}
681
+ except Exception:
682
+ info = {}
683
+ # try fields: 'regularMarketPrice', 'previousClose'
684
+ last = info.get('regularMarketPrice') or info.get('currentPrice') or info.get('previousClose')
685
+ prev = info.get('previousClose')
686
+ try:
687
+ if last is not None:
688
+ price = float(last)
689
+ if prev is not None:
690
+ chg = float(last) - float(prev) if last is not None else None
691
+ chg_pct = (chg / float(prev) * 100) if prev and chg is not None else None
692
+ except Exception:
693
+ price = price or None
694
+
695
+ out.append({
696
+ 'title': title,
697
+ 'symbol': symbol,
698
+ 'price': price,
699
+ 'chg': chg,
700
+ 'chgPct': chg_pct
701
+ })
702
+ except Exception as e:
703
+ app.logger.exception('getmarketcards: failed for %s', symbol)
704
+ out.append({'title': title, 'symbol': symbol, 'price': None, 'chg': None, 'chgPct': None})
705
+
706
+ return jsonify(out), 200
707
+
708
+
709
+ # ------------------------------------------------------------------------------
710
+ # Global indices (uses yfinance)
711
+ # ------------------------------------------------------------------------------
712
+ @app.get("/getglobalindices")
713
+ def get_global_indices():
714
+ """
715
+ Returns a flat list of global indices for a set of countries. Each item:
716
+ { id, name, country, region, price, change, changePct, sparkline }
717
+ """
718
+ # Define representative indices per country with yfinance symbols
719
+ indices_map = {
720
+ 'India': [
721
+ ('Nifty 50', '^NSEI'),
722
+ ('SENSEX', '^BSESN'),
723
+ ('Nifty Bank', '^NSEBANK'),
724
+ ('Nifty Midcap 100', None),
725
+ ('Nifty Smallcap 100', None),
726
+ ],
727
+ 'United States': [
728
+ ('S&P 500', '^GSPC'),
729
+ ('Dow Jones', '^DJI'),
730
+ ('Nasdaq Composite', '^IXIC'),
731
+ ('S&P MidCap 400', None),
732
+ ('S&P SmallCap 600', None),
733
+ ],
734
+ 'United Kingdom': [
735
+ ('FTSE 100', '^FTSE'),
736
+ ('FTSE 250', None),
737
+ ],
738
+ 'Germany': [
739
+ ('DAX', '^GDAXI'),
740
+ ('MDAX', None),
741
+ ],
742
+ 'Sweden': [
743
+ ('OMX Stockholm 30', '^OMXSPI'),
744
+ ],
745
+ 'Russia': [
746
+ ('MOEX Russia', 'IMOEX.ME'),
747
+ ('RTS Index', None),
748
+ ]
749
+ }
750
+
751
+ def build_spark_from_hist(close_vals, pts=26):
752
+ # normalize to length pts by sampling or padding
753
+ arr = []
754
+ if not close_vals:
755
+ # synthetic series
756
+ base = 100
757
+ from random import random
758
+ arr = [max(1, base + (random() - 0.5) * base * 0.02) for _ in range(pts)]
759
+ return arr
760
+ vals = list(close_vals)
761
+ # if too short, pad with last
762
+ while len(vals) < pts:
763
+ vals.insert(0, vals[0])
764
+ if len(vals) > pts:
765
+ # sample evenly
766
+ step = len(vals) / pts
767
+ sampled = [vals[int(i * step)] for i in range(pts)]
768
+ return [float(v) for v in sampled]
769
+ return [float(v) for v in vals]
770
+
771
+ out = []
772
+ for country, items in indices_map.items():
773
+ for name, symbol in items:
774
+ price = None
775
+ change = None
776
+ change_pct = None
777
+ spark = []
778
+ try:
779
+ if symbol:
780
+ t = yf.Ticker(symbol)
781
+ hist = None
782
+ try:
783
+ hist = t.history(period='30d')
784
+ except Exception:
785
+ hist = None
786
+ if hist is not None and hasattr(hist, 'empty') and not hist.empty:
787
+ closes = list(hist['Close'].values)
788
+ # create spark from most recent values
789
+ spark = build_spark_from_hist(closes[-26:], pts=26)
790
+ last = float(closes[-1])
791
+ prev = float(closes[-2]) if len(closes) >= 2 else last
792
+ price = last
793
+ change = last - prev
794
+ change_pct = (change / prev * 100) if prev != 0 else 0.0
795
+ else:
796
+ # try single-value info
797
+ info = {}
798
+ try:
799
+ info = t.info or {}
800
+ except Exception:
801
+ info = {}
802
+ last = info.get('regularMarketPrice') or info.get('currentPrice') or info.get('previousClose')
803
+ prev = info.get('previousClose')
804
+ if last is not None:
805
+ price = float(last)
806
+ if price is not None and prev is not None:
807
+ change = float(price) - float(prev)
808
+ change_pct = (change / float(prev) * 100) if prev != 0 else 0.0
809
+ else:
810
+ # no symbol: produce demo values (randomized around a base)
811
+ import random
812
+ base = 10000 if 'Nifty' in name or 'Sensex' in name or 'Nifty' in name else 1000
813
+ price = round(base + (random.random() - 0.5) * base * 0.05, 2)
814
+ change = round((random.random() - 0.5) * price * 0.01, 2)
815
+ change_pct = (change / (price - change) * 100) if price - change != 0 else 0.0
816
+ spark = build_spark_from_hist([price for _ in range(26)], pts=26)
817
+ except Exception as e:
818
+ app.logger.exception('get_global_indices: failed for %s', symbol or name)
819
+
820
+ gid = (name or '').replace('\n', ' ').replace(' ', '_') + '_' + (country.replace(' ', '_') if country else 'unknown')
821
+ out.append({
822
+ 'id': gid,
823
+ 'name': name,
824
+ 'country': country,
825
+ 'region': country,
826
+ 'price': price,
827
+ 'change': change,
828
+ 'changePct': change_pct,
829
+ 'sparkline': spark
830
+ })
831
+
832
+ return jsonify(out), 200
833
+
834
+ @app.get("/getquotes")
835
+ def get_quotes():
836
+ """
837
+ Returns live quotes for a list of tickers provided via ?tickers=CSV
838
+ Each returned item: { symbol, price, chg, chgPct, high, low }
839
+ """
840
+ tickers_csv = (request.args.get("tickers") or "").strip()
841
+ if not tickers_csv:
842
+ return jsonify({"error": "Missing ?tickers=..."}), 400
843
+
844
+ tickers = [t.strip() for t in tickers_csv.split(",") if t.strip()]
845
+ out = []
846
+ for symbol in tickers:
847
+ price = None
848
+ chg = None
849
+ chg_pct = None
850
+ high = None
851
+ low = None
852
+ try:
853
+ t = yf.Ticker(symbol)
854
+ hist = None
855
+ try:
856
+ hist = t.history(period="2d")
857
+ except Exception:
858
+ hist = None
859
+
860
+ if hist is not None and hasattr(hist, 'empty') and not hist.empty:
861
+ closes = list(hist['Close'].values)
862
+ if len(closes) >= 2:
863
+ last = float(closes[-1])
864
+ prev = float(closes[-2])
865
+ else:
866
+ last = float(closes[-1])
867
+ prev = last
868
+ price = last
869
+ chg = last - prev
870
+ chg_pct = (chg / prev * 100) if prev != 0 else 0.0
871
+
872
+ # try to extract intraday high/low from history if available
873
+ try:
874
+ highs = list(hist['High'].values)
875
+ lows = list(hist['Low'].values)
876
+ high = float(highs[-1]) if highs else None
877
+ low = float(lows[-1]) if lows else None
878
+ except Exception:
879
+ high = None
880
+ low = None
881
+ else:
882
+ info = {}
883
+ try:
884
+ info = t.info or {}
885
+ except Exception:
886
+ info = {}
887
+ last = info.get('regularMarketPrice') or info.get('currentPrice') or info.get('previousClose')
888
+ prev = info.get('previousClose')
889
+ if last is not None:
890
+ price = float(last)
891
+ if price is not None and prev is not None:
892
+ chg = float(price) - float(prev)
893
+ chg_pct = (chg / float(prev) * 100) if prev != 0 else 0.0
894
+ try:
895
+ high = info.get('dayHigh') or info.get('regularMarketDayRange')
896
+ low = info.get('dayLow')
897
+ except Exception:
898
+ high = None
899
+ low = None
900
+ except Exception as e:
901
+ app.logger.exception('get_quotes: failed for %s', symbol)
902
+
903
+ out.append({
904
+ 'symbol': symbol,
905
+ 'price': price,
906
+ 'chg': chg,
907
+ 'chgPct': chg_pct,
908
+ 'high': high,
909
+ 'low': low
910
+ })
911
+
912
+ return jsonify(out), 200
913
+
914
+ @app.get("/getintraday")
915
+ def get_intraday():
916
+ """
917
+ Returns intraday series for a given symbol using yfinance.
918
+ Query params: ?symbol=...&period=1d&interval=1m
919
+ Response: { symbol, timestamps: [iso,...], closes: [num,...] }
920
+ """
921
+ symbol = (request.args.get('symbol') or '').strip()
922
+ period = (request.args.get('period') or '1d').strip()
923
+ interval = (request.args.get('interval') or '1m').strip()
924
+ if not symbol:
925
+ return jsonify({'error': 'Missing ?symbol parameter'}), 400
926
+
927
+ try:
928
+ t = yf.Ticker(symbol)
929
+ hist = None
930
+ try:
931
+ hist = t.history(period=period, interval=interval)
932
+ except Exception:
933
+ hist = None
934
+
935
+ timestamps = []
936
+ closes = []
937
+ if hist is not None and hasattr(hist, 'empty') and not hist.empty:
938
+ # hist.index may be DatetimeIndex
939
+ for idx, row in hist.iterrows():
940
+ try:
941
+ ts = idx.isoformat()
942
+ except Exception:
943
+ try:
944
+ ts = str(idx)
945
+ except Exception:
946
+ ts = None
947
+ if ts is not None:
948
+ timestamps.append(ts)
949
+ try:
950
+ closes.append(float(row['Close']))
951
+ except Exception:
952
+ closes.append(None)
953
+ else:
954
+ # fallback: attempt to get last close from info
955
+ info = {}
956
+ try:
957
+ info = t.info or {}
958
+ except Exception:
959
+ info = {}
960
+ last = info.get('regularMarketPrice') or info.get('currentPrice') or info.get('previousClose')
961
+ if last is not None:
962
+ # return a tiny synthetic series
963
+ from datetime import datetime, timedelta
964
+ now = datetime.utcnow()
965
+ for i in range(60):
966
+ ts = (now - timedelta(minutes=(59 - i))).isoformat()
967
+ timestamps.append(ts)
968
+ closes.append(float(last))
969
+
970
+ return jsonify({
971
+ 'symbol': symbol,
972
+ 'timestamps': timestamps,
973
+ 'closes': closes
974
+ }), 200
975
+ except Exception as e:
976
+ app.logger.exception('get_intraday failed for %s', symbol)
977
+ return jsonify({'symbol': symbol, 'timestamps': [], 'closes': []}), 200
978
+
979
  # ------------------------------------------------------------------------------
980
  # Run
981
  # ------------------------------------------------------------------------------