Skip to content

SonicAlgo/fyers-java-sdk

Repository files navigation

Fyers Java SDK

Unofficial Kotlin/Java SDK for the Fyers trading platform. Supports REST APIs and real-time WebSocket streaming.

Maven Central License: MIT Java 11+

Installation

Gradle (Kotlin DSL)

implementation("io.github.sonicalgo:fyers-java-sdk:1.2.0")

Gradle (Groovy)

implementation 'io.github.sonicalgo:fyers-java-sdk:1.2.0'

Maven

<dependency>
    <groupId>io.github.sonicalgo</groupId>
    <artifactId>fyers-java-sdk</artifactId>
    <version>1.2.0</version>
</dependency>

Quick Start

Kotlin
import io.github.sonicalgo.fyers.Fyers
import io.github.sonicalgo.fyers.usecase.*
import io.github.sonicalgo.fyers.common.*
import io.github.sonicalgo.fyers.common.Exchange.*
import io.github.sonicalgo.fyers.util.*

fun main() {
    val fyers = Fyers.builder()
        .appId("your-app-id")
        .accessToken("your-access-token")
        .build()

    // Get user profile
    val profile = fyers.getProfile()
    println("Hello, ${profile.name}!")

    // Place an order using Kotlin DSL
    val orderId = fyers.placeOrder(PlaceOrderParams {
        symbol = NSE.equity("SBIN")
        qty = 1
        type = OrderType.MARKET
        side = OrderSide.BUY
        productType = ProductType.INTRADAY
        validity = OrderValidity.DAY
    })
    println("Order placed: $orderId")

    // Get market quotes
    val quotes = fyers.getQuotes(listOf(NSE.equity("SBIN"), NSE.equity("HDFCBANK")))
    quotes.forEach { quote ->
        // values is nullable - null if symbol is invalid or market data unavailable
        println("${quote.name}: LTP = ${quote.values?.lastPrice}")
    }

    fyers.close()
}
Java
import io.github.sonicalgo.fyers.Fyers;
import io.github.sonicalgo.fyers.usecase.*;
import io.github.sonicalgo.fyers.common.*;
import io.github.sonicalgo.fyers.util.Symbol;

public class Main {
    public static void main(String[] args) {
        Fyers fyers = Fyers.builder()
            .appId("your-app-id")
            .accessToken("your-access-token")
            .build();

        try {
            // Get user profile
            var profile = fyers.getProfile();
            System.out.println("Hello, " + profile.getName() + "!");

            // Place an order using Builder pattern
            var orderId = fyers.placeOrder(new PlaceOrderParamsBuilder()
                .symbol(Symbol.equity(Exchange.NSE, "SBIN"))
                .qty(1)
                .type(OrderType.MARKET)
                .side(OrderSide.BUY)
                .productType(ProductType.INTRADAY)
                .validity(OrderValidity.DAY)
                .build());
            System.out.println("Order placed: " + orderId);
        } finally {
            fyers.close();
        }
    }
}

Note: All subsequent examples assume the SDK is initialized as shown above.

Table of Contents


Why This SDK?

Benefit Description
Type-Safe API Strongly typed enums prevent invalid parameters at compile time
Complete Trading Stack 50+ REST methods: orders, positions, holdings, market data, GTT, eDIS
Built-in TOTP Automatic login with no external authenticator dependencies
2 WebSocket Protocols HSM (quotes, 5-depth), Order stream - pick what you need
Batch Operations Place/modify/cancel up to 10 orders in a single API call
Bandwidth Optimization LITE mode for market data (4 fields vs 20+)
Thread-Safe HTTP client and WebSocket clients safe for concurrent use
Auto-Reconnect Exponential backoff with automatic resubscription
Per-Instance Design Multiple SDK instances for different trading accounts
Unwrapped Responses Methods return data directly, not wrapper objects

Features

REST API (50+ Methods)

  • User: Profile, funds/margin info
  • Orders: Single, multi (batch 10), multi-leg spreads
  • GTT: Place, modify, cancel, query triggered orders
  • Portfolio: Positions, holdings, exit by ID/filter, position conversion
  • Market Data: Quotes, 5-level depth, historical candles, option chains
  • Utilities: Symbol master, market status, SPAN margin calculator

