File size: 4,363 Bytes
f5cd2d3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
package com.rods.backtestingstrategies.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rods.backtestingstrategies.entity.StockSymbol;
import com.rods.backtestingstrategies.repository.StockSymbolRepository;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * Service to populate the stock_symbols table on startup
 * from a curated JSON file of global exchange tickers.
 *
 * Covers: NASDAQ, NYSE/S&P 500, NSE (India), BSE (India), LSE (UK), TSE (Japan).
 * Runs only when tickers are missing from the DB.
 */
@Service
public class TickerSeederService {

    private final StockSymbolRepository symbolRepository;
    private final ObjectMapper objectMapper;

    @Value("${ticker.seeder.enabled:true}")
    private boolean seederEnabled;

    public TickerSeederService(StockSymbolRepository symbolRepository) {
        this.symbolRepository = symbolRepository;
        this.objectMapper = new ObjectMapper();
    }

    @PostConstruct
    public void seedTickers() {
        if (!seederEnabled) {
            System.out.println("Ticker seeder is disabled.");
            return;
        }

        long existingCount = symbolRepository.count();
        if (existingCount > 0) {
            System.out.println("Ticker database already populated with " + existingCount + " symbols. Skipping seed.");
            return;
        }

        System.out.println("Seeding ticker database from ticker_data.json...");

        try {
            ClassPathResource resource = new ClassPathResource("ticker_data.json");
            InputStream inputStream = resource.getInputStream();
            JsonNode root = objectMapper.readTree(inputStream);
            JsonNode exchanges = root.get("exchanges");

            List<StockSymbol> allSymbols = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();

            for (JsonNode exchange : exchanges) {
                String exchangeName = exchange.get("name").asText();
                String region = exchange.get("region").asText();
                String currency = exchange.get("currency").asText();
                String timezone = exchange.get("timezone").asText();
                String marketOpen = exchange.get("marketOpen").asText();
                String marketClose = exchange.get("marketClose").asText();

                JsonNode tickers = exchange.get("tickers");
                for (JsonNode ticker : tickers) {
                    StockSymbol symbol = new StockSymbol();
                    symbol.setSymbol(ticker.get("symbol").asText());
                    symbol.setName(ticker.get("name").asText());
                    symbol.setType("Equity");
                    symbol.setExchange(exchangeName);
                    symbol.setRegion(region);
                    symbol.setCurrency(currency);
                    symbol.setTimezone(timezone);
                    symbol.setMarketOpen(marketOpen);
                    symbol.setMarketClose(marketClose);
                    symbol.setSector(ticker.has("sector") ? ticker.get("sector").asText() : null);
                    symbol.setIndustry(ticker.has("industry") ? ticker.get("industry").asText() : null);
                    symbol.setMatchScore(1.0);
                    symbol.setLastFetched(now);
                    symbol.setSource("TICKER_SEED");

                    allSymbols.add(symbol);
                }
            }

            symbolRepository.saveAll(allSymbols);
            System.out.println("Successfully seeded " + allSymbols.size() + " tickers across " +
                    exchanges.size() + " exchanges.");

        } catch (IOException e) {
            System.err.println("Failed to seed ticker data: " + e.getMessage());
        }
    }

    /**
     * Manual re-seed: clears all existing symbols and re-imports from JSON.
     * Use this endpoint for manual updates.
     */
    public int reseedTickers() {
        symbolRepository.deleteAll();
        seedTickers();
        return (int) symbolRepository.count();
    }
}