import pandas as pd import json import logging from src.strategy.scanner import scan_for_candidates logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def find_best_isa_tickers(): """ 1. Reads available Trading212 instruments. 2. Filters for US Stocks (excluding ETFs/Warrants which are often non-ISA compliant or bad for this strategy). 3. Maps T212 tickers to Yahoo Finance tickers. 4. Runs the strategy scanner to find the most volatile/liquid candidates. """ try: with open('available_instruments.json', 'r') as f: instruments = json.load(f) except FileNotFoundError: logger.error("Please run get_available_tickers.py first to generate available_instruments.json") return # Filter for US Stocks only # - type == 'STOCK': Excludes US ETFs (not allowed in UK ISAs) and Warrants # - currencyCode == 'USD': Ensures it's trading during the US session (09:30 EST) us_stocks = [ inst for inst in instruments if inst.get('type') == 'STOCK' and inst.get('currencyCode') == 'USD' ] logger.info(f"Filtered down to {len(us_stocks)} US Stocks from Trading212.") # Extract short names (Yahoo Finance tickers) # Trading212 usually uses 'shortName' for the actual market ticker (e.g., AAPL) # and 'ticker' for their internal ID (e.g., AAPL_US_EQ). t212_to_yf_map = {} for stock in us_stocks: short_name = stock.get('shortName') t212_id = stock.get('ticker') if short_name and t212_id: # Avoid preferred shares/warrants that might sneak in with hyphens or dots # if yfinance can't parse them easily, but we'll try them all. t212_to_yf_map[short_name] = t212_id yf_tickers = list(t212_to_yf_map.keys()) # We don't want to scan all 6,000+ stocks at once (Yahoo Finance will rate limit us). # Let's filter locally first using T212 maxOpenQuantity or just take a known subset, # OR we can pass the top 500 popular ones. For this script, let's scan a robust list of # well-known highly liquid tech/growth stocks that are definitely ISA eligible. # Known high-liquidity ISA-eligible US stocks: focus_list = [ "TSLA", "NVDA", "AMD", "AAPL", "MSFT", "META", "AMZN", "GOOGL", "NFLX", "COIN", "MSTR", "PLTR", "UBER", "HOOD", "RST", "SNOW", "CRM", "CRWD", "PANW", "SMCI", "ARM", "SQ", "SHOP", "ROKU", "DDOG", "NET", "DOCN" ] # Ensure they exist in our T212 account valid_yf_tickers = [t for t in focus_list if t in t212_to_yf_map] logger.info(f"Scanning {len(valid_yf_tickers)} highly liquid known ISA-eligible stocks...") # Run the scanner results_df = scan_for_candidates(tickers=valid_yf_tickers, min_price=20.0, min_volume=2_000_000) if results_df.empty: logger.warning("No candidates met the minimum price/volume criteria.") return # Map back to Trading212 internal tickers so the bot knows what to trade results_df['T212_Ticker'] = results_df['Ticker'].map(t212_to_yf_map) # Reorder columns cols = ['Ticker', 'T212_Ticker', 'Close', 'ATR_14', 'ATR_Percent', 'Avg_Volume'] results_df = results_df[cols] print("\n" + "="*80) print("🏆 BEST ISA-ELIGIBLE CANDIDATES FOR TOUCH & TURN TODAY 🏆") print("="*80) print(results_df.to_string(index=False)) print("\n* Use the 'T212_Ticker' column when configuring the ExecutionManager.") # Save the day's watchlist results_df.to_csv("isa_watchlist.csv", index=False) logger.info("Saved shortlist to isa_watchlist.csv") return results_df if __name__ == "__main__": find_best_isa_tickers()