WebSocket Streaming

Client Protocol Best For
MarketFeedClient Binary HSM Quotes, LTP, OHLC, 5-depth (RECOMMENDED)
OrderStreamClient JSON Order/trade/position updates

Authentication

  • OAuth flow with authorization URL generation
  • Automatic TOTP login - built-in RFC 6238 generator
  • Refresh token support with PIN verification
  • Session logout

Developer Experience

  • Builder pattern for SDK configuration
  • Flat API (fyers.placeOrder() not fyers.orders().place())
  • Symbol builder helpers (NSE.equity("SBIN"))
  • Comprehensive input validation
  • Full KDoc with examples

Type-Safe Enums

The SDK provides type-safe enums for all API parameters:

// Order types
OrderType.LIMIT       // 1 - Limit order, executed at specified price or better
OrderType.MARKET      // 2 - Market order, executed at current market price
OrderType.STOP        // 3 - Stop-Loss Market (SL-M), becomes market order when stop price is hit
OrderType.STOP_LIMIT  // 4 - Stop-Loss Limit (SL-L), becomes limit order when stop price is hit

// Order side
OrderSide.BUY   // 1  - Buy order
OrderSide.SELL  // -1 - Sell order

// Product types
ProductType.CNC       // Cash and Carry - For equity delivery, positions carried forward
ProductType.INTRADAY  // Intraday - Positions squared off same day
ProductType.MARGIN    // Margin - For derivatives, positions carried forward
ProductType.CO        // Cover Order - With mandatory stop loss
ProductType.BO        // Bracket Order - With stop loss and take profit
ProductType.MTF       // Margin Trading Facility - For approved symbols only

// Order validity
OrderValidity.DAY     // Valid till end of trading day
OrderValidity.IOC     // Immediate or Cancel - Execute immediately or cancel

// Position side
PositionSide.LONG   // 1  - Long position (bought)
PositionSide.SHORT  // -1 - Short position (sold)
PositionSide.CLOSED // 0  - Closed position

// Segments
Segment.EQUITY     // 10 - Capital Market / Equity
Segment.FNO        // 11 - Equity Derivatives / F&O
Segment.CURRENCY   // 12 - Currency Derivatives
Segment.COMMODITY  // 20 - Commodity Derivatives

// Exchanges
Exchange.NSE  // 10 - National Stock Exchange
Exchange.BSE  // 12 - Bombay Stock Exchange
Exchange.MCX  // 11 - Multi Commodity Exchange

API Reference

All methods are called directly on the Fyers instance:

Method Description
getAuthorizationUrl() Get OAuth URL
validateAuthCode() Exchange code for token
validateRefreshToken() Refresh access token
logout() Invalidate session
login() Auto login with TOTP
getProfile() Get user profile
getFunds() Get fund/margin info
placeOrder() Place single order
placeMultiOrder() Place multiple orders
placeMultiLegOrder() Place multi-leg order
modifyOrder() Modify order
modifyMultiOrder() Modify multiple orders
cancelOrder() Cancel order
cancelMultiOrder() Cancel multiple orders
getOrders() Get order book
getOrderById() Get specific order
getOrdersByTag() Get orders by tag
getTrades() Get trade book
getTradesByTag() Get trades by tag
getPositions() Get positions
exitPositionById() Exit position by ID
exitPositionsByIds() Exit multiple positions
exitAllPositions() Exit all positions
exitPositionsByFilter() Exit by filter
convertPosition() Convert position
cancelPendingOrders() Cancel pending orders
getHoldings() Get holdings
getHistory() Get historical data
getQuotes() Get quotes
getMarketDepth() Get market depth
getOptionChain() Get option chain
getMarketStatus() Get market status
getSymbolMaster() Get symbol master
getSpanMargin() Calculate SPAN margin
getMultiOrderMargin() Calculate multi-order margin
placeGttOrder() Place GTT order
modifyGttOrder() Modify GTT order
cancelGttOrder() Cancel GTT order
getGttOrders() Get GTT orders
generateTpin() Generate TPIN
getEdisDetails() Get eDIS details
initiateEdis() Initiate eDIS
inquireEdis() Inquire eDIS status

Configuration

SDK Configuration

