how to migrate from zerodha kite to angelone

Migrate to angelone java sdk. Append _AO to name: package mts;

import com.zerodhatech.kiteconnect.KiteConnect;
import com.zerodhatech.kiteconnect.kitehttp.exceptions.KiteException;
import com.zerodhatech.models.HistoricalData;
import com.zerodhatech.models.Instrument;

import java.awt.Toolkit;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Adaptive Channel + Volumized Bullish Order Blocks Buy Scanner
 * Buy when: price above Adaptive Median Line + recent bullish OB respected
 */
public class AdaptiveChannelVolOBBuyScanner {

    // ── Configuration ───────────────────────────────────────────────────────────
    private static final double DEV_MULTIPLIER      = 2.0;
    private static final int    ATR_PERIOD          = 10;
    private static final float  MAX_ATR_MULT_OB     = 3.5f;

    private static final int    SWING_LENGTH        = 10;
    private static final int    MAX_RECENT_BULL_OB  = 5;

    // Filters
    private static final int    RSI_PERIOD          = 14;
    private static final double RSI_MIN_BUY         = 48.0;
    private static final int    ADX_PERIOD          = 14;
    private static final double ADX_MIN             = 20.0;
    private static final int    VOL_PERIOD          = 20;
    private static final double VOL_MULTIPLIER      = 1.35;

    // Kite Connect
    private static final String API_KEY    = "g9wl2rucy7fgl79g";
    private static final String USER_ID    = "XCY173";
    private static final String TOKEN_FILE = "tokens.json";

    private static KiteConnect kiteConnect;
    private static final SimpleDateFormat LOG_FMT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static PrintWriter logWriter;
    private static final Map<String, String> symbolToToken = new HashMap<>();

    // Watchlist
    private static final String[] SYMBOLS = {
        "RELIANCE","HDFCBANK","ICICIBANK","INFY","TCS","KOTAKBANK","HINDUNILVR","ITC","SBIN","BHARTIARTL",
        "LT","AXISBANK","BAJFINANCE","MARUTI","ASIANPAINT","SUNPHARMA","TITAN","HCLTECH","TATAMOTORS","ULTRACEMCO",
        "BAJAJFINSV","WIPRO","NESTLEIND","TECHM","JSWSTEEL","POWERGRID","NTPC","ONGC","ADANIENT","ADANIPORTS",
        "COALINDIA","TATASTEEL","M&M","DIVISLAB","DRREDDY","APOLLOHOSP","BRITANNIA","CIPLA","HEROMOTOCO","EICHERMOT",
        "SHREECEM","GRASIM","BPCL","IOC","HDFCLIFE","SBILIFE","BAJAJ-AUTO","TRENT","ZOMATO","ADANIGREEN",
        "PIDILITIND","GODREJCP","VBL","DMART","ATGL","SRF","BERGEPAINT","HAVELLS","ABB","SIEMENS",
        "DABUR","MARICO","COLPAL","LTIM","TORNTPHARM","INDUSINDBK","PNB","BANKBARODA","CANBK","UNIONBANK",
        "TATAPOWER","GAIL","VEDL","HINDALCO","JINDALSTEL","ACC","AMBUJACEM","UPL","LUPIN","CHOLAFIN"
    };

