wiz-trader 0.17.0__tar.gz → 0.19.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wiz_trader-0.17.0/src/wiz_trader.egg-info → wiz_trader-0.19.0}/PKG-INFO +635 -128
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/README.md +634 -127
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/pyproject.toml +1 -1
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/setup.py +1 -1
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader/__init__.py +1 -1
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader/apis/client.py +176 -10
- {wiz_trader-0.17.0 → wiz_trader-0.19.0/src/wiz_trader.egg-info}/PKG-INFO +635 -128
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/MANIFEST.in +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/setup.cfg +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader/apis/__init__.py +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader/quotes/__init__.py +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader/quotes/client.py +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader.egg-info/SOURCES.txt +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader.egg-info/dependency_links.txt +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader.egg-info/requires.txt +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/src/wiz_trader.egg-info/top_level.txt +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/tests/test_apis.py +0 -0
- {wiz_trader-0.17.0 → wiz_trader-0.19.0}/tests/test_quotes.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: wiz_trader
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.19.0
|
4
4
|
Summary: A Python SDK for connecting to the Wizzer.
|
5
5
|
Home-page: https://bitbucket.org/wizzer-tech/quotes_sdk.git
|
6
6
|
Author: Pawan Wagh
|
@@ -388,29 +388,388 @@ for component in components[:5]:
|
|
388
388
|
```
|
389
389
|
|
390
390
|
#### Get Historical OHLCV Data
|
391
|
+
## Overview
|
391
392
|
|
392
|
-
|
393
|
+
The `get_historical_ohlcv` method supports multiple time intervals for historical data retrieval, from 1-minute intraday data to monthly aggregated data.
|
394
|
+
|
395
|
+
## Supported Intervals
|
396
|
+
|
397
|
+
### Intraday Intervals
|
398
|
+
- `1m` - 1 minute
|
399
|
+
- `2m` - 2 minutes
|
400
|
+
- `3m` - 3 minutes
|
401
|
+
- `5m` - 5 minutes
|
402
|
+
- `10m` - 10 minutes
|
403
|
+
- `15m` - 15 minutes
|
404
|
+
- `30m` - 30 minutes
|
405
|
+
- `45m` - 45 minutes
|
406
|
+
- `1h` - 1 hour
|
407
|
+
|
408
|
+
### Daily/Monthly Intervals
|
409
|
+
- `1d` - 1 day (default)
|
410
|
+
- `1M` - 1 month (last trading day of month)
|
411
|
+
|
412
|
+
## Date Format Requirements
|
413
|
+
|
414
|
+
### For Daily and Monthly Intervals (`1d`, `1M`)
|
415
|
+
- **Format**: `YYYY-MM-DD`
|
416
|
+
- **Example**: `"2024-01-15"`
|
417
|
+
|
418
|
+
### For Intraday Intervals (all minute/hour intervals)
|
419
|
+
- **Format**: `YYYY-MM-DD HH:MM:SS`
|
420
|
+
- **Example**: `"2024-01-15 09:30:00"`
|
421
|
+
|
422
|
+
## Using Constants
|
423
|
+
|
424
|
+
The client provides constants for all intervals:
|
425
|
+
|
426
|
+
```python
|
427
|
+
from wiz_trader import WizzerClient
|
428
|
+
|
429
|
+
client = WizzerClient(...)
|
430
|
+
|
431
|
+
# Intraday intervals
|
432
|
+
client.INTERVAL_1_MINUTE # "1m"
|
433
|
+
client.INTERVAL_2_MINUTES # "2m"
|
434
|
+
client.INTERVAL_3_MINUTES # "3m"
|
435
|
+
client.INTERVAL_5_MINUTES # "5m"
|
436
|
+
client.INTERVAL_10_MINUTES # "10m"
|
437
|
+
client.INTERVAL_15_MINUTES # "15m"
|
438
|
+
client.INTERVAL_30_MINUTES # "30m"
|
439
|
+
client.INTERVAL_45_MINUTES # "45m"
|
440
|
+
client.INTERVAL_1_HOUR # "1h"
|
441
|
+
|
442
|
+
# Daily/Monthly intervals
|
443
|
+
client.INTERVAL_1_DAY # "1d"
|
444
|
+
client.INTERVAL_1_MONTH # "1M"
|
445
|
+
```
|
446
|
+
|
447
|
+
## Usage Examples
|
448
|
+
|
449
|
+
### 1. Get 5-minute intraday data
|
450
|
+
|
451
|
+
```python
|
452
|
+
# Get 5-minute candles for a trading session
|
453
|
+
intraday_data = client.get_historical_ohlcv(
|
454
|
+
instruments=["NSE:SBIN:3045"],
|
455
|
+
start_date="2024-01-15 09:15:00", # Market open
|
456
|
+
end_date="2024-01-15 15:30:00", # Market close
|
457
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
458
|
+
interval=client.INTERVAL_5_MINUTES
|
459
|
+
)
|
460
|
+
|
461
|
+
# Response will have date field as: "2024-01-15 09:15:00", "2024-01-15 09:20:00", etc.
|
462
|
+
```
|
463
|
+
|
464
|
+
### 2. Get 1-minute data for scalping
|
465
|
+
|
466
|
+
```python
|
467
|
+
# Get 1-minute data for the first hour of trading
|
468
|
+
scalping_data = client.get_historical_ohlcv(
|
469
|
+
instruments=["NSE:RELIANCE:2885", "NSE:TCS:2953"],
|
470
|
+
start_date="2024-01-15 09:15:00",
|
471
|
+
end_date="2024-01-15 10:15:00",
|
472
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
473
|
+
interval=client.INTERVAL_1_MINUTE
|
474
|
+
)
|
475
|
+
```
|
476
|
+
|
477
|
+
### 3. Get hourly data for swing trading
|
478
|
+
|
479
|
+
```python
|
480
|
+
# Get hourly data for a week
|
481
|
+
hourly_data = client.get_historical_ohlcv(
|
482
|
+
instruments=["NSE:NIFTY 50:26000"],
|
483
|
+
start_date="2024-01-15 09:15:00",
|
484
|
+
end_date="2024-01-19 15:30:00",
|
485
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
486
|
+
interval=client.INTERVAL_1_HOUR
|
487
|
+
)
|
488
|
+
```
|
489
|
+
|
490
|
+
### 4. Get daily data (traditional)
|
393
491
|
|
394
492
|
```python
|
395
|
-
# Get daily data
|
493
|
+
# Get daily data for a month
|
396
494
|
daily_data = client.get_historical_ohlcv(
|
397
495
|
instruments=["NSE:SBIN:3045"],
|
398
|
-
start_date="2024-01-01",
|
496
|
+
start_date="2024-01-01", # Note: No time component
|
399
497
|
end_date="2024-01-31",
|
400
498
|
ohlcv=["open", "high", "low", "close", "volume"],
|
401
|
-
interval=
|
499
|
+
interval=client.INTERVAL_1_DAY
|
402
500
|
)
|
403
501
|
|
404
|
-
#
|
502
|
+
# Response will have date field as: "2024-01-01", "2024-01-02", etc.
|
503
|
+
```
|
504
|
+
|
505
|
+
### 5. Get monthly data for long-term analysis
|
506
|
+
|
507
|
+
```python
|
508
|
+
# Get monthly data for a year
|
405
509
|
monthly_data = client.get_historical_ohlcv(
|
406
|
-
instruments=["NSE:SBIN:3045"
|
510
|
+
instruments=["NSE:SBIN:3045"],
|
407
511
|
start_date="2023-01-01",
|
408
|
-
end_date="
|
512
|
+
end_date="2023-12-31",
|
409
513
|
ohlcv=["close", "volume"],
|
410
|
-
interval=
|
514
|
+
interval=client.INTERVAL_1_MONTH
|
515
|
+
)
|
516
|
+
```
|
517
|
+
|
518
|
+
## Response Structure
|
519
|
+
|
520
|
+
The response structure remains the same, but the `date` field format varies:
|
521
|
+
|
522
|
+
### For Daily/Monthly Intervals
|
523
|
+
```json
|
524
|
+
{
|
525
|
+
"instrument": {
|
526
|
+
"exchange": "NSE",
|
527
|
+
"tradingSymbol": "SBIN",
|
528
|
+
"exchangeToken": 3045,
|
529
|
+
"identifier": "NSE:SBIN:3045"
|
530
|
+
},
|
531
|
+
"data": [
|
532
|
+
{
|
533
|
+
"date": "2024-01-15", // YYYY-MM-DD format
|
534
|
+
"open": 750.0,
|
535
|
+
"high": 765.0,
|
536
|
+
"low": 745.0,
|
537
|
+
"close": 760.0,
|
538
|
+
"volume": 1000000
|
539
|
+
}
|
540
|
+
]
|
541
|
+
}
|
542
|
+
```
|
543
|
+
|
544
|
+
### For Intraday Intervals
|
545
|
+
```json
|
546
|
+
{
|
547
|
+
"instrument": {
|
548
|
+
"exchange": "NSE",
|
549
|
+
"tradingSymbol": "SBIN",
|
550
|
+
"exchangeToken": 3045,
|
551
|
+
"identifier": "NSE:SBIN:3045"
|
552
|
+
},
|
553
|
+
"data": [
|
554
|
+
{
|
555
|
+
"date": "2024-01-15 09:15:00", // YYYY-MM-DD HH:MM:SS format
|
556
|
+
"open": 750.0,
|
557
|
+
"high": 752.0,
|
558
|
+
"low": 749.0,
|
559
|
+
"close": 751.0,
|
560
|
+
"volume": 50000
|
561
|
+
}
|
562
|
+
]
|
563
|
+
}
|
564
|
+
```
|
565
|
+
|
566
|
+
## Advanced Usage Examples
|
567
|
+
|
568
|
+
### Multiple Timeframe Analysis
|
569
|
+
|
570
|
+
```python
|
571
|
+
def get_multi_timeframe_data(symbol, date):
|
572
|
+
"""Get data across multiple timeframes for comprehensive analysis"""
|
573
|
+
|
574
|
+
# 1-minute data for entry/exit precision
|
575
|
+
minute_data = client.get_historical_ohlcv(
|
576
|
+
instruments=[symbol],
|
577
|
+
start_date=f"{date} 09:15:00",
|
578
|
+
end_date=f"{date} 15:30:00",
|
579
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
580
|
+
interval=client.INTERVAL_1_MINUTE
|
581
|
+
)
|
582
|
+
|
583
|
+
# 5-minute data for short-term trends
|
584
|
+
five_min_data = client.get_historical_ohlcv(
|
585
|
+
instruments=[symbol],
|
586
|
+
start_date=f"{date} 09:15:00",
|
587
|
+
end_date=f"{date} 15:30:00",
|
588
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
589
|
+
interval=client.INTERVAL_5_MINUTES
|
590
|
+
)
|
591
|
+
|
592
|
+
# 15-minute data for medium-term trends
|
593
|
+
fifteen_min_data = client.get_historical_ohlcv(
|
594
|
+
instruments=[symbol],
|
595
|
+
start_date=f"{date} 09:15:00",
|
596
|
+
end_date=f"{date} 15:30:00",
|
597
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
598
|
+
interval=client.INTERVAL_15_MINUTES
|
599
|
+
)
|
600
|
+
|
601
|
+
# Hourly data for major trend
|
602
|
+
hourly_data = client.get_historical_ohlcv(
|
603
|
+
instruments=[symbol],
|
604
|
+
start_date=f"{date} 09:15:00",
|
605
|
+
end_date=f"{date} 15:30:00",
|
606
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
607
|
+
interval=client.INTERVAL_1_HOUR
|
608
|
+
)
|
609
|
+
|
610
|
+
return {
|
611
|
+
"1m": minute_data,
|
612
|
+
"5m": five_min_data,
|
613
|
+
"15m": fifteen_min_data,
|
614
|
+
"1h": hourly_data
|
615
|
+
}
|
616
|
+
|
617
|
+
# Usage
|
618
|
+
multi_data = get_multi_timeframe_data("NSE:SBIN:3045", "2024-01-15")
|
619
|
+
```
|
620
|
+
|
621
|
+
### Building OHLC Candlestick Data
|
622
|
+
|
623
|
+
```python
|
624
|
+
import pandas as pd
|
625
|
+
import matplotlib.pyplot as plt
|
626
|
+
from mplfinance import plot as mpf
|
627
|
+
|
628
|
+
def plot_candlestick_chart(symbol, start_date, end_date, interval):
|
629
|
+
"""Create a candlestick chart from historical data"""
|
630
|
+
|
631
|
+
# Get historical data
|
632
|
+
data = client.get_historical_ohlcv(
|
633
|
+
instruments=[symbol],
|
634
|
+
start_date=start_date,
|
635
|
+
end_date=end_date,
|
636
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
637
|
+
interval=interval
|
638
|
+
)
|
639
|
+
|
640
|
+
if not data or not data[0].get('data'):
|
641
|
+
print("No data available")
|
642
|
+
return
|
643
|
+
|
644
|
+
# Convert to DataFrame
|
645
|
+
df = pd.DataFrame(data[0]['data'])
|
646
|
+
df['date'] = pd.to_datetime(df['date'])
|
647
|
+
df.set_index('date', inplace=True)
|
648
|
+
|
649
|
+
# Rename columns for mplfinance
|
650
|
+
df.columns = ['Open', 'High', 'Low', 'Close', 'Volume']
|
651
|
+
|
652
|
+
# Create candlestick chart
|
653
|
+
mpf.plot(df, type='candle', volume=True,
|
654
|
+
title=f'{symbol} - {interval} Chart',
|
655
|
+
style='charles')
|
656
|
+
|
657
|
+
# Plot 5-minute chart
|
658
|
+
plot_candlestick_chart(
|
659
|
+
"NSE:SBIN:3045",
|
660
|
+
"2024-01-15 09:15:00",
|
661
|
+
"2024-01-15 15:30:00",
|
662
|
+
client.INTERVAL_5_MINUTES
|
663
|
+
)
|
664
|
+
```
|
665
|
+
|
666
|
+
### Backtesting with Different Intervals
|
667
|
+
|
668
|
+
```python
|
669
|
+
def backtest_strategy_multiple_intervals(symbol, start_date, end_date):
|
670
|
+
"""Backtest a strategy across different intervals"""
|
671
|
+
|
672
|
+
intervals = [
|
673
|
+
(client.INTERVAL_5_MINUTES, "5m"),
|
674
|
+
(client.INTERVAL_15_MINUTES, "15m"),
|
675
|
+
(client.INTERVAL_30_MINUTES, "30m"),
|
676
|
+
(client.INTERVAL_1_HOUR, "1h")
|
677
|
+
]
|
678
|
+
|
679
|
+
results = {}
|
680
|
+
|
681
|
+
for interval_code, interval_name in intervals:
|
682
|
+
# For intraday intervals, use datetime format
|
683
|
+
data = client.get_historical_ohlcv(
|
684
|
+
instruments=[symbol],
|
685
|
+
start_date=f"{start_date} 09:15:00",
|
686
|
+
end_date=f"{end_date} 15:30:00",
|
687
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
688
|
+
interval=interval_code
|
689
|
+
)
|
690
|
+
|
691
|
+
if data and data[0].get('data'):
|
692
|
+
df = pd.DataFrame(data[0]['data'])
|
693
|
+
df['date'] = pd.to_datetime(df['date'])
|
694
|
+
|
695
|
+
# Simple moving average crossover strategy
|
696
|
+
df['sma_10'] = df['close'].rolling(10).mean()
|
697
|
+
df['sma_20'] = df['close'].rolling(20).mean()
|
698
|
+
|
699
|
+
# Generate signals
|
700
|
+
df['signal'] = 0
|
701
|
+
df.loc[df['sma_10'] > df['sma_20'], 'signal'] = 1
|
702
|
+
df.loc[df['sma_10'] < df['sma_20'], 'signal'] = -1
|
703
|
+
|
704
|
+
# Calculate returns
|
705
|
+
df['returns'] = df['close'].pct_change()
|
706
|
+
df['strategy_returns'] = df['signal'].shift(1) * df['returns']
|
707
|
+
|
708
|
+
# Calculate total return
|
709
|
+
total_return = (1 + df['strategy_returns']).prod() - 1
|
710
|
+
|
711
|
+
results[interval_name] = {
|
712
|
+
'total_return': total_return,
|
713
|
+
'num_trades': df['signal'].diff().abs().sum() / 2,
|
714
|
+
'num_candles': len(df)
|
715
|
+
}
|
716
|
+
|
717
|
+
return results
|
718
|
+
|
719
|
+
# Compare strategy performance across intervals
|
720
|
+
performance = backtest_strategy_multiple_intervals(
|
721
|
+
"NSE:SBIN:3045",
|
722
|
+
"2024-01-01",
|
723
|
+
"2024-01-31"
|
411
724
|
)
|
725
|
+
|
726
|
+
for interval, metrics in performance.items():
|
727
|
+
print(f"{interval}: Return={metrics['total_return']:.2%}, "
|
728
|
+
f"Trades={metrics['num_trades']:.0f}, "
|
729
|
+
f"Candles={metrics['num_candles']}")
|
730
|
+
```
|
731
|
+
|
732
|
+
## Error Handling
|
733
|
+
|
734
|
+
```python
|
735
|
+
try:
|
736
|
+
data = client.get_historical_ohlcv(
|
737
|
+
instruments=["NSE:SBIN:3045"],
|
738
|
+
start_date="2024-01-15 09:15:00",
|
739
|
+
end_date="2024-01-15 15:30:00",
|
740
|
+
ohlcv=["open", "high", "low", "close", "volume"],
|
741
|
+
interval=client.INTERVAL_5_MINUTES
|
742
|
+
)
|
743
|
+
except ValueError as e:
|
744
|
+
print(f"Date format error: {e}")
|
745
|
+
except Exception as e:
|
746
|
+
print(f"API error: {e}")
|
412
747
|
```
|
413
748
|
|
749
|
+
## Best Practices
|
750
|
+
|
751
|
+
1. **Use appropriate intervals for your strategy**:
|
752
|
+
- Scalping: 1m, 2m, 3m
|
753
|
+
- Day trading: 5m, 15m, 30m
|
754
|
+
- Swing trading: 1h, 1d
|
755
|
+
- Position trading: 1d, 1M
|
756
|
+
|
757
|
+
2. **Be mindful of data volume**:
|
758
|
+
- 1-minute data generates a lot of candles
|
759
|
+
- Use shorter date ranges for minute-level data
|
760
|
+
|
761
|
+
3. **Validate date formats**:
|
762
|
+
- The client will validate formats automatically
|
763
|
+
- Use datetime strings consistently
|
764
|
+
|
765
|
+
4. **Consider market hours**:
|
766
|
+
- For intraday data, use market hours: 09:15:00 to 15:30:00
|
767
|
+
- Weekend dates won't have intraday data
|
768
|
+
|
769
|
+
5. **Cache data when possible**:
|
770
|
+
- Historical data doesn't change
|
771
|
+
- Store frequently used datasets locally
|
772
|
+
|
414
773
|
### Order Management
|
415
774
|
|
416
775
|
#### Place Regular Order
|
@@ -643,13 +1002,13 @@ Fetch detailed information and metrics for specific instruments:
|
|
643
1002
|
|
644
1003
|
```python
|
645
1004
|
# Get metrics for a single equity instrument
|
646
|
-
equity_info = client.get_instrument_metrics(
|
1005
|
+
equity_info = client.get_instrument_metrics(identifiers=["NSE:SBIN:3045"])
|
647
1006
|
print(f"SBIN Last Price: {equity_info[0]['ltp']}")
|
648
1007
|
print(f"SBIN 52-week High: {equity_info[0]['week52High']}")
|
649
1008
|
|
650
1009
|
# Get metrics for multiple instruments of different types
|
651
1010
|
instruments_info = client.get_instrument_metrics(
|
652
|
-
|
1011
|
+
identifiers=[
|
653
1012
|
"NSE:AARTIIND:7", # Equity
|
654
1013
|
"NSE:NIFTY26DEC11000CE:61009", # Option
|
655
1014
|
"NSE:SBIN25MAYFUT:57515" # Future
|
@@ -831,12 +1190,150 @@ Note that certain fields may have zero or empty values if the data is not availa
|
|
831
1190
|
|
832
1191
|
### Options Chain
|
833
1192
|
|
1193
|
+
#### Get Option Expiry List
|
1194
|
+
|
1195
|
+
Fetch available expiry dates for an instrument's options:
|
1196
|
+
|
1197
|
+
```python
|
1198
|
+
# For a stock
|
1199
|
+
expiry_list = client.get_option_expiry_list("NSE:SBIN:3045")
|
1200
|
+
|
1201
|
+
# For an index
|
1202
|
+
nifty_expiry = client.get_option_expiry_list("NSE:NIFTY 50:26000")
|
1203
|
+
|
1204
|
+
# Print all available expiry dates
|
1205
|
+
for expiry in expiry_list.get('expiryList', []):
|
1206
|
+
print(f"{expiry['date']} - {expiry['contract']} " +
|
1207
|
+
f"(Futures: {'Yes' if expiry['isFuturesExpiry'] else 'No'}, " +
|
1208
|
+
f"Options: {'Yes' if expiry['isOptionsExpiry'] else 'No'})")
|
1209
|
+
```
|
1210
|
+
|
1211
|
+
#### Response Structure
|
1212
|
+
|
1213
|
+
The response is a JSON object with the following structure:
|
1214
|
+
|
1215
|
+
```json
|
1216
|
+
{
|
1217
|
+
"exchange": "NSE", // Exchange of the instrument
|
1218
|
+
"tradingSymbol": "SBIN", // Trading symbol
|
1219
|
+
"exchangeToken": 3045, // Exchange token
|
1220
|
+
"identifier": "NSE:SBIN:3045", // Full identifier
|
1221
|
+
"expiryList": [ // Array of expiry objects
|
1222
|
+
{
|
1223
|
+
"date": "2025-05-29", // Expiry date in YYYY-MM-DD format
|
1224
|
+
"contract": "near_month", // Contract type (see below)
|
1225
|
+
"isFuturesExpiry": true, // Whether futures expire on this date
|
1226
|
+
"isOptionsExpiry": true // Whether options expire on this date
|
1227
|
+
},
|
1228
|
+
// More expiry objects...
|
1229
|
+
]
|
1230
|
+
}
|
1231
|
+
```
|
1232
|
+
|
1233
|
+
For index options like NIFTY, the response will typically include more expiry dates, including weekly options and longer-dated quarterly options.
|
1234
|
+
|
1235
|
+
The `expiryList` array contains objects with the following fields:
|
1236
|
+
- `date`: The expiry date in YYYY-MM-DD format
|
1237
|
+
- `contract`: The type of contract (e.g., "near_month", "current_weekly")
|
1238
|
+
- `isFuturesExpiry`: Boolean indicating if futures expire on this date
|
1239
|
+
- `isOptionsExpiry`: Boolean indicating if options expire on this date
|
1240
|
+
|
1241
|
+
#### Contract Types
|
1242
|
+
|
1243
|
+
Each expiry date is categorized with a `contract` field that indicates the type of expiry. The possible contract types are:
|
1244
|
+
|
1245
|
+
1. **Weekly Expiries (Thursdays/Wednesdays)**
|
1246
|
+
- `current_weekly`: The first non-expiry Thursday of the current week
|
1247
|
+
|
1248
|
+
2. **Monthly Expiries (last Wed/Thu of month)**
|
1249
|
+
- `near_month`: Last Wed/Thu of this month (current month)
|
1250
|
+
- `mid_month`: Last Wed/Thu of next month
|
1251
|
+
- `far_month`: Last Wed/Thu of month after next
|
1252
|
+
|
1253
|
+
3. **Weekly Ordinals Within Current Month**
|
1254
|
+
- `first_weekly`: 1st non-expiry Thursday of current month
|
1255
|
+
- `second_weekly`: 2nd non-expiry Thursday
|
1256
|
+
- `third_weekly`: 3rd non-expiry Thursday
|
1257
|
+
- `fourth_weekly`: 4th non-expiry Thursday
|
1258
|
+
- `fifth_weekly`: 5th non-expiry Thursday (rare)
|
1259
|
+
|
1260
|
+
4. **Weekly Ordinals in Mid-Month Slot (next month's week-trade dates)**
|
1261
|
+
- `first_weekly_mid_month`: 1st Thursday of next month
|
1262
|
+
- `second_weekly_mid_month`: 2nd Thursday of next month
|
1263
|
+
- `third_weekly_mid_month`: 3rd Thursday of next month
|
1264
|
+
- `fourth_weekly_mid_month`: 4th Thursday of next month
|
1265
|
+
- `fifth_weekly_mid_month`: 5th Thursday of next month (rare)
|
1266
|
+
|
1267
|
+
5. **Weekly Ordinals in Far-Month Slot (month-after-next)**
|
1268
|
+
- `first_weekly_far_month`: 1st Thursday of month after next
|
1269
|
+
- `second_weekly_far_month`: 2nd Thursday of month after next
|
1270
|
+
- `third_weekly_far_month`: 3rd Thursday of month after next
|
1271
|
+
- `fourth_weekly_far_month`: 4th Thursday of month after next
|
1272
|
+
- `fifth_weekly_far_month`: 5th Thursday of month after next (rare)
|
1273
|
+
|
1274
|
+
6. **Quarterly Expiries (last-Thu of Mar/Jun/Sep/Dec)**
|
1275
|
+
- `first_quarter`: Last Thu of March (Q1)
|
1276
|
+
- `second_quarter`: Last Thu of June (Q2)
|
1277
|
+
- `third_quarter`: Last Thu of September (Q3)
|
1278
|
+
- `fourth_quarter`: Last Thu of December (Q4)
|
1279
|
+
|
1280
|
+
7. **Half-Yearly Expiries**
|
1281
|
+
- `first_half_yearly`: Last Thu of June (H1)
|
1282
|
+
- `second_half_yearly`: Last Thu of December (H2)
|
1283
|
+
|
1284
|
+
8. **Year-Plus-N Quarterly/Half-Yearly (N = years ahead)**
|
1285
|
+
- For quarterly options in future years:
|
1286
|
+
- `first_quarter_1`: Q1 (March) of next year
|
1287
|
+
- `second_quarter_1`: Q2 (June) of next year
|
1288
|
+
- `third_quarter_1`: Q3 (September) of next year
|
1289
|
+
- `fourth_quarter_1`: Q4 (December) of next year
|
1290
|
+
- For half-yearly options in future years:
|
1291
|
+
- `first_half_yearly_1`: H1 (June) of next year
|
1292
|
+
- `second_half_yearly_1`: H2 (December) of next year
|
1293
|
+
- This pattern continues with `_2`, `_3`, and `_4` suffixes for up to 4 years ahead
|
1294
|
+
|
1295
|
+
9. **Special Case**
|
1296
|
+
- `none`: No matching expiry category
|
1297
|
+
|
1298
|
+
### Get Options Chain
|
1299
|
+
|
1300
|
+
The Options Chain API provides detailed information about available option contracts for a specified instrument, including strike prices, premiums, and option Greeks.
|
1301
|
+
|
1302
|
+
#### Constants
|
1303
|
+
|
1304
|
+
The SDK provides constants for option types, moneyness, and expiry preferences to make your code more readable and type-safe:
|
1305
|
+
|
1306
|
+
**Option Types:**
|
1307
|
+
```python
|
1308
|
+
client.OPTION_TYPE_CE # Call option
|
1309
|
+
client.OPTION_TYPE_PE # Put option
|
1310
|
+
```
|
1311
|
+
|
1312
|
+
**Moneyness Types:**
|
1313
|
+
```python
|
1314
|
+
client.MONEYNESS_ATM # At-the-money
|
1315
|
+
client.MONEYNESS_ITM # In-the-money
|
1316
|
+
client.MONEYNESS_OTM # Out-of-the-money
|
1317
|
+
```
|
1318
|
+
|
1319
|
+
**Expiry Preferences:**
|
1320
|
+
```python
|
1321
|
+
# Common expiry preferences
|
1322
|
+
client.EXPIRY_CURRENT_WEEKLY # Current week's expiry
|
1323
|
+
client.EXPIRY_NEAR_MONTH # Current month's expiry
|
1324
|
+
client.EXPIRY_MID_MONTH # Next month's expiry
|
1325
|
+
client.EXPIRY_FAR_MONTH # Month after next expiry
|
1326
|
+
|
1327
|
+
# Many more constants available for weekly, monthly,
|
1328
|
+
# quarterly, and yearly expiries
|
1329
|
+
```
|
1330
|
+
|
834
1331
|
#### Get Option Chain
|
835
1332
|
|
836
|
-
Fetch the option chain for a specific instrument
|
1333
|
+
Fetch the option chain for a specific instrument using either an exact expiry date or a expiry preference:
|
837
1334
|
|
838
1335
|
```python
|
839
|
-
# Get ATM call options for SBIN
|
1336
|
+
# Get ATM call options for SBIN with specific expiry date
|
840
1337
|
options = client.get_option_chain(
|
841
1338
|
identifier="NSE:SBIN:3045",
|
842
1339
|
expiry_date="2025-05-30",
|
@@ -846,10 +1343,10 @@ options = client.get_option_chain(
|
|
846
1343
|
print(f"Found {len(options['strikes'])} strikes")
|
847
1344
|
print(f"Current underlying price: {options['underlyingPrice']}")
|
848
1345
|
|
849
|
-
# Get both call and put options
|
1346
|
+
# Get both call and put options with expiry preference
|
850
1347
|
all_options = client.get_option_chain(
|
851
|
-
identifier="NSE:
|
852
|
-
|
1348
|
+
identifier="NSE:NIFTY 50:26000",
|
1349
|
+
expiry_preference=client.EXPIRY_CURRENT_WEEKLY, # Current week's expiry
|
853
1350
|
option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE], # Both calls and puts
|
854
1351
|
moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM] # All moneyness types
|
855
1352
|
)
|
@@ -864,7 +1361,7 @@ for strike in all_options['strikes']:
|
|
864
1361
|
print(f"{strike['tradingSymbol']} ({strike['moneyness']}): {strike['ltp']}")
|
865
1362
|
```
|
866
1363
|
|
867
|
-
#### Response Structure
|
1364
|
+
#### Response Structure
|
868
1365
|
|
869
1366
|
The `get_option_chain` method returns a dictionary with the following structure:
|
870
1367
|
|
@@ -938,133 +1435,143 @@ The `get_option_chain` method returns a dictionary with the following structure:
|
|
938
1435
|
}
|
939
1436
|
```
|
940
1437
|
|
941
|
-
|
1438
|
+
#### Advanced Examples
|
942
1439
|
|
943
|
-
|
944
|
-
|
945
|
-
Here's an example of how to use the option chain API for more advanced analysis:
|
1440
|
+
##### Finding a Straddle/Strangle
|
946
1441
|
|
947
1442
|
```python
|
948
|
-
def
|
949
|
-
"""
|
950
|
-
|
1443
|
+
def find_straddle_strangle(identifier, expiry):
|
1444
|
+
"""Find and analyze straddle/strangle opportunities."""
|
1445
|
+
# Get the option chain
|
1446
|
+
option_chain = client.get_option_chain(
|
1447
|
+
identifier=identifier,
|
1448
|
+
expiry_date=expiry,
|
1449
|
+
option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
|
1450
|
+
moneyness=[client.MONEYNESS_ATM]
|
1451
|
+
)
|
1452
|
+
|
1453
|
+
# Find ATM call and put
|
1454
|
+
calls = [s for s in option_chain["strikes"] if s["optionType"] == "CE"]
|
1455
|
+
puts = [s for s in option_chain["strikes"] if s["optionType"] == "PE"]
|
1456
|
+
|
1457
|
+
if not calls or not puts:
|
1458
|
+
print("Couldn't find both call and put options")
|
1459
|
+
return
|
1460
|
+
|
1461
|
+
# For a straddle, we want the same strike price
|
1462
|
+
atm_strike = calls[0]["strikePrice"]
|
1463
|
+
atm_call = calls[0]
|
1464
|
+
atm_put = next((p for p in puts if p["strikePrice"] == atm_strike), None)
|
951
1465
|
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
1466
|
+
if atm_call and atm_put:
|
1467
|
+
call_premium = atm_call["ltp"]
|
1468
|
+
put_premium = atm_put["ltp"]
|
1469
|
+
total_premium = call_premium + put_premium
|
1470
|
+
|
1471
|
+
print(f"ATM Straddle Analysis for {identifier} (Expiry: {expiry})")
|
1472
|
+
print(f"Underlying Price: {option_chain['underlyingPrice']}")
|
1473
|
+
print(f"ATM Strike: {atm_strike}")
|
1474
|
+
print(f"Call Premium: {call_premium}")
|
1475
|
+
print(f"Put Premium: {put_premium}")
|
1476
|
+
print(f"Total Premium: {total_premium}")
|
1477
|
+
print(f"Breakeven Upper: {atm_strike + total_premium}")
|
1478
|
+
print(f"Breakeven Lower: {atm_strike - total_premium}")
|
1479
|
+
|
1480
|
+
# Calculate the percentage move needed for breakeven
|
1481
|
+
pct_move = (total_premium / option_chain['underlyingPrice']) * 100
|
1482
|
+
print(f"Required % Move for Breakeven: {pct_move:.2f}%")
|
957
1483
|
|
958
|
-
#
|
1484
|
+
# For a strangle, we want OTM call and put
|
1485
|
+
otm_options = client.get_option_chain(
|
1486
|
+
identifier=identifier,
|
1487
|
+
expiry_date=expiry,
|
1488
|
+
option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
|
1489
|
+
moneyness=[client.MONEYNESS_OTM]
|
1490
|
+
)
|
1491
|
+
|
1492
|
+
otm_calls = sorted([s for s in otm_options["strikes"] if s["optionType"] == "CE"],
|
1493
|
+
key=lambda x: x["strikePrice"])
|
1494
|
+
otm_puts = sorted([s for s in otm_options["strikes"] if s["optionType"] == "PE"],
|
1495
|
+
key=lambda x: x["strikePrice"], reverse=True)
|
1496
|
+
|
1497
|
+
if otm_calls and otm_puts:
|
1498
|
+
otm_call = otm_calls[0] # First OTM call
|
1499
|
+
otm_put = otm_puts[0] # First OTM put
|
1500
|
+
|
1501
|
+
call_premium = otm_call["ltp"]
|
1502
|
+
put_premium = otm_put["ltp"]
|
1503
|
+
total_premium = call_premium + put_premium
|
1504
|
+
|
1505
|
+
print(f"\nOTM Strangle Analysis for {identifier} (Expiry: {expiry})")
|
1506
|
+
print(f"Call Strike: {otm_call['strikePrice']} (Premium: {call_premium})")
|
1507
|
+
print(f"Put Strike: {otm_put['strikePrice']} (Premium: {put_premium})")
|
1508
|
+
print(f"Total Premium: {total_premium}")
|
1509
|
+
print(f"Breakeven Upper: {otm_call['strikePrice'] + total_premium}")
|
1510
|
+
print(f"Breakeven Lower: {otm_put['strikePrice'] - total_premium}")
|
1511
|
+
|
1512
|
+
return option_chain
|
1513
|
+
|
1514
|
+
# Example usage
|
1515
|
+
find_straddle_strangle("NSE:SBIN:3045", "2025-05-30")
|
1516
|
+
```
|
1517
|
+
|
1518
|
+
##### Option Chain Visualization
|
1519
|
+
|
1520
|
+
```python
|
1521
|
+
def visualize_option_chain(identifier, expiry):
|
1522
|
+
"""Create a visualization of the option chain."""
|
1523
|
+
import matplotlib.pyplot as plt
|
1524
|
+
import numpy as np
|
1525
|
+
|
1526
|
+
# Get the option chain
|
959
1527
|
option_chain = client.get_option_chain(
|
960
|
-
identifier=
|
961
|
-
expiry_date=
|
1528
|
+
identifier=identifier,
|
1529
|
+
expiry_date=expiry,
|
962
1530
|
option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
|
963
1531
|
moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM]
|
964
1532
|
)
|
965
1533
|
|
966
|
-
# Extract
|
1534
|
+
# Extract data
|
967
1535
|
underlying_price = option_chain["underlyingPrice"]
|
968
|
-
future_price = option_chain["futurePrice"]
|
969
|
-
resolved_expiry = option_chain["resolvedExpiry"]
|
970
1536
|
|
971
1537
|
# Separate calls and puts
|
972
|
-
calls = [s for s in option_chain["strikes"] if s["optionType"] == "CE"]
|
973
|
-
|
1538
|
+
calls = sorted([s for s in option_chain["strikes"] if s["optionType"] == "CE"],
|
1539
|
+
key=lambda x: x["strikePrice"])
|
1540
|
+
puts = sorted([s for s in option_chain["strikes"] if s["optionType"] == "PE"],
|
1541
|
+
key=lambda x: x["strikePrice"])
|
1542
|
+
|
1543
|
+
# Extract strike prices and premiums
|
1544
|
+
call_strikes = [c["strikePrice"] for c in calls]
|
1545
|
+
call_premiums = [c["ltp"] for c in calls]
|
1546
|
+
|
1547
|
+
put_strikes = [p["strikePrice"] for p in puts]
|
1548
|
+
put_premiums = [p["ltp"] for p in puts]
|
1549
|
+
|
1550
|
+
# Create figure and axis
|
1551
|
+
fig, ax = plt.subplots(figsize=(12, 8))
|
1552
|
+
|
1553
|
+
# Plot calls and puts
|
1554
|
+
ax.plot(call_strikes, call_premiums, 'b-', marker='o', label='Calls')
|
1555
|
+
ax.plot(put_strikes, put_premiums, 'r-', marker='o', label='Puts')
|
1556
|
+
|
1557
|
+
# Add vertical line for current price
|
1558
|
+
ax.axvline(x=underlying_price, color='g', linestyle='--',
|
1559
|
+
label=f'Current Price ({underlying_price})')
|
1560
|
+
|
1561
|
+
# Add labels and title
|
1562
|
+
ax.set_xlabel('Strike Price')
|
1563
|
+
ax.set_ylabel('Premium')
|
1564
|
+
ax.set_title(f'Option Chain for {identifier} (Expiry: {expiry})')
|
1565
|
+
ax.legend()
|
1566
|
+
ax.grid(True)
|
1567
|
+
|
1568
|
+
plt.tight_layout()
|
1569
|
+
plt.show()
|
974
1570
|
|
975
|
-
# Sort by strike price
|
976
|
-
calls.sort(key=lambda x: x["strikePrice"])
|
977
|
-
puts.sort(key=lambda x: x["strikePrice"])
|
978
|
-
|
979
|
-
# Find ATM options
|
980
|
-
atm_call = next((s for s in calls if s["moneyness"] == "ATM"), None)
|
981
|
-
atm_put = next((s for s in puts if s["moneyness"] == "ATM"), None)
|
982
|
-
atm_strike = atm_call["strikePrice"] if atm_call else None
|
983
|
-
|
984
|
-
print(f"Analysis for Option Chain (Expiry: {resolved_expiry})")
|
985
|
-
print(f"Underlying Price: {underlying_price}")
|
986
|
-
print(f"Future Price: {future_price}")
|
987
|
-
print(f"ATM Strike: {atm_strike}")
|
988
|
-
print(f"Days to Expiry: {(datetime.strptime(resolved_expiry, '%Y-%m-%d') - datetime.now()).days}")
|
989
|
-
print("=" * 60)
|
990
|
-
|
991
|
-
# Find interesting spreads
|
992
|
-
if len(calls) >= 2 and len(puts) >= 2:
|
993
|
-
# Vertical spreads
|
994
|
-
bull_call_spread = {
|
995
|
-
'long': atm_call,
|
996
|
-
'short': next((c for c in calls if c["strikePrice"] > atm_strike), None)
|
997
|
-
}
|
998
|
-
|
999
|
-
bear_put_spread = {
|
1000
|
-
'long': atm_put,
|
1001
|
-
'short': next((p for p in puts if p["strikePrice"] < atm_strike), None)
|
1002
|
-
}
|
1003
|
-
|
1004
|
-
# Iron condor
|
1005
|
-
iron_condor = {
|
1006
|
-
'long_put': next((p for p in puts if p["strikePrice"] < atm_strike and p["moneyness"] == "OTM"), None),
|
1007
|
-
'short_put': atm_put,
|
1008
|
-
'short_call': atm_call,
|
1009
|
-
'long_call': next((c for c in calls if c["strikePrice"] > atm_strike and c["moneyness"] == "OTM"), None)
|
1010
|
-
}
|
1011
|
-
|
1012
|
-
# Print potential strategies
|
1013
|
-
print("Potential Strategies:")
|
1014
|
-
|
1015
|
-
# Bull Call Spread
|
1016
|
-
if bull_call_spread['long'] and bull_call_spread['short']:
|
1017
|
-
long_premium = bull_call_spread['long']['ltp']
|
1018
|
-
short_premium = bull_call_spread['short']['ltp']
|
1019
|
-
net_premium = long_premium - short_premium
|
1020
|
-
max_profit = bull_call_spread['short']['strikePrice'] - bull_call_spread['long']['strikePrice'] - net_premium
|
1021
|
-
|
1022
|
-
print(f"Bull Call Spread: Buy {bull_call_spread['long']['tradingSymbol']} @ {long_premium}, "
|
1023
|
-
f"Sell {bull_call_spread['short']['tradingSymbol']} @ {short_premium}")
|
1024
|
-
print(f" Net Premium: {net_premium}")
|
1025
|
-
print(f" Max Profit: {max_profit}")
|
1026
|
-
print(f" Break-even: {bull_call_spread['long']['strikePrice'] + net_premium}")
|
1027
|
-
|
1028
|
-
# Bear Put Spread
|
1029
|
-
if bear_put_spread['long'] and bear_put_spread['short']:
|
1030
|
-
long_premium = bear_put_spread['long']['ltp']
|
1031
|
-
short_premium = bear_put_spread['short']['ltp']
|
1032
|
-
net_premium = long_premium - short_premium
|
1033
|
-
max_profit = bear_put_spread['long']['strikePrice'] - bear_put_spread['short']['strikePrice'] - net_premium
|
1034
|
-
|
1035
|
-
print(f"Bear Put Spread: Buy {bear_put_spread['long']['tradingSymbol']} @ {long_premium}, "
|
1036
|
-
f"Sell {bear_put_spread['short']['tradingSymbol']} @ {short_premium}")
|
1037
|
-
print(f" Net Premium: {net_premium}")
|
1038
|
-
print(f" Max Profit: {max_profit}")
|
1039
|
-
print(f" Break-even: {bear_put_spread['long']['strikePrice'] - net_premium}")
|
1040
|
-
|
1041
|
-
# Iron Condor
|
1042
|
-
if all(iron_condor.values()):
|
1043
|
-
long_put_premium = iron_condor['long_put']['ltp']
|
1044
|
-
short_put_premium = iron_condor['short_put']['ltp']
|
1045
|
-
short_call_premium = iron_condor['short_call']['ltp']
|
1046
|
-
long_call_premium = iron_condor['long_call']['ltp']
|
1047
|
-
|
1048
|
-
net_premium = (short_put_premium + short_call_premium) - (long_put_premium + long_call_premium)
|
1049
|
-
put_wing_width = iron_condor['short_put']['strikePrice'] - iron_condor['long_put']['strikePrice']
|
1050
|
-
call_wing_width = iron_condor['long_call']['strikePrice'] - iron_condor['short_call']['strikePrice']
|
1051
|
-
|
1052
|
-
max_risk = max(put_wing_width, call_wing_width) - net_premium
|
1053
|
-
|
1054
|
-
print(f"Iron Condor Strategy:")
|
1055
|
-
print(f" Long Put: {iron_condor['long_put']['tradingSymbol']} @ {long_put_premium}")
|
1056
|
-
print(f" Short Put: {iron_condor['short_put']['tradingSymbol']} @ {short_put_premium}")
|
1057
|
-
print(f" Short Call: {iron_condor['short_call']['tradingSymbol']} @ {short_call_premium}")
|
1058
|
-
print(f" Long Call: {iron_condor['long_call']['tradingSymbol']} @ {long_call_premium}")
|
1059
|
-
print(f" Net Premium Received: {net_premium}")
|
1060
|
-
print(f" Max Risk: {max_risk}")
|
1061
|
-
print(f" Max Profit: {net_premium}")
|
1062
|
-
|
1063
|
-
# Return the option chain for further analysis
|
1064
1571
|
return option_chain
|
1065
1572
|
|
1066
|
-
# Example usage
|
1067
|
-
|
1573
|
+
# Example usage
|
1574
|
+
visualize_option_chain("NSE:NIFTY 50:26000", "2025-05-30")
|
1068
1575
|
```
|
1069
1576
|
|
1070
1577
|
### Wizzer Client Examples
|