Option Default Description
appId - Your Fyers app ID (required)
accessToken - Access token from authentication (can set later)
loggingEnabled false Enable HTTP request/response logging (logs URL, method, headers, body)
rateLimitRetries 0 Number of retries on rate limit (HTTP 429). Range: 0-5. Uses exponential backoff.
val fyers = Fyers.builder()
    .appId("your-app-id")
    .accessToken("your-access-token")
    .loggingEnabled(true)
    .rateLimitRetries(3)
    .build()

// Update credentials at runtime
fyers.setAccessToken("new-token")
fyers.setAppId("new-app-id")

WebSocket Configuration

Option Default Description
maxReconnectAttempts 5 Maximum reconnection attempts (1-20)
autoReconnectEnabled true Enable automatic reconnection
autoResubscribeEnabled true Auto-resubscribe after reconnect

Authentication

Getting API Credentials

  1. Register at Fyers API Portal
  2. Create an app to get your app_id and app_secret
  3. Set up a redirect URL for OAuth callback

OAuth Flow

val fyers = Fyers.builder()
    .appId("your-app-id")
    .build()

// Step 1: Generate authorization URL
val authUrl = fyers.getAuthorizationUrl(
    redirectUri = "https://your-app.com/callback",
    state = "random-state"
)
// Redirect user to authUrl

// Step 2: Exchange auth code for access token
val tokenData = fyers.validateAuthCode(
    appSecret = "your-app-secret",
    code = "auth-code-from-callback"
)

// Step 3: Configure SDK with access token
fyers.setAccessToken(tokenData.accessToken!!)

Automatic Login (TOTP)

Kotlin:

val fyers = Fyers.builder()
    .appId("your-app-id")
    .build()

val tokenData = fyers.login(
    clientId = "FY12345",
    totpSecret = "your-totp-secret",
    pin = "1234",
    appSecret = "your-app-secret",
    redirectUri = "https://your-app.com/callback"
)
// Access token is automatically configured - ready to use!
val profile = fyers.getProfile()

Java:

TokenData tokenData = fyers.login(
    "FY12345",
    "your-totp-secret",
    "1234",
    "your-app-secret",
    "https://your-app.com/callback"
);

Refresh Token

val newAccessToken = fyers.validateRefreshToken(
    appSecret = "your-app-secret",
    refreshToken = "your-refresh-token",
    pin = "1234"
)
fyers.setAccessToken(newAccessToken)

Logout

// Invalidate the current session
fyers.logout()

REST API Reference

User & Funds

// Get profile
val profile = fyers.getProfile()
println("Name: ${profile.name}")
println("Email: ${profile.emailId}")

// Get funds
val funds = fyers.getFunds()
funds.forEach { fund ->
    println("${fund.title}: ${fund.equityAmount}")
}

Orders

Place Order

Kotlin:

val params = PlaceOrderParams {
    symbol = NSE.equity("SBIN")
    qty = 10
    type = OrderType.LIMIT
    side = OrderSide.BUY
    productType = ProductType.INTRADAY
    validity = OrderValidity.DAY
    limitPrice = 650.0
}
val orderId = fyers.placeOrder(params)

Java:

PlaceOrderParams params = new PlaceOrderParamsBuilder()
    .symbol(Symbol.equity(Exchange.NSE, "SBIN"))
    .qty(10)
    .type(OrderType.LIMIT)
    .side(OrderSide.BUY)
    .productType(ProductType.INTRADAY)
    .validity(OrderValidity.DAY)
    .limitPrice(650.0)
    .build();

String orderId = fyers.placeOrder(params);

Modify Order

Kotlin:

val params = ModifyOrderParams {
    id = orderId
    qty = 15
    type = OrderType.LIMIT
    limitPrice = 655.0
}
fyers.modifyOrder(params)

Java:

ModifyOrderParams params = new ModifyOrderParamsBuilder()
    .id(orderId)
    .qty(15)
    .type(OrderType.LIMIT)
    .limitPrice(655.0)
    .build();

fyers.modifyOrder(params);

Cancel Order

fyers.cancelOrder(orderId)

Multi/Basket Orders