    public static void main(String[] args) {
        try {
            logWriter = new PrintWriter(new FileWriter("adaptive_volob_buy_scanner.log", true));
            System.out.println("=== ADAPTIVE CHANNEL + VOLUMIZED BULLISH OB BUY SCANNER ===");
            log("SCAN STARTED @ " + LOG_FMT.format(new Date()));

            if (!loadSession()) return;
            loadInstrumentTokens();

            int hits = 0;
            for (String symbol : SYMBOLS) {
                try {
                    if (checkAdaptiveChannelVolOBBuy(symbol.trim())) hits++;
                    Thread.sleep(1200);
                } catch (Exception ignored) {}
            }

            System.out.println("\nSCAN COMPLETE — " + hits + " setups found");
            log("SCAN COMPLETE — " + hits + " ADAPTIVE + VOL OB BUY setups");
            logWriter.close();

            if (hits > 0) beep(3);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // ── Core Logic ──────────────────────────────────────────────────────────────

    private static boolean checkAdaptiveChannelVolOBBuy(String symbol) throws Exception {
        String token = symbolToToken.get(symbol.toUpperCase());
        if (token == null) return false;

        HistoricalData data = fetchDailyData(token);
        List<HistoricalData> candles = data.dataArrayList;
        int n = candles.size();
        if (n < 300) return false;

        double[] open   = new double[n];
        double[] high   = new double[n];
        double[] low    = new double[n];
        double[] close  = new double[n];
        long[]   volume = new long[n];

        for (int i = 0; i < n; i++) {
            HistoricalData c = candles.get(i);
            open[i]   = c.open;
            high[i]   = c.high;
            low[i]    = c.low;
            close[i]  = c.close;
            volume[i] = c.volume;
        }

        double[] atr = calculateATR(high, low, close, ATR_PERIOD);

        // 1. Approximate Adaptive Median Line (last known value)
        double medianLineApprox = approximateAdaptiveMedian(close, n);
        if (Double.isNaN(medianLineApprox)) return false;

        int last = n - 1;
        if (close[last] <= medianLineApprox) return false; // must be ABOVE median line

        // 2. Recent Bullish Order Blocks
        List<BullishOrderBlock> bullOBs = findRecentBullishOrderBlocks(
                open, high, low, close, volume, atr, n, SWING_LENGTH);

        if (bullOBs.isEmpty()) return false;

        BullishOrderBlock recentOB = bullOBs.get(0);

        // Respect / Retest condition
        boolean respectingOB = close[last] >= recentOB.bottom && close[last] <= recentOB.top * 1.015;
        boolean freshRetest  = close[last-1] < recentOB.top && close[last] >= recentOB.bottom;

        if (!respectingOB && !freshRetest) return false;

        // No invalidation
        boolean invalidated = low[last] < recentOB.bottom;
        if (invalidated) return false;

        // 3. Classic Filters
        double[] rsi = calculateRSI(close, RSI_PERIOD);
        if (rsi[last] < RSI_MIN_BUY) return false;

        double[] adx = calculateADX(high, low, close, ADX_PERIOD);
        if (adx[last] < ADX_MIN) return false;

        double avgVol = 0;
        int volCount = Math.min(VOL_PERIOD, n);
        for (int i = n - volCount; i < n; i++) avgVol += volume[i];
        avgVol /= volCount;

        if (volume[last] < avgVol * VOL_MULTIPLIER) return false;

        // ── Signal Confirmed ────────────────────────────────────────────────────
        double entry = close[last];
        double sl    = recentOB.bottom - atr[last] * 0.4;
        double risk  = entry - sl;
        double tp1   = entry + risk * 2.0;
        double tp2   = entry + risk * 3.2;

        String msg = String.format(
            "ADAPTIVE + VOL OB BUY ▲ | %s.NS | Entry ~%.2f | " +
            "Above Median | OB [%.2f–%.2f] Vol:%.0f | SL %.2f | TP1 %.2f / TP2 %.2f | " +
            "RSI %.1f | ADX %.1f | Vol %.1fx",
            symbol.toUpperCase(), entry,
            recentOB.bottom, recentOB.top, recentOB.volume,
            sl, tp1, tp2,
            rsi[last], adx[last], (double)volume[last]/avgVol
        );

        System.out.println(msg);
        log(msg);

        beep(2);
        return true;
    }

    // ── Very Simplified Adaptive Median Approximation ───────────────────────────
    // (real Pine uses regression over multiple lengths → we approximate with longest good fit)
    private static double approximateAdaptiveMedian(double[] close, int n) {
        if (n < 250) return Double.NaN;

        // We try several periods (like 100,200,300,400,500)
        int[] periods = {100, 150, 200, 250, 300, 350, 400, 450, 500};
        double bestR = -1;
        double bestMedian = Double.NaN;

        for (int period : periods) {
            if (n < period + 10) continue;

            double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0;
            int count = period;

            for (int i = 0; i < count; i++) {
                int idx = n - count + i;
                double x = i + 1;
                double y = Math.log(close[idx]);
                sumX += x;
                sumY += y;
                sumXY += x * y;
                sumXX += x * x;
            }

            double slope = (count * sumXY - sumX * sumY) / (count * sumXX - sumX * sumX);
            double intercept = (sumY - slope * sumX) / count;

            // Pearson R approximation
            double r = Math.abs(slope) > 0.0001 ? 0.85 : 0.4; // rough proxy

            if (r > bestR) {
                bestR = r;
                // Last point of the regression line (median approx)
                double lastX = count;
                bestMedian = Math.exp(intercept + slope * lastX);
            }
        }

        return bestMedian;
    }

    // ── Bullish Order Block Detection (same as previous) ────────────────────────

    static class BullishOrderBlock {
        double top;
        double bottom;
        long volume;
        int startBarIndex;

        BullishOrderBlock(double top, double bottom, long volume, int startBar) {
            this.top = top;
            this.bottom = bottom;
            this.volume = volume;
            this.startBarIndex = startBar;
        }
    }

    private static List<BullishOrderBlock> findRecentBullishOrderBlocks(
            double[] open, double[] high, double[] low, double[] close, long[] volume,
            double[] atr, int n, int swingLen) {

        List<BullishOrderBlock> bullOBs = new ArrayList<>();

        for (int i = swingLen * 2; i < n - 1; i++) {
            boolean potentialReversal = close[i] > close[i-1] && close[i-1] < close[i-2];

            if (!potentialReversal) continue;

            int lowIdx = i - 1;
            for (int k = 1; k <= swingLen && (i - k - 1) >= 0; k++) {
                if (low[i - k] < low[lowIdx]) lowIdx = i - k;
            }

            double obBottom = Math.min(low[lowIdx], low[lowIdx + 1]);
            double obTop = Math.max(open[lowIdx], close[lowIdx]);

            double obSize = obTop - obBottom;
            if (obSize > atr[i] * MAX_ATR_MULT_OB) continue;

            long obVol = volume[lowIdx] + volume[lowIdx + 1] + volume[lowIdx + 2];

            bullOBs.add(new BullishOrderBlock(obTop, obBottom, obVol, lowIdx));

            if (bullOBs.size() >= MAX_RECENT_BULL_OB) break;
        }

        bullOBs.sort((a, b) -> Integer.compare(b.startBarIndex, a.startBarIndex));
        return bullOBs;
    }

    // ── Technical Indicators (RSI, ADX, ATR) ────────────────────────────────────
    // (same implementations as in previous scanners)

    private static double[] calculateRSI(double[] close, int period) {
        int n = close.length;
        double[] rsi = new double[n];
        if (n < period + 1) return rsi;

        double gain = 0, loss = 0;
        for (int i = 1; i <= period; i++) {
            double chg = close[i] - close[i - 1];
            if (chg > 0) gain += chg; else loss -= chg;
        }
        double avgGain = gain / period;
        double avgLoss = loss / period;
        rsi[period] = avgLoss == 0 ? 100 : 100 - (100 / (1 + avgGain / avgLoss));

        for (int i = period + 1; i < n; i++) {
            double chg = close[i] - close[i - 1];
            double cg = chg > 0 ? chg : 0;
            double cl = chg < 0 ? -chg : 0;
            avgGain = (avgGain * (period - 1) + cg) / period;
            avgLoss = (avgLoss * (period - 1) + cl) / period;
            rsi[i] = avgLoss == 0 ? 100 : 100 - (100 / (1 + avgGain / avgLoss));
        }
        return rsi;
    }

    private static double[] calculateADX(double[] high, double[] low, double[] close, int period) {
        int n = high.length;
        double[] adx = new double[n];
        double[] plusDI = new double[n];
        double[] minusDI = new double[n];

        for (int i = 1; i < n; i++) {
            double up = high[i] - high[i - 1];
            double down = low[i - 1] - low[i];
            plusDI[i] = (up > down && up > 0) ? up : 0;
            minusDI[i] = (down > up && down > 0) ? down : 0;
        }

        double[] smoothedPlus  = ema(plusDI, period);
        double[] smoothedMinus = ema(minusDI, period);
        double[] atrArr        = atr(high, low, close, period);

        for (int i = 0; i < n; i++) {
            plusDI[i]  = 100 * smoothedPlus[i]  / (atrArr[i] == 0 ? 1 : atrArr[i]);
            minusDI[i] = 100 * smoothedMinus[i] / (atrArr[i] == 0 ? 1 : atrArr[i]);
        }

        double[] dx = new double[n];
        for (int i = 0; i < n; i++) {
            double diff = Math.abs(plusDI[i] - minusDI[i]);
            double sum  = plusDI[i] + minusDI[i];
            dx[i] = sum == 0 ? 0 : 100 * diff / sum;
        }

        return ema(dx, period);
    }

    private static double[] ema(double[] src, int period) {
        int n = src.length;
        double[] ema = new double[n];
        double k = 2.0 / (period + 1);
        ema[0] = src[0];
        for (int i = 1; i < n; i++) {
            ema[i] = src[i] * k + ema[i-1] * (1 - k);
        }
        return ema;
    }

    private static double[] calculateATR(double[] high, double[] low, double[] close, int period) {
        return atr(high, low, close, period);
    }

    private static double[] atr(double[] high, double[] low, double[] close, int period) {
        int n = high.length;
        double[] tr = new double[n];
        tr[0] = high[0] - low[0];
        for (int i = 1; i < n; i++) {
            tr[i] = Math.max(high[i] - low[i],
                    Math.max(Math.abs(high[i] - close[i-1]), Math.abs(low[i] - close[i-1])));
        }
        return ema(tr, period);
    }

    // ── Kite & Logging ──────────────────────────────────────────────────────────

    private static boolean loadSession() { /* same as previous */ 
        try (FileReader fr = new FileReader(TOKEN_FILE)) {
            org.json.JSONObject json = new org.json.JSONObject(new org.json.JSONTokener(fr));
            kiteConnect = new KiteConnect(API_KEY);
            kiteConnect.setUserId(USER_ID);
            kiteConnect.setAccessToken(json.getString("access_token"));
            System.out.println("Session loaded successfully");
            return true;
        } catch (Exception e) {
            System.out.println("Failed to load session: " + e.getMessage());
            return false;
        }
    }

    private static void loadInstrumentTokens() { /* same as previous */ 
        try {
            System.out.println("Downloading NSE instrument list...");
            List<Instrument> instruments = kiteConnect.getInstruments("NSE");
            for (Instrument i : instruments) {
                if ("EQ".equals(i.instrument_type)) {
                    symbolToToken.put(i.tradingsymbol.toUpperCase(), String.valueOf(i.instrument_token));
                }
            }
            System.out.println("Loaded " + symbolToToken.size() + " equity tokens");
        } catch (Exception e) {
            System.out.println("Failed to load instruments: " + e.getMessage());
        }
    }

    private static HistoricalData fetchDailyData(String token) throws KiteException, IOException {
        Calendar from = Calendar.getInstance();
        from.add(Calendar.YEAR, -4);
        Calendar to = Calendar.getInstance();
        return kiteConnect.getHistoricalData(from.getTime(), to.getTime(), token, "day", false, false);
    }

    private static void log(String msg) {
        String line = LOG_FMT.format(new Date()) + " | " + msg;
        System.out.println(line);
        if (logWriter != null) {
            logWriter.println(line);
            logWriter.flush();
        }
    }

    private static void beep(int times) {
        for (int i = 0; i < times; i++) {
            Toolkit.getDefaultToolkit().beep();
            try { Thread.sleep(400); } catch (Exception ignored) {}
        }
    }
}

Comments

Popular posts from this blog

OVERSOLD BY LINEAR REGRESSION

Top No-Code Algo Trading Platforms in India (2025) – Full Comparison & Ranking

OVERSOLD BY LINEAR REGRESSION