fyers
¶
Fyers ticks.
A Fyers tick names its instrument by symbol - NSE:SBIN-EQ, MCX:CRUDEOIL26SEPFUT - rather than by
token. unified.broker_mappings stores that symbol as Fyers's order symbol beside its numeric
token, so the resolver translates one to the other before searching. The symbol's prefix gives the
exchange and its shape the kind: -INDEX is an index, a symbol ending in FUT, CE or PE a derivative on
NSE and BSE, anything else there cash; everything on MCX is a derivative.
Nothing Fyers streams is stored yet - its raw tick table is empty - so every fact below is from its protocol rather than from a measurement, and the broker stays unverified until a live session:
prev_close_priceis named for what it is, and is taken as the previous close at every hour.- MCX quantities are taken to be lots, as at every broker measured.
- The last traded and exchange feed times are epochs.
Currency derivatives are left out. Fyers scales prices by a precision and multiplier per instrument that arrive with the subscription, and the market feed does not read them yet, so it divides every price by 100 - right for two-decimal instruments, a hundred times wrong for four-decimal currency pairs. Refusing those instruments writes nothing rather than something wrong; they return once the feed reads its scale.
Classes:
| Name | Description |
|---|---|
FyersTickNormalizer |
Normalizes Fyers ticks. |
FyersTickNormalizer
¶
Bases: TickNormalizer
Normalizes Fyers ticks.
Build the lookup from each Fyers exchange prefix and instrument family to the canonical segments it can hold.
Every prefix in EXCHANGES gets an entry for the cash, index and derivative families. Currency derivative segments are left out of the derivative entry, because the market feed does not yet scale Fyers currency prices correctly, so those instruments are refused rather than resolved.
Example programs
"""Places Fyers feed tokens, which are ticker symbols, on the canonical segments they can be in.
A Fyers tick names its instrument by the Fyers symbol rather than by a number, so the key carries no broker token: it carries the symbol as `order_symbol`, which the resolver turns into a token through the broker mappings. The normalizer decides the family from the symbol itself: MCX and names ending in FUT, CE or PE are derivatives, names ending in -INDEX are indices, and everything else is cash. An exchange Fyers does not serve, or a prefix with no name after it, prints `None`.
The normalizer only works on the text of each token, so the program needs no Redis, database, network or stand-in of any kind. Each output line shows a token as the feed spells it, then the broker token that `unified.broker_mappings` is searched with, the order symbol when the broker names instruments by symbol, and how many canonical segments the search is limited to, with the first of them. A token the normalizer cannot place prints `None`.
Run it from the project root:
python examples/stock_brokers/instruments/ticks/fyers/FyersTickNormalizer/example_1_placing_feed_tokens.py
"""
from stock_brokers.instruments.ticks.fyers import (
FyersTickNormalizer,
)
class PlacingFeedTokensExample:
"""Asks the Fyers normalizer where each of a few feed tokens belongs.
Attributes:
normalizer (FyersTickNormalizer): The normalizer being shown.
tokens (list): The tokens to place, spelled as the feed spells them.
"""
def __init__(self):
"""Builds the normalizer and the tokens to place.
Returns:
None: This method returns nothing.
"""
self.normalizer = FyersTickNormalizer()
self.tokens = [
'NSE:SBIN-EQ',
'NSE:NIFTY50-INDEX',
'NSE:NIFTY26SEPFUT',
'MCX:CRUDEOIL26OCTFUT',
'LSE:VOD',
'NSE:',
]
def describe(self, feed_key):
"""Describes a feed key in one line.
Args:
feed_key (FeedKey | None): The key the normalizer returned.
Returns:
str: The description.
"""
if feed_key is None:
return 'None'
segment_count = len(feed_key.segments)
first_segment = feed_key.segments[0]
return f'broker_token={feed_key.broker_token!r} order_symbol={feed_key.order_symbol!r} segments={segment_count} starting with {first_segment}'
def run(self):
"""Prints where each token belongs.
Returns:
None: This method returns nothing.
"""
print(f'Broker: {FyersTickNormalizer.BROKER_NAME}')
for token in self.tokens:
feed_key = self.normalizer.feed_key(token)
print(f'{token!r} -> {self.describe(feed_key)}')
if __name__ == '__main__':
PlacingFeedTokensExample().run()
It prints:
Broker: fyers
'NSE:SBIN-EQ' -> broker_token=None order_symbol='NSE:SBIN-EQ' segments=6 starting with nse_equities
'NSE:NIFTY50-INDEX' -> broker_token=None order_symbol='NSE:NIFTY50-INDEX' segments=4 starting with nse_equity_indices
'NSE:NIFTY26SEPFUT' -> broker_token=None order_symbol='NSE:NIFTY26SEPFUT' segments=12 starting with nse_fixed_income_futures
'MCX:CRUDEOIL26OCTFUT' -> broker_token=None order_symbol='MCX:CRUDEOIL26OCTFUT' segments=12 starting with mcx_fixed_income_futures
'LSE:VOD' -> None
'NSE:' -> None
"""Normalizes one Fyers tick for SBIN on NSE, whose `close` is trusted at every hour.
Fyers names the instrument by symbol, so the program prints the order symbol the feed key carries. The plan's broker token, 3045, is what the resolver would have found for that symbol in the broker mappings. Fyers' `close` is always the previous session's close, so `reported_close` is kept both before and after the session ends.
The plan that `normalize` applies is normally compiled by `TickResolver` from the mapping cache. This program builds it by hand with the same rules, asking the normalizer how it reports each quantity field and when its close may be trusted, so it needs no database. The tick is shaped like the ones the broker's market feed publishes, with fixed times, so the output is the same on every run. The program normalizes the tick twice, once as received before the session's close and once as received after it, which only changes whether `reported_close` is kept. Order book levels are printed as (price, quantity, orders).
Run it from the project root:
python examples/stock_brokers/instruments/ticks/fyers/FyersTickNormalizer/example_2_a_share_named_by_symbol.py
"""
import datetime
import zoneinfo
from stock_brokers.instruments.ticks import base
from stock_brokers.instruments.ticks.base import (
InstrumentPlan,
)
from stock_brokers.instruments.ticks.fyers import (
FyersTickNormalizer,
)
from stock_brokers.instruments.ticks.utilities import sessions
INDIA = zoneinfo.ZoneInfo('Asia/Kolkata')
class StateBankTickExample:
"""Normalizes one Fyers tick through a hand-built plan and prints the result.
Attributes:
normalizer (FyersTickNormalizer): The normalizer being shown.
received_at (float): When the tick was received, in epoch seconds.
tick (dict): The tick as the market feed published it.
plan (InstrumentPlan): The plan for the tick's instrument.
"""
def __init__(self):
"""Builds the normalizer, the tick and its plan.
Returns:
None: This method returns nothing.
"""
self.normalizer = FyersTickNormalizer()
received = datetime.datetime(2026, 9, 15, 11, 5, tzinfo=INDIA)
self.received_at = received.timestamp()
self.tick = {
'instrument_token': 'NSE:SBIN-EQ',
'last_price': 812.35,
'last_quantity': 40,
'average_price': 810.92,
'volume': 6320415,
'buy_quantity': 812640,
'sell_quantity': 790115,
'ohlc': {
'open': 806.0,
'high': 813.9,
'low': 805.2,
'close': 804.55,
},
'oi': None,
'oi_day_high': None,
'oi_day_low': None,
'last_trade_time': self.received_at - 2.0,
'exchange_timestamp': self.received_at - 1.0,
'received_at': self.received_at,
'depth': {
'buy': [
{
'price': 812.3,
'quantity': 1500,
'orders': 12,
},
{
'price': 812.25,
'quantity': 820,
'orders': 7,
},
{
'price': 812.2,
'quantity': 2300,
'orders': 15,
},
{
'price': 812.15,
'quantity': 640,
'orders': 5,
},
{
'price': 812.1,
'quantity': 1910,
'orders': 11,
},
],
'sell': [
{
'price': 812.35,
'quantity': 700,
'orders': 6,
},
{
'price': 812.4,
'quantity': 1340,
'orders': 10,
},
{
'price': 812.45,
'quantity': 980,
'orders': 8,
},
{
'price': 812.5,
'quantity': 4100,
'orders': 21,
},
{
'price': 812.55,
'quantity': 560,
'orders': 4,
},
],
},
}
self.plan = self.build_plan()
def build_plan(self):
"""Compiles the plan for the tick's instrument the way the resolver would.
Returns:
InstrumentPlan: The plan.
"""
exchange = 'nse'
segment = 'nse_equities'
lot_size = 1
broker_lot_size = 1
multipliers = {}
for field in base.QUANTITY_FIELDS:
basis = self.normalizer.quantity_basis(exchange, field)
if basis == base.BASIS_LOTS:
multipliers[field] = lot_size
elif basis == base.BASIS_BROKER_LOTS:
multipliers[field] = lot_size // broker_lot_size
else:
multipliers[field] = 1
identity = {
'exchange': 'nse',
'segment': 'nse_equities',
'shape': 'security',
'symbol': 'SBIN',
'underlying_symbol': None,
'expiry_date': None,
'strike_price': None,
'option_type': None,
}
instrument_id = '11111111-1111-5111-8111-000000000104'
broker_token = '3045'
return InstrumentPlan(
instrument_id=instrument_id,
broker=FyersTickNormalizer.BROKER_NAME,
broker_token=broker_token,
exchange=exchange,
segment=segment,
shape=identity['shape'],
session=sessions.session_for(segment),
lot_size=lot_size,
multipliers=multipliers,
price_decimals=2,
negative_prices=False,
close_policy=self.normalizer.close_policy(exchange),
has_open_interest=identity['shape'] != 'security',
trusts_last_trade_time=FyersTickNormalizer.TRUSTS_LAST_TRADE_TIME,
trusts_exchange_time=FyersTickNormalizer.TRUSTS_EXCHANGE_TIME,
identity_json=base.identity_json(
instrument_id,
FyersTickNormalizer.BROKER_NAME,
broker_token,
identity,
lot_size,
),
)
def run(self):
"""Prints the feed key, the plan's rules and the normalized values.
Returns:
None: This method returns nothing.
"""
token = self.tick['instrument_token']
feed_key = self.normalizer.feed_key(token)
print(f'Token {token!r}: broker_token={feed_key.broker_token!r} order_symbol={feed_key.order_symbol!r}')
volume_basis = self.normalizer.quantity_basis(self.plan.exchange, 'volume')
print(f'Volume on {self.plan.exchange} is reported in {volume_basis}, multiplier {self.plan.multipliers["volume"]}')
print(f'Close policy on {self.plan.exchange}: {self.normalizer.close_policy(self.plan.exchange)}')
before_close = self.normalizer.normalize(self.tick, self.plan, True)
print('Normalized, received before the close:')
for name, value in before_close.items():
print(f' {name}: {value}')
after_close = self.normalizer.normalize(self.tick, self.plan, False)
print(f'reported_close when received after the close: {after_close["reported_close"]}')
if __name__ == '__main__':
StateBankTickExample().run()
It prints:
Token 'NSE:SBIN-EQ': broker_token=None order_symbol='NSE:SBIN-EQ'
Volume on nse is reported in units, multiplier 1
Close policy on nse: always
Normalized, received before the close:
last_price: 812.35
last_quantity: 40
average_price: 810.92
volume: 6320415
buy_quantity: 812640
sell_quantity: 790115
open: 806.0
high: 813.9
low: 805.2
reported_close: 804.55
oi: None
oi_day_high: None
oi_day_low: None
last_trade_time: 1789450498.0
exchange_time: 1789450499.0
bids: [(812.3, 1500, 12), (812.25, 820, 7), (812.2, 2300, 15), (812.15, 640, 5), (812.1, 1910, 11)]
asks: [(812.35, 700, 6), (812.4, 1340, 10), (812.45, 980, 8), (812.5, 4100, 21), (812.55, 560, 4)]
reported_close when received after the close: 804.55
Methods:
| Name | Description |
|---|---|
feed_key |
The order symbol and segments for a Fyers symbol. |
tick_spelling |
A subscription-set token spelled the way the feed spells it on ticks. |
quantity_basis |
Whether the broker reports a quantity field in lots or units on an exchange. |
close_policy |
When the broker's |
normalize |
Apply a plan to one tick. |
Source code in stock_brokers/instruments/ticks/fyers.py
feed_key
¶
The order symbol and segments for a Fyers symbol.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
instrument_token
|
str
|
The tick's |
required |
Returns:
| Type | Description |
|---|---|
FeedKey | None
|
The key, carrying the symbol as the order symbol, or None for an unknown exchange. |
Example usage
Source code in stock_brokers/instruments/ticks/fyers.py
tick_spelling
¶
A subscription-set token spelled the way the feed spells it on ticks.
Plans are filed under the tick's spelling, because that is what the per-tick path looks up. A subscription set holds strings in the spelling the broker's quote feed subscribes with, which is not always the tick's: Kite ticks carry an integer, Dhan ticks a numeric segment code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
subscription_token
|
str
|
A member of |
required |
Returns:
| Type | Description |
|---|---|
int | str | None
|
The tick's spelling, or None for a token this normalizer cannot place. |
Example usage
print(f"Tick spelling of 'NSE-2885': {self.normalizer.tick_spelling('NSE-2885')!r}")
Source code in stock_brokers/instruments/ticks/base.py
quantity_basis
¶
Whether the broker reports a quantity field in lots or units on an exchange.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exchange
|
str
|
Canonical exchange. |
required |
field
|
str
|
One of QUANTITY_FIELDS. |
required |
Returns:
| Type | Description |
|---|---|
str
|
BASIS_UNITS, BASIS_LOTS or BASIS_BROKER_LOTS. |
Example usage
Source code in stock_brokers/instruments/ticks/base.py
close_policy
¶
When the broker's close is the previous session's close on an exchange.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exchange
|
str
|
Canonical exchange. |
required |
Returns:
| Type | Description |
|---|---|
str
|
One of the CLOSE_* policies. |
Example usage
print(f'{exchange} close policy: {self.normalizer.close_policy(exchange)}')
return InstrumentPlan(
instrument_id='11111111-1111-5111-8111-000000000102',
broker='imaginary',
broker_token='2885',
exchange=exchange,
segment=segment,
shape=shape,
session=sessions.session_for(segment),
lot_size=lot_size,
multipliers=multipliers,
price_decimals=2,
negative_prices=shape != 'security' and exchange == 'mcx',
close_policy=self.normalizer.close_policy(exchange),
has_open_interest=shape != 'security',
trusts_last_trade_time=True,
trusts_exchange_time=True,
identity_json='"instrument_id":"11111111-1111-5111-8111-000000000102"',
)
Source code in stock_brokers/instruments/ticks/base.py
normalize
¶
Apply a plan to one tick.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tick
|
dict
|
A tick as the broker's market feed published it. |
required |
plan
|
InstrumentPlan
|
The compiled plan for the tick's token. |
required |
before_trading_close
|
bool
|
Whether the tick was received before its session's close, for the close policy. |
required |
Returns:
| Type | Description |
|---|---|
dict | None
|
The normalized values, or None when the tick carries no usable last price. Keys are last_price, last_quantity, average_price, volume, buy_quantity, sell_quantity, open, high, low, reported_close, oi, oi_day_high, oi_day_low, last_trade_time, exchange_time, bids and asks, where bids and asks are lists of (price, quantity, orders) best first. |
Example usage
values = self.normalizer.normalize(
{
'last_price': -12.5,
'volume': 400,
'oi': 900,
'received_at': self.received_at,
},
future,
True,
)
outcome = self.normalizer.normalize(
{
'last_price': last_price,
'received_at': self.received_at,
},
share,
True,
)
Source code in stock_brokers/instruments/ticks/base.py
_instant
¶
A broker timestamp as a true epoch, or None when it is missing or implausible.
Brokers that stamp times on a shifted clock have that corrected in their market feed; what is left to catch here is a clock nobody has corrected yet, which shows as an instant days away from when the tick arrived.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
float | int | None
|
Epoch seconds as the feed published them. |
required |
received_at
|
float
|
When the feed decoded the tick. |
required |
Returns:
| Type | Description |
|---|---|
float | None
|
The instant, or None. |