// Place multiple orders (max 10) using DSL
val results = fyers.placeMultiOrder(listOf(
    PlaceOrderParams {
        symbol = NSE.equity("SBIN")
        qty = 10
        type = OrderType.MARKET
        side = OrderSide.BUY
        productType = ProductType.INTRADAY
        validity = OrderValidity.DAY
    },
    PlaceOrderParams {
        symbol = NSE.equity("HDFCBANK")
        qty = 5
        type = OrderType.MARKET
        side = OrderSide.BUY
        productType = ProductType.INTRADAY
        validity = OrderValidity.DAY
    }
))
results.forEach { result ->
    if (result.isSuccess) println("Order placed: ${result.body?.id}")
    else println("Failed: ${result.statusDescription}")
}

// Modify multiple orders
val modifyResults = fyers.modifyMultiOrder(listOf(
    ModifyOrderParams {
        id = "order1"
        type = OrderType.LIMIT
        limitPrice = 100.0
    },
    ModifyOrderParams {
        id = "order2"
        type = OrderType.LIMIT
        limitPrice = 200.0
    }
))

// Cancel multiple orders
val cancelResults = fyers.cancelMultiOrder(listOf("order1", "order2"))

Multi-Leg Order (Spreads)

Kotlin:

val params = PlaceMultiLegOrderParams {
    productType = ProductType.INTRADAY
    orderType = MultiLegOrderType.TWO_LEG
    validity = OrderValidity.IOC
    legs = MultiLegOrderLegs {
        leg1 = MultiLegOrderLeg {
            symbol = NSE.option("NIFTY25JAN2322500CE")
            qty = 50
            side = OrderSide.BUY
            type = OrderType.LIMIT
            limitPrice = 100.0
        }
        leg2 = MultiLegOrderLeg {
            symbol = NSE.option("NIFTY25JAN2322600CE")
            qty = 50
            side = OrderSide.SELL
            type = OrderType.LIMIT
            limitPrice = 80.0
        }
    }
}
val orderId = fyers.placeMultiLegOrder(params)

Java:

PlaceMultiLegOrderParams params = new PlaceMultiLegOrderParamsBuilder()
    .productType(ProductType.INTRADAY)
    .orderType(MultiLegOrderType.TWO_LEG)
    .validity(OrderValidity.IOC)
    .legs(new MultiLegOrderLegsBuilder()
        .leg1(new MultiLegOrderLegBuilder()
            .symbol(Symbol.option(Exchange.NSE, "NIFTY25JAN2322500CE"))
            .qty(50)
            .side(OrderSide.BUY)
            .type(OrderType.LIMIT)
            .limitPrice(100.0)
            .build())
        .leg2(new MultiLegOrderLegBuilder()
            .symbol(Symbol.option(Exchange.NSE, "NIFTY25JAN2322600CE"))
            .qty(50)
            .side(OrderSide.SELL)
            .type(OrderType.LIMIT)
            .limitPrice(80.0)
            .build())
        .build())
    .build();

String orderId = fyers.placeMultiLegOrder(params);

Query Orders

// Get all orders
val orders = fyers.getOrders()
orders.forEach { order ->
    println("${order.id}: ${order.symbol} - ${order.status}")
}

// Get specific order by ID
val order = fyers.getOrderById("2420611000001")

// Get orders by tag
val taggedOrders = fyers.getOrdersByTag("my-strategy")

// Get trades
val trades = fyers.getTrades()
trades.forEach { trade ->
    println("${trade.symbol}: ${trade.tradedQuantity} @ ${trade.tradePrice}")
}

// Get trades by tag
val taggedTrades = fyers.getTradesByTag("my-strategy")

GTT Orders

Kotlin:

// Place GTT order
val placeParams = PlaceGttOrderParams {
    symbol = NSE.equity("SBIN")
    side = OrderSide.BUY
    productType = ProductType.CNC
    orderInfo = GttOrderInfo {
        leg1 = GttOrderLeg {
            price = 605.0
            triggerPrice = 600.0
            qty = 10
        }
    }
}
val gttId = fyers.placeGttOrder(placeParams)

// Get GTT orders
val gttOrders = fyers.getGttOrders()

// Modify GTT order
val modifyParams = ModifyGttOrderParams {
    id = gttId
    orderInfo = GttOrderInfo {
        leg1 = GttOrderLeg {
            price = 610.0
            triggerPrice = 605.0
            qty = 15
        }
    }
}
fyers.modifyGttOrder(modifyParams)

// Cancel GTT order
fyers.cancelGttOrder(gttId)

Java:

// Place GTT order
PlaceGttOrderParams placeParams = new PlaceGttOrderParamsBuilder()
    .symbol(Symbol.equity(Exchange.NSE, "SBIN"))
    .side(OrderSide.BUY)
    .productType(ProductType.CNC)
    .orderInfo(new GttOrderInfoBuilder()
        .leg1(new GttOrderLegBuilder()
            .price(605.0)
            .triggerPrice(600.0)
            .qty(10)
            .build())
        .build())
    .build();

String gttId = fyers.placeGttOrder(placeParams);

// Modify GTT order
ModifyGttOrderParams modifyParams = new ModifyGttOrderParamsBuilder()
    .id(gttId)
    .orderInfo(new GttOrderInfoBuilder()
        .leg1(new GttOrderLegBuilder()
            .price(610.0)
            .triggerPrice(605.0)
            .qty(15)
            .build())
        .build())
    .build();

fyers.modifyGttOrder(modifyParams);

Portfolio

Positions

// Get positions
val positionsData = fyers.getPositions()
positionsData.netPositions.forEach { position ->
    println("${position.symbol}: Qty=${position.netQuantity}, P&L=${position.realizedPl}")
}

// Exit position by ID
fyers.exitPositionById("NSE:SBIN-EQ-INTRADAY")

// Exit multiple positions by IDs
fyers.exitPositionsByIds(listOf("NSE:SBIN-EQ-INTRADAY", "NSE:HDFCBANK-EQ-INTRADAY"))

// Exit all positions
fyers.exitAllPositions()

// Cancel all pending orders (optional: pass position ID to cancel for specific position)
fyers.cancelPendingOrders()

// Exit positions by filter using DSL
fyers.exitPositionsByFilter(ExitPositionByFilterParams {
    segment = listOf(Segment.EQUITY)
    side = listOf(PositionSide.LONG)
    productType = listOf(ProductType.INTRADAY)
})

// Convert position using DSL
fyers.convertPosition(ConvertPositionParams {
    symbol = NSE.equity("SBIN")
    positionSide = PositionSide.LONG
    convertQty = 10
    convertFrom = ProductType.INTRADAY
    convertTo = ProductType.CNC
    overnight = 0
})

Holdings

val holdingsData = fyers.getHoldings()
holdingsData.holdings.forEach { holding ->
    println("${holding.symbol}: Qty=${holding.quantity}, P&L=${holding.profitLoss}")
}

Market Data

Quotes

val quotes = fyers.getQuotes(listOf(NSE.equity("SBIN"), NSE.equity("HDFCBANK")))
quotes.forEach { quote ->
    // values is nullable - null if symbol is invalid or market data unavailable
    println("${quote.name}: LTP=${quote.values?.lastPrice}")
}

Market Depth

val depthMap = fyers.getMarketDepth(
    symbol = NSE.equity("SBIN"),
    includeOhlcv = true
)

Historical Data

Kotlin:

val params = HistoryParams {
    symbol = NSE.equity("SBIN")
    resolution = Resolution.DAY
    rangeFrom = "2025-01-01"
    rangeTo = "2025-12-31"
    dateFormat = DateFormat.FORMATTED
}
val candles = fyers.getHistory(params)
// Returns List<Candle> with timestamp, open, high, low, close, volume, openInterest
candles.forEach { candle ->
    println("${candle.timestamp}: O=${candle.open} H=${candle.high} L=${candle.low} C=${candle.close} V=${candle.volume}")
}

Java:

HistoryParams params = new HistoryParamsBuilder()
    .symbol(Symbol.equity(Exchange.NSE, "SBIN"))
    .resolution(Resolution.DAY)
    .rangeFrom("2025-01-01")
    .rangeTo("2025-12-31")
    .dateFormat(DateFormat.FORMATTED)
    .build();

List<Candle> candles = fyers.getHistory(params);

Option Chain

val optionChainData = fyers.getOptionChain(
    symbol = NSE.index("NIFTY50"),
    strikeCount = 10
)
// Returns flat list of options - filter by optionType: "" (underlying), "CE" (call), "PE" (put)
optionChainData.optionsChain?.forEach { item ->
    when (item.optionType) {
        "" -> println("Underlying: ${item.symbol} LTP=${item.lastPrice}")
        "CE" -> println("Call: Strike=${item.strikePrice} LTP=${item.lastPrice} OI=${item.openInterest}")
        "PE" -> println("Put: Strike=${item.strikePrice} LTP=${item.lastPrice} OI=${item.openInterest}")
    }
}

Symbol Master

// Get symbol master for a segment (NSE_CM, NSE_FO, BSE_CM, MCX_COM, etc.)
val symbols = fyers.getSymbolMaster(SymbolMasterSegment.NSE_FO)
symbols.forEach { (symbol, info) ->
    println("$symbol: Lot=${info.minLotSize}, Tick=${info.tickSize}")
}

Margin

Kotlin:

// SPAN margin calculation
val spanItem = SpanMarginItem {
    symbol = NSE.option("NIFTY25JAN2322500CE")
    qty = 50
    side = OrderSide.BUY
    type = OrderType.MARKET
    productType = ProductType.INTRADAY
}
val marginData = fyers.getSpanMargin(listOf(spanItem))
println("Total margin required: ${marginData.totalMargin}")

// Multi-order margin calculation
val marginItem = MultiOrderMarginItem {
    symbol = NSE.equity("SBIN")
    qty = 100
    side = OrderSide.BUY
    type = OrderType.MARKET
    productType = ProductType.CNC
}
val multiMargin = fyers.getMultiOrderMargin(listOf(marginItem))
println("New order margin: ${multiMargin.newOrderMargin}")

Java:

// SPAN margin calculation
SpanMarginItem spanItem = new SpanMarginItemBuilder()
    .symbol(Symbol.option(Exchange.NSE, "NIFTY25JAN2322500CE"))
    .qty(50)
    .side(OrderSide.BUY)
    .type(OrderType.MARKET)
    .productType(ProductType.INTRADAY)
    .build();

SpanMarginData marginData = fyers.getSpanMargin(List.of(spanItem));

// Multi-order margin calculation
MultiOrderMarginItem marginItem = new MultiOrderMarginItemBuilder()
    .symbol(Symbol.equity(Exchange.NSE, "SBIN"))
    .qty(100)
    .side(OrderSide.BUY)
    .type(OrderType.MARKET)
    .productType(ProductType.CNC)
    .build();

MultiOrderMarginData multiMargin = fyers.getMultiOrderMargin(List.of(marginItem));

EDIS

Kotlin:

// Generate TPIN
fyers.generateTpin()

// Get EDIS details
val details = fyers.getEdisDetails()

// Initiate EDIS transaction
val record = EdisRecord { isinCode = "INE062A01020"; qty = "10"; symbol = NSE.equity("SAIL") }
val cdslForm = fyers.initiateEdis(listOf(record))

// Inquire EDIS status
val inquiry = fyers.inquireEdis("txn-12345")

Java:

// Initiate EDIS transaction
EdisRecord record = new EdisRecordBuilder()
    .isinCode("INE062A01020").qty("10").symbol("NSE:SAIL-EQ")
    .build();

String cdslForm = fyers.initiateEdis(List.of(record));

WebSocket Streaming

The SDK provides two WebSocket clients for real-time data:

Client Protocol Use Case
MarketFeedClient Binary HSM LTP, quotes, 5-level depth (RECOMMENDED)
OrderStreamClient JSON Orders, trades, positions

Which Client Should I Use?

  • For real-time quotes, LTP, OHLC → Use MarketFeedClient (most efficient)
  • For 5-level market depth → Use MarketFeedClient with DataType.DEPTH
  • For order/trade/position updates → Use OrderStreamClient (auto-subscribes on connect)

Tip: MarketFeedClient supports two modes:

  • FULL mode (default): 20+ fields including OHLC, volume, bid/ask
  • LITE mode: Only 4 fields (symbol, ltp, change, changePercent) - saves bandwidth

Market Feed Stream (Recommended)

The Market Feed client uses Fyers' binary HSM protocol for efficient real-time market data.

FULL Mode (default) - Complete market data with 20+ fields:

val marketFeedClient = fyers.createMarketFeedClient(
    maxReconnectAttempts = 5,
    autoReconnectEnabled = true,
    autoResubscribeEnabled = true
)

marketFeedClient.addListener(object : MarketFeedListener {
    override fun onConnected() {
        println("Connected!")
        // Subscribe to quote updates (LTP, OHLC, volume, bid/ask) - QUOTE is default
        marketFeedClient.subscribe(listOf(NSE.equity("SBIN"), NSE.equity("HDFCBANK")))
        // Subscribe to 5-level depth
        marketFeedClient.subscribe(listOf(NSE.equity("SBIN")), DataType.DEPTH)
        // Subscribe to index (use quotes for index symbols)
        marketFeedClient.subscribe(listOf(NSE.index("NIFTY50")))
    }

    override fun onDisconnected(code: Int, reason: String) {
        println("Disconnected: $reason")
    }

    override fun onFullQuoteUpdate(update: MarketQuoteUpdate) {
        // Full data: symbol, ltp, open, high, low, volume, bid/ask, etc. (20+ fields)
        println("${update.symbol}: LTP=${update.ltp} Vol=${update.volume}")
    }

    override fun onFullIndexUpdate(update: MarketIndexUpdate) {
        println("${update.symbol}: LTP=${update.ltp}")
    }

    override fun onDepthUpdate(update: MarketDepthUpdate) {
        println("${update.symbol}: Bids=${update.bids.size} Asks=${update.asks.size}")
    }

    override fun onError(error: Throwable) {
        error.printStackTrace()
    }
})
marketFeedClient.connect()

LITE Mode - Minimal bandwidth with only 4 fields (symbol, ltp, change, changePercent):

val liteClient = fyers.createMarketFeedClient()
liteClient.addListener(object : MarketFeedListener {
    override fun onConnected() {
        liteClient.setMode(DataMode.LITE)  // Switch to LITE mode
        liteClient.subscribe(listOf(NSE.equity("SBIN")))
    }

    override fun onLiteQuoteUpdate(update: LiteQuoteUpdate) {
        // Only 4 fields: symbol, ltp, change, changePercent
        println("${update.symbol}: LTP=${update.ltp} Change=${update.changePercent}%")
    }

    override fun onLiteIndexUpdate(update: LiteIndexUpdate) {
        println("${update.symbol}: LTP=${update.ltp} Change=${update.changePercent}%")
    }
})
liteClient.connect()

Market Feed API:

Method Description
subscribe(symbols) Subscribe to quotes (default)
subscribe(symbols, DataType.DEPTH) Subscribe to 5-level depth
unsubscribe(symbols) Auto-detects type and unsubscribes
setMode(DataMode.LITE) LITE mode - only onLiteQuoteUpdate/onLiteIndexUpdate callbacks
setMode(DataMode.FULL) FULL mode - only onFullQuoteUpdate/onFullIndexUpdate callbacks (default)

Listener Callbacks:

Callback Mode Fields
onFullQuoteUpdate(MarketQuoteUpdate) FULL 20+ fields (LTP, OHLC, volume, bid/ask, etc.)
onLiteQuoteUpdate(LiteQuoteUpdate) LITE 4 fields (symbol, ltp, change, changePercent)
onFullIndexUpdate(MarketIndexUpdate) FULL 8 fields (LTP, OHLC, etc.)
onLiteIndexUpdate(LiteIndexUpdate) LITE 4 fields (symbol, ltp, change, changePercent)
onDepthUpdate(MarketDepthUpdate) Both 5-level bid/ask depth

Order Stream

The Order Stream client auto-subscribes to all update types on connect:

val orderClient = fyers.createOrderStreamClient(
    maxReconnectAttempts = 5,
    autoReconnectEnabled = true
)

// Auto-subscribes to all updates (orders, trades, positions, eDIS)
// Required callbacks: onConnected, onDisconnected, onError
orderClient.addListener(object : OrderStreamListener {
    override fun onConnected() {
        println("Connected!")
    }

    override fun onOrderUpdate(order: WsOrderUpdate) {
        println("Order: ${order.id} - Status: ${order.status}")
    }

    override fun onDisconnected(code: Int, reason: String) {
        println("Disconnected: $reason")
    }

    override fun onError(error: Throwable) {
        error.printStackTrace()
    }
    // Other optional callbacks: onTradeUpdate(), onPositionUpdate(), onEdisUpdate(), etc.
})
orderClient.connect()

// Cleanup
orderClient.close()

Error Handling

All API methods throw FyersApiException on failure:

try {
    val orderId = fyers.placeOrder(params)
} catch (e: FyersApiException) {
    println("Error: ${e.message}")         // Raw response body from API
    println("HTTP Status: ${e.httpStatusCode}")  // HTTP status code (e.g., 401, 429, 500)

    // Helper methods for common error categories
    when {
        e.isRateLimitError -> println("Rate limited, retry later")
        e.isAuthenticationError -> println("Invalid credentials")
        e.isValidationError -> println("Bad request parameters")
        e.isServerError -> println("Server error, try again")
    }
}

Exception Properties:

Property Type Description
message String? Raw response body from the API
httpStatusCode Int? HTTP status code
isRateLimitError Boolean True if HTTP 429 (rate limited)
isAuthenticationError Boolean True if HTTP 401/403
isValidationError Boolean True if HTTP 400
isServerError Boolean True if HTTP 5xx

Symbol Format

Type Format Examples
Equity EXCHANGE:SYMBOL-EQ NSE:SBIN-EQ, BSE:RELIANCE-EQ
Index EXCHANGE:SYMBOL-INDEX NSE:NIFTY50-INDEX, NSE:BANKNIFTY-INDEX
Futures EXCHANGE:SYMBOLYYMONTHFUT NSE:SBIN25JANFUT, NSE:NIFTY25JANFUT
Options EXCHANGE:SYMBOLYYMONTHDDSTRIKETYPE NSE:SBIN25JAN19650CE, NSE:NIFTY25JAN2322500PE
Commodity MCX:SYMBOLYYMONTHFUT MCX:GOLD25FEBFUT
Currency NSE:PAIRYYMONTHFUT NSE:USDINR25JANFUT

Format Notes:

  • YY = 2-digit year (e.g., 25 for 2025)
  • MONTH = 3-letter month in uppercase (e.g., JAN, FEB, MAR)
  • DD = 2-digit day (for weekly options)
  • STRIKE = Strike price without decimal
  • TYPE = Option type (CE for Call, PE for Put)

Symbol Builder

Recommended: Use symbol builder instead of raw strings.

Kotlin:

import io.github.sonicalgo.fyers.common.Exchange.*
import io.github.sonicalgo.fyers.util.*

NSE.equity("SBIN")               // "NSE:SBIN-EQ"
NSE.index("NIFTY50")             // "NSE:NIFTY50-INDEX"
NSE.future("NIFTY25JANFUT")      // "NSE:NIFTY25JANFUT"
NSE.option("NIFTY25JAN2322500PE")   // "NSE:NIFTY25JAN2322500PE"

Java:

import io.github.sonicalgo.fyers.util.Symbol;
import io.github.sonicalgo.fyers.common.Exchange;

Symbol.equity(Exchange.NSE, "SBIN");               // "NSE:SBIN-EQ"
Symbol.index(Exchange.NSE, "NIFTY50");             // "NSE:NIFTY50-INDEX"
Symbol.future(Exchange.NSE, "NIFTY25JANFUT");      // "NSE:NIFTY25JANFUT"
Symbol.option(Exchange.NSE, "NIFTY25JAN2322500PE");   // "NSE:NIFTY25JAN2322500PE"
Method Suffix Example Output
equity() -EQ NSE:SBIN-EQ
index() -INDEX NSE:NIFTY50-INDEX
future() none NSE:NIFTY25JANFUT
option() none NSE:NIFTY25JAN2322500PE

Requirements

  • JDK 11 or higher
  • Kotlin 1.9+ (for Kotlin projects)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Links

Disclaimer

This is an unofficial SDK and is not affiliated with, endorsed by, or supported by Fyers. Use at your own risk. Always test thoroughly in a sandbox/paper trading environment before using in production.

About

Unofficial Kotlin/Java SDK for the Fyers trading platform. Supports REST APIs and real-time WebSocket streaming.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages