nsekit 0.2.0 → 0.3.1
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.
- package/README.md +51 -33
- package/dist/brokers/dhan/DhanBroker.d.ts +10 -4
- package/dist/brokers/dhan/DhanBroker.d.ts.map +1 -1
- package/dist/brokers/dhan/dhan-instruments.d.ts +1 -11
- package/dist/brokers/dhan/dhan-instruments.d.ts.map +1 -1
- package/dist/brokers/dhan/dhan-socket.d.ts +33 -3
- package/dist/brokers/dhan/dhan-socket.d.ts.map +1 -1
- package/dist/brokers/finvasia/FinvasiaBroker.d.ts +10 -4
- package/dist/brokers/finvasia/FinvasiaBroker.d.ts.map +1 -1
- package/dist/brokers/finvasia/finvasia-constants.d.ts +1 -1
- package/dist/brokers/finvasia/finvasia-constants.d.ts.map +1 -1
- package/dist/brokers/finvasia/finvasia-instruments.d.ts +1 -11
- package/dist/brokers/finvasia/finvasia-instruments.d.ts.map +1 -1
- package/dist/brokers/finvasia/finvasia-socket.d.ts.map +1 -1
- package/dist/brokers/paper/PaperBroker.d.ts +11 -3
- package/dist/brokers/paper/PaperBroker.d.ts.map +1 -1
- package/dist/brokers/zerodha/ZerodhaBroker.d.ts +10 -4
- package/dist/brokers/zerodha/ZerodhaBroker.d.ts.map +1 -1
- package/dist/brokers/zerodha/zerodha-instruments.d.ts +0 -12
- package/dist/brokers/zerodha/zerodha-instruments.d.ts.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +306 -170
- package/dist/instruments/instrument-master.d.ts +9 -2
- package/dist/instruments/instrument-master.d.ts.map +1 -1
- package/dist/interfaces/broker.interface.d.ts +8 -3
- package/dist/interfaces/broker.interface.d.ts.map +1 -1
- package/dist/types/broker.d.ts +9 -1
- package/dist/types/broker.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/instruments.d.ts +1 -6
- package/dist/types/instruments.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19443,6 +19443,23 @@ class InstrumentMaster {
|
|
|
19443
19443
|
const list = matches.slice(0, 5).map((m) => `${m.exchange}:${m.tradingSymbol}`).join(", ");
|
|
19444
19444
|
return Err(new Error(`Multiple matches found. Specify exchange: ${list}`));
|
|
19445
19445
|
}
|
|
19446
|
+
async resolveAsync(input, brokerId, brokerInstruments) {
|
|
19447
|
+
const local = this.resolve(input);
|
|
19448
|
+
if (local.ok)
|
|
19449
|
+
return local;
|
|
19450
|
+
if (brokerInstruments.capabilities.searchAPI && brokerInstruments.searchAPI) {
|
|
19451
|
+
const { symbol } = this.parseInput(input);
|
|
19452
|
+
const apiResult = await brokerInstruments.searchAPI(symbol);
|
|
19453
|
+
if (apiResult.ok && apiResult.value.length > 0) {
|
|
19454
|
+
for (const entry of apiResult.value)
|
|
19455
|
+
this.mergeEntry(brokerId, entry);
|
|
19456
|
+
if (this.redis)
|
|
19457
|
+
this.cacheInstrumentsToRedis();
|
|
19458
|
+
return this.resolve(input);
|
|
19459
|
+
}
|
|
19460
|
+
}
|
|
19461
|
+
return Err(new Error(`Symbol "${input}" not found`));
|
|
19462
|
+
}
|
|
19446
19463
|
async getOptionChainCached(underlying, expiry) {
|
|
19447
19464
|
const expiryDate = expiry.toISOString().slice(0, 10);
|
|
19448
19465
|
const cacheKey = `optchain:${underlying.toUpperCase()}:${expiryDate}`;
|
|
@@ -20565,33 +20582,6 @@ class ZerodhaInstruments {
|
|
|
20565
20582
|
yield row;
|
|
20566
20583
|
}
|
|
20567
20584
|
}
|
|
20568
|
-
async checkDumpChanged(lastSync) {
|
|
20569
|
-
const response = await fetch(KITE_INSTRUMENTS_URL, { method: "HEAD" });
|
|
20570
|
-
if (!response.ok)
|
|
20571
|
-
return true;
|
|
20572
|
-
const etag = response.headers.get("etag");
|
|
20573
|
-
const lastModified = response.headers.get("last-modified");
|
|
20574
|
-
if (etag && lastSync.etag)
|
|
20575
|
-
return etag !== lastSync.etag;
|
|
20576
|
-
if (lastModified && lastSync.lastModified)
|
|
20577
|
-
return lastModified !== lastSync.lastModified;
|
|
20578
|
-
return true;
|
|
20579
|
-
}
|
|
20580
|
-
async resolve(symbol, exchange) {
|
|
20581
|
-
try {
|
|
20582
|
-
for await (const raw of this.streamDump()) {
|
|
20583
|
-
const fields = raw;
|
|
20584
|
-
const rowSymbol = fields["tradingsymbol"] ?? "";
|
|
20585
|
-
const rowExchange = fields["exchange"] ?? "";
|
|
20586
|
-
if (rowSymbol === symbol && rowExchange === exchange) {
|
|
20587
|
-
return Ok(this.normalize(raw));
|
|
20588
|
-
}
|
|
20589
|
-
}
|
|
20590
|
-
return Err(new Error(`Instrument ${symbol} not found on ${exchange} (Zerodha)`));
|
|
20591
|
-
} catch (err) {
|
|
20592
|
-
return Err(err instanceof Error ? err : new Error(String(err)));
|
|
20593
|
-
}
|
|
20594
|
-
}
|
|
20595
20585
|
normalize(raw) {
|
|
20596
20586
|
const fields = raw;
|
|
20597
20587
|
const tradingSymbol = fields["tradingsymbol"] ?? fields[COL.TRADINGSYMBOL] ?? "";
|
|
@@ -20625,13 +20615,23 @@ class ZerodhaBroker {
|
|
|
20625
20615
|
id = "zerodha";
|
|
20626
20616
|
name = "Zerodha";
|
|
20627
20617
|
instruments;
|
|
20618
|
+
has = {
|
|
20619
|
+
bulkDump: true,
|
|
20620
|
+
searchAPI: false,
|
|
20621
|
+
optionChain: false,
|
|
20622
|
+
historicalCandles: true,
|
|
20623
|
+
websocket: true,
|
|
20624
|
+
pnlReport: false
|
|
20625
|
+
};
|
|
20628
20626
|
session = null;
|
|
20629
20627
|
kite = null;
|
|
20630
20628
|
socket = null;
|
|
20631
20629
|
apiKey = "";
|
|
20632
20630
|
KiteConnect = null;
|
|
20633
|
-
|
|
20631
|
+
_iMaster;
|
|
20632
|
+
constructor(options) {
|
|
20634
20633
|
this.instruments = new ZerodhaInstruments;
|
|
20634
|
+
this._iMaster = new InstrumentMaster(options);
|
|
20635
20635
|
}
|
|
20636
20636
|
async authenticate(creds) {
|
|
20637
20637
|
this.apiKey = creds.apiKey;
|
|
@@ -20654,10 +20654,34 @@ class ZerodhaBroker {
|
|
|
20654
20654
|
return null;
|
|
20655
20655
|
return new Date(this.session.expiresAt);
|
|
20656
20656
|
}
|
|
20657
|
+
async sync(force) {
|
|
20658
|
+
return this._iMaster.syncBroker(this.id, this.instruments, force);
|
|
20659
|
+
}
|
|
20660
|
+
resolve(input) {
|
|
20661
|
+
return this._iMaster.resolve(input);
|
|
20662
|
+
}
|
|
20663
|
+
search(query, exchange, instrumentType, limit) {
|
|
20664
|
+
return this._iMaster.search(query, exchange, instrumentType, limit);
|
|
20665
|
+
}
|
|
20657
20666
|
async placeOrder(params) {
|
|
20658
20667
|
try {
|
|
20668
|
+
let resolvedParams = params;
|
|
20669
|
+
if (!params.exchange) {
|
|
20670
|
+
const resolved = this._iMaster.resolve(params.tradingSymbol);
|
|
20671
|
+
if (!resolved.ok) {
|
|
20672
|
+
const asyncResolved = await this._iMaster.resolveAsync(params.tradingSymbol, this.id, this.instruments);
|
|
20673
|
+
if (!asyncResolved.ok) {
|
|
20674
|
+
return Err(new Error(`Cannot resolve "${params.tradingSymbol}". Either run broker.sync() first to use unified nsekit symbols, or provide exchange and the broker-native tradingSymbol directly.`));
|
|
20675
|
+
}
|
|
20676
|
+
const nativeSymbol = asyncResolved.value.brokerTokens.zerodha?.tradingsymbol ?? params.tradingSymbol;
|
|
20677
|
+
resolvedParams = { ...params, exchange: asyncResolved.value.exchange, tradingSymbol: nativeSymbol };
|
|
20678
|
+
} else {
|
|
20679
|
+
const nativeSymbol = resolved.value.brokerTokens.zerodha?.tradingsymbol ?? params.tradingSymbol;
|
|
20680
|
+
resolvedParams = { ...params, exchange: resolved.value.exchange, tradingSymbol: nativeSymbol };
|
|
20681
|
+
}
|
|
20682
|
+
}
|
|
20659
20683
|
const kite = await this.ensureKite();
|
|
20660
|
-
const kiteParams = toOrderParams(
|
|
20684
|
+
const kiteParams = toOrderParams(resolvedParams);
|
|
20661
20685
|
const res = await kite.placeOrder("regular", kiteParams);
|
|
20662
20686
|
return Ok({
|
|
20663
20687
|
orderId: res.order_id,
|
|
@@ -20988,7 +21012,7 @@ var VALIDITY_FROM_SHOONYA = {
|
|
|
20988
21012
|
IOC: "IOC"
|
|
20989
21013
|
};
|
|
20990
21014
|
var SHOONYA_API_BASE = "https://api.shoonya.com/NorenWClientTP";
|
|
20991
|
-
var SHOONYA_WS_URL = "wss://api.shoonya.com/NorenWSTP";
|
|
21015
|
+
var SHOONYA_WS_URL = "wss://api.shoonya.com/NorenWSTP/";
|
|
20992
21016
|
var SHOONYA_INSTRUMENTS_BASE = "https://api.shoonya.com/";
|
|
20993
21017
|
var SHOONYA_INSTRUMENT_FILES = {
|
|
20994
21018
|
NSE: "NSE_symbols.txt.zip",
|
|
@@ -21288,6 +21312,7 @@ function fromQuote2(quote) {
|
|
|
21288
21312
|
}
|
|
21289
21313
|
|
|
21290
21314
|
// src/brokers/finvasia/finvasia-socket.ts
|
|
21315
|
+
import WS from "ws";
|
|
21291
21316
|
var subIdCounter3 = 0;
|
|
21292
21317
|
function nextSubId3() {
|
|
21293
21318
|
subIdCounter3 += 1;
|
|
@@ -21314,12 +21339,13 @@ class FinvasiaSocket {
|
|
|
21314
21339
|
return;
|
|
21315
21340
|
this.state = "CONNECTING";
|
|
21316
21341
|
try {
|
|
21317
|
-
this.ws = new
|
|
21342
|
+
this.ws = new WS(SHOONYA_WS_URL);
|
|
21318
21343
|
} catch {
|
|
21319
21344
|
this.state = "DISCONNECTED";
|
|
21320
21345
|
return;
|
|
21321
21346
|
}
|
|
21322
|
-
this.ws.
|
|
21347
|
+
this.ws.on("open", () => {
|
|
21348
|
+
console.log(`[FinvasiaSocket] WS open, sending auth for uid=${this.userId}`);
|
|
21323
21349
|
const authMsg = JSON.stringify({
|
|
21324
21350
|
t: "c",
|
|
21325
21351
|
uid: this.userId,
|
|
@@ -21328,18 +21354,23 @@ class FinvasiaSocket {
|
|
|
21328
21354
|
source: "API"
|
|
21329
21355
|
});
|
|
21330
21356
|
this.ws.send(authMsg);
|
|
21331
|
-
};
|
|
21332
|
-
this.ws.
|
|
21357
|
+
});
|
|
21358
|
+
this.ws.on("message", (raw) => {
|
|
21333
21359
|
try {
|
|
21334
|
-
const
|
|
21360
|
+
const text = raw.toString();
|
|
21361
|
+
console.log(`[FinvasiaSocket] WS msg: ${text.slice(0, 200)}`);
|
|
21362
|
+
const data = JSON.parse(text);
|
|
21335
21363
|
this.handleMessage(data);
|
|
21336
21364
|
} catch {}
|
|
21337
|
-
};
|
|
21338
|
-
this.ws.
|
|
21365
|
+
});
|
|
21366
|
+
this.ws.on("close", (code, reason) => {
|
|
21367
|
+
console.error(`[FinvasiaSocket] WS closed: code=${code}, reason=${reason.toString()}`);
|
|
21339
21368
|
this.state = "DISCONNECTED";
|
|
21340
21369
|
this.attemptReconnect();
|
|
21341
|
-
};
|
|
21342
|
-
this.ws.
|
|
21370
|
+
});
|
|
21371
|
+
this.ws.on("error", (err) => {
|
|
21372
|
+
console.error(`[FinvasiaSocket] WS error:`, err.message);
|
|
21373
|
+
});
|
|
21343
21374
|
}
|
|
21344
21375
|
disconnect() {
|
|
21345
21376
|
this.clearReconnectTimer();
|
|
@@ -21410,9 +21441,12 @@ class FinvasiaSocket {
|
|
|
21410
21441
|
}
|
|
21411
21442
|
if (type === "tf" || type === "tk" || type === "dk" || type === "df") {
|
|
21412
21443
|
const tick = data;
|
|
21413
|
-
const
|
|
21414
|
-
const
|
|
21444
|
+
const rawToken = tick.tk;
|
|
21445
|
+
const exch = data["e"] ?? "";
|
|
21446
|
+
const fullKey = exch ? `${exch}|${rawToken}` : rawToken;
|
|
21447
|
+
const symbol = this.tokenToSymbol.get(fullKey) ?? this.tokenToSymbol.get(rawToken);
|
|
21415
21448
|
const unified = fromTick2(tick, symbol);
|
|
21449
|
+
unified.token = fullKey;
|
|
21416
21450
|
this.dispatchTick(unified);
|
|
21417
21451
|
return;
|
|
21418
21452
|
}
|
|
@@ -21576,25 +21610,7 @@ class FinvasiaInstruments {
|
|
|
21576
21610
|
}
|
|
21577
21611
|
}
|
|
21578
21612
|
}
|
|
21579
|
-
async
|
|
21580
|
-
const firstFile = Object.values(SHOONYA_INSTRUMENT_FILES)[0];
|
|
21581
|
-
const url = `${SHOONYA_INSTRUMENTS_BASE}${firstFile}`;
|
|
21582
|
-
try {
|
|
21583
|
-
const response = await fetch(url, { method: "HEAD" });
|
|
21584
|
-
if (!response.ok)
|
|
21585
|
-
return true;
|
|
21586
|
-
const etag = response.headers.get("etag");
|
|
21587
|
-
const lastModified = response.headers.get("last-modified");
|
|
21588
|
-
if (etag && lastSync.etag)
|
|
21589
|
-
return etag !== lastSync.etag;
|
|
21590
|
-
if (lastModified && lastSync.lastModified)
|
|
21591
|
-
return lastModified !== lastSync.lastModified;
|
|
21592
|
-
return true;
|
|
21593
|
-
} catch {
|
|
21594
|
-
return true;
|
|
21595
|
-
}
|
|
21596
|
-
}
|
|
21597
|
-
async search(query, exchange) {
|
|
21613
|
+
async searchAPI(query, exchange) {
|
|
21598
21614
|
if (!this.accessToken) {
|
|
21599
21615
|
return Err(new Error("Finvasia search requires authentication. Call setCredentials() first."));
|
|
21600
21616
|
}
|
|
@@ -21634,16 +21650,6 @@ class FinvasiaInstruments {
|
|
|
21634
21650
|
return Err(err instanceof Error ? err : new Error(String(err)));
|
|
21635
21651
|
}
|
|
21636
21652
|
}
|
|
21637
|
-
async resolve(symbol, exchange) {
|
|
21638
|
-
const result = await this.search(symbol, exchange);
|
|
21639
|
-
if (!result.ok)
|
|
21640
|
-
return result;
|
|
21641
|
-
const match = result.value.find((e) => e.tradingSymbol === symbol && e.exchange === exchange);
|
|
21642
|
-
if (!match) {
|
|
21643
|
-
return Err(new Error(`Instrument ${symbol} not found on ${exchange} (Finvasia)`));
|
|
21644
|
-
}
|
|
21645
|
-
return Ok(match);
|
|
21646
|
-
}
|
|
21647
21653
|
normalize(raw) {
|
|
21648
21654
|
const fields = raw;
|
|
21649
21655
|
const exchangeRaw = fields["exchange"] ?? fields["exch"] ?? fields["_exchange"] ?? "NSE";
|
|
@@ -21679,12 +21685,22 @@ class FinvasiaBroker {
|
|
|
21679
21685
|
id = "finvasia";
|
|
21680
21686
|
name = "Finvasia (Shoonya)";
|
|
21681
21687
|
instruments;
|
|
21688
|
+
has = {
|
|
21689
|
+
bulkDump: true,
|
|
21690
|
+
searchAPI: true,
|
|
21691
|
+
optionChain: true,
|
|
21692
|
+
historicalCandles: true,
|
|
21693
|
+
websocket: true,
|
|
21694
|
+
pnlReport: false
|
|
21695
|
+
};
|
|
21682
21696
|
session = null;
|
|
21683
21697
|
socket = null;
|
|
21684
21698
|
instrumentsImpl;
|
|
21685
|
-
|
|
21699
|
+
_iMaster;
|
|
21700
|
+
constructor(options) {
|
|
21686
21701
|
this.instrumentsImpl = new FinvasiaInstruments;
|
|
21687
21702
|
this.instruments = this.instrumentsImpl;
|
|
21703
|
+
this._iMaster = new InstrumentMaster(options);
|
|
21688
21704
|
}
|
|
21689
21705
|
async authenticate(creds) {
|
|
21690
21706
|
const result = await authenticate2(creds);
|
|
@@ -21705,10 +21721,34 @@ class FinvasiaBroker {
|
|
|
21705
21721
|
return null;
|
|
21706
21722
|
return new Date(this.session.expiresAt);
|
|
21707
21723
|
}
|
|
21724
|
+
async sync(force) {
|
|
21725
|
+
return this._iMaster.syncBroker(this.id, this.instruments, force);
|
|
21726
|
+
}
|
|
21727
|
+
resolve(input) {
|
|
21728
|
+
return this._iMaster.resolve(input);
|
|
21729
|
+
}
|
|
21730
|
+
search(query, exchange, instrumentType, limit) {
|
|
21731
|
+
return this._iMaster.search(query, exchange, instrumentType, limit);
|
|
21732
|
+
}
|
|
21708
21733
|
async placeOrder(params) {
|
|
21709
21734
|
try {
|
|
21735
|
+
let resolvedParams = params;
|
|
21736
|
+
if (!params.exchange) {
|
|
21737
|
+
const resolved = this._iMaster.resolve(params.tradingSymbol);
|
|
21738
|
+
if (!resolved.ok) {
|
|
21739
|
+
const asyncResolved = await this._iMaster.resolveAsync(params.tradingSymbol, this.id, this.instruments);
|
|
21740
|
+
if (!asyncResolved.ok) {
|
|
21741
|
+
return Err(new Error(`Cannot resolve "${params.tradingSymbol}". Either run broker.sync() first to use unified nsekit symbols, or provide exchange and the broker-native tradingSymbol directly.`));
|
|
21742
|
+
}
|
|
21743
|
+
const nativeSymbol = asyncResolved.value.brokerTokens.finvasia?.tsym ?? params.tradingSymbol;
|
|
21744
|
+
resolvedParams = { ...params, exchange: asyncResolved.value.exchange, tradingSymbol: nativeSymbol };
|
|
21745
|
+
} else {
|
|
21746
|
+
const nativeSymbol = resolved.value.brokerTokens.finvasia?.tsym ?? params.tradingSymbol;
|
|
21747
|
+
resolvedParams = { ...params, exchange: resolved.value.exchange, tradingSymbol: nativeSymbol };
|
|
21748
|
+
}
|
|
21749
|
+
}
|
|
21710
21750
|
const uid = this.session?.userId ?? "";
|
|
21711
|
-
const shoonyaParams = toOrderParams2(
|
|
21751
|
+
const shoonyaParams = toOrderParams2(resolvedParams, uid, uid);
|
|
21712
21752
|
const res = await this.post("PlaceOrder", shoonyaParams);
|
|
21713
21753
|
if (res.stat !== "Ok" || !res.norenordno) {
|
|
21714
21754
|
return Err(new Error(`Order placement failed: ${res.emsg ?? "Unknown error"}`));
|
|
@@ -21726,20 +21766,28 @@ class FinvasiaBroker {
|
|
|
21726
21766
|
async modifyOrder(orderId, params) {
|
|
21727
21767
|
try {
|
|
21728
21768
|
const uid = this.session?.userId ?? "";
|
|
21729
|
-
const
|
|
21769
|
+
const histRaw = await this.post("SingleOrdHist", {
|
|
21730
21770
|
uid,
|
|
21731
21771
|
norenordno: orderId
|
|
21772
|
+
});
|
|
21773
|
+
if (!Array.isArray(histRaw) || histRaw.length === 0) {
|
|
21774
|
+
return Err(new Error(`Cannot modify order ${orderId}: order not found`));
|
|
21775
|
+
}
|
|
21776
|
+
const latestOrder = histRaw[histRaw.length - 1];
|
|
21777
|
+
const payload = {
|
|
21778
|
+
uid,
|
|
21779
|
+
norenordno: orderId,
|
|
21780
|
+
exch: latestOrder.exch,
|
|
21781
|
+
tsym: latestOrder.tsym,
|
|
21782
|
+
prctyp: latestOrder.prctyp,
|
|
21783
|
+
prc: String(params.price ?? latestOrder.prc),
|
|
21784
|
+
qty: String(params.quantity ?? latestOrder.qty),
|
|
21785
|
+
ret: params.validity ?? latestOrder.ret
|
|
21732
21786
|
};
|
|
21733
|
-
if (params.price !== undefined)
|
|
21734
|
-
payload["prc"] = String(params.price);
|
|
21735
|
-
if (params.quantity !== undefined)
|
|
21736
|
-
payload["qty"] = String(params.quantity);
|
|
21737
21787
|
if (params.triggerPrice !== undefined)
|
|
21738
21788
|
payload["trgprc"] = String(params.triggerPrice);
|
|
21739
21789
|
if (params.type !== undefined)
|
|
21740
21790
|
payload["prctyp"] = params.type;
|
|
21741
|
-
if (params.validity !== undefined)
|
|
21742
|
-
payload["ret"] = params.validity;
|
|
21743
21791
|
const res = await this.post("ModifyOrder", payload);
|
|
21744
21792
|
if (res.stat !== "Ok") {
|
|
21745
21793
|
return Err(new Error(`Order modification failed: ${res.emsg ?? "Unknown error"}`));
|
|
@@ -21809,7 +21857,7 @@ class FinvasiaBroker {
|
|
|
21809
21857
|
async getPositions() {
|
|
21810
21858
|
try {
|
|
21811
21859
|
const uid = this.session?.userId ?? "";
|
|
21812
|
-
const raw = await this.post("PositionBook", { uid });
|
|
21860
|
+
const raw = await this.post("PositionBook", { uid, actid: uid });
|
|
21813
21861
|
if (!Array.isArray(raw))
|
|
21814
21862
|
return Ok([]);
|
|
21815
21863
|
return Ok(raw.map(fromPosition2));
|
|
@@ -22083,7 +22131,7 @@ var EXCHANGE_FROM_DHAN = {
|
|
|
22083
22131
|
NSE_CURRENCY: "CDS"
|
|
22084
22132
|
};
|
|
22085
22133
|
var PRODUCT_TO_DHAN = {
|
|
22086
|
-
INTRADAY: "
|
|
22134
|
+
INTRADAY: "INTRADAY",
|
|
22087
22135
|
DELIVERY: "CNC",
|
|
22088
22136
|
NORMAL: "MARGIN"
|
|
22089
22137
|
};
|
|
@@ -22361,11 +22409,28 @@ function fromQuote3(quote, symbol, exchange) {
|
|
|
22361
22409
|
}
|
|
22362
22410
|
|
|
22363
22411
|
// src/brokers/dhan/dhan-socket.ts
|
|
22412
|
+
import WS2 from "ws";
|
|
22364
22413
|
var subIdCounter4 = 0;
|
|
22365
22414
|
function nextSubId4() {
|
|
22366
22415
|
subIdCounter4 += 1;
|
|
22367
22416
|
return `dsub_${subIdCounter4}`;
|
|
22368
22417
|
}
|
|
22418
|
+
var EXCH_SEG_FROM_BYTE = {
|
|
22419
|
+
0: "IDX",
|
|
22420
|
+
1: "NSE_EQ",
|
|
22421
|
+
2: "NSE_FNO",
|
|
22422
|
+
3: "NSE_CURRENCY",
|
|
22423
|
+
4: "BSE_EQ",
|
|
22424
|
+
5: "BSE_FNO",
|
|
22425
|
+
6: "MCX_COMM"
|
|
22426
|
+
};
|
|
22427
|
+
function splitToken(token) {
|
|
22428
|
+
const sep = token.includes("|") ? "|" : ":";
|
|
22429
|
+
const idx = token.indexOf(sep);
|
|
22430
|
+
if (idx === -1)
|
|
22431
|
+
return ["NSE_EQ", token];
|
|
22432
|
+
return [token.slice(0, idx), token.slice(idx + 1)];
|
|
22433
|
+
}
|
|
22369
22434
|
|
|
22370
22435
|
class DhanSocket {
|
|
22371
22436
|
ws = null;
|
|
@@ -22389,36 +22454,36 @@ class DhanSocket {
|
|
|
22389
22454
|
this.state = "CONNECTING";
|
|
22390
22455
|
try {
|
|
22391
22456
|
const url = `${DHAN_WS_URL}?version=2&token=${this.accessToken}&clientId=${this.clientId}&authType=2`;
|
|
22392
|
-
this.ws = new
|
|
22393
|
-
this.ws.binaryType = "arraybuffer";
|
|
22457
|
+
this.ws = new WS2(url);
|
|
22394
22458
|
} catch {
|
|
22395
22459
|
this.state = "DISCONNECTED";
|
|
22396
22460
|
return;
|
|
22397
22461
|
}
|
|
22398
|
-
this.ws.
|
|
22462
|
+
this.ws.on("open", () => {
|
|
22399
22463
|
this.state = "CONNECTED";
|
|
22400
22464
|
this.reconnectAttempts = 0;
|
|
22401
22465
|
this.startHeartbeat();
|
|
22402
22466
|
if (this.subscribedTokens.size > 0) {
|
|
22403
22467
|
this.sendSubscribe(Array.from(this.subscribedTokens));
|
|
22404
22468
|
}
|
|
22405
|
-
};
|
|
22406
|
-
this.ws.
|
|
22469
|
+
});
|
|
22470
|
+
this.ws.on("message", (raw, isBinary) => {
|
|
22407
22471
|
try {
|
|
22408
|
-
if (
|
|
22409
|
-
|
|
22472
|
+
if (isBinary) {
|
|
22473
|
+
const buf = raw instanceof ArrayBuffer ? Buffer.from(raw) : Buffer.isBuffer(raw) ? raw : Array.isArray(raw) ? Buffer.concat(raw) : Buffer.from(raw);
|
|
22474
|
+
this.handleBinaryMessage(buf);
|
|
22410
22475
|
} else {
|
|
22411
|
-
const data = JSON.parse(
|
|
22476
|
+
const data = JSON.parse(raw.toString());
|
|
22412
22477
|
this.handleJsonMessage(data);
|
|
22413
22478
|
}
|
|
22414
22479
|
} catch {}
|
|
22415
|
-
};
|
|
22416
|
-
this.ws.
|
|
22480
|
+
});
|
|
22481
|
+
this.ws.on("close", () => {
|
|
22417
22482
|
this.state = "DISCONNECTED";
|
|
22418
22483
|
this.stopHeartbeat();
|
|
22419
22484
|
this.attemptReconnect();
|
|
22420
|
-
};
|
|
22421
|
-
this.ws.
|
|
22485
|
+
});
|
|
22486
|
+
this.ws.on("error", () => {});
|
|
22422
22487
|
}
|
|
22423
22488
|
disconnect() {
|
|
22424
22489
|
this.clearReconnectTimer();
|
|
@@ -22476,39 +22541,74 @@ class DhanSocket {
|
|
|
22476
22541
|
this.tokenToSymbol.set(token, symbol);
|
|
22477
22542
|
}
|
|
22478
22543
|
}
|
|
22479
|
-
handleBinaryMessage(
|
|
22480
|
-
|
|
22481
|
-
if (buffer.byteLength < 48)
|
|
22544
|
+
handleBinaryMessage(data) {
|
|
22545
|
+
if (data.length < 8)
|
|
22482
22546
|
return;
|
|
22483
|
-
|
|
22547
|
+
const responseCode = data.readUInt8(0);
|
|
22548
|
+
const exchSegByte = data.readUInt8(3);
|
|
22549
|
+
const securityId = data.readInt32LE(4);
|
|
22550
|
+
const exchangeSegment = EXCH_SEG_FROM_BYTE[exchSegByte] ?? "NSE_EQ";
|
|
22551
|
+
const fullKey = `${exchangeSegment}|${securityId}`;
|
|
22552
|
+
if (responseCode === 2 && data.length >= 16) {
|
|
22553
|
+
const ltp = data.readFloatLE(8);
|
|
22554
|
+
const ltt = data.readInt32LE(12);
|
|
22484
22555
|
const tick = {
|
|
22485
|
-
securityId
|
|
22486
|
-
LTP:
|
|
22487
|
-
open:
|
|
22488
|
-
high:
|
|
22489
|
-
low:
|
|
22490
|
-
close:
|
|
22491
|
-
volume:
|
|
22492
|
-
|
|
22493
|
-
|
|
22494
|
-
|
|
22495
|
-
|
|
22496
|
-
|
|
22497
|
-
|
|
22498
|
-
timestamp: Date.now()
|
|
22556
|
+
securityId,
|
|
22557
|
+
LTP: ltp,
|
|
22558
|
+
open: 0,
|
|
22559
|
+
high: 0,
|
|
22560
|
+
low: 0,
|
|
22561
|
+
close: 0,
|
|
22562
|
+
volume: 0,
|
|
22563
|
+
bestBidPrice: 0,
|
|
22564
|
+
bestAskPrice: 0,
|
|
22565
|
+
bestBidQty: 0,
|
|
22566
|
+
bestAskQty: 0,
|
|
22567
|
+
exchangeSegment,
|
|
22568
|
+
timestamp: ltt > 0 ? ltt * 1000 : Date.now()
|
|
22499
22569
|
};
|
|
22500
|
-
const
|
|
22501
|
-
const symbol = this.tokenToSymbol.get(tokenStr);
|
|
22570
|
+
const symbol = this.tokenToSymbol.get(fullKey) ?? this.tokenToSymbol.get(String(securityId));
|
|
22502
22571
|
const unified = fromTick3(tick, symbol);
|
|
22572
|
+
unified.token = fullKey;
|
|
22503
22573
|
this.dispatchTick(unified);
|
|
22504
|
-
}
|
|
22574
|
+
} else if (responseCode === 4 && data.length >= 50) {
|
|
22575
|
+
const ltp = data.readFloatLE(8);
|
|
22576
|
+
const ltt = data.readInt32LE(14);
|
|
22577
|
+
const volume = data.readInt32LE(22);
|
|
22578
|
+
const totalSellQty = data.readInt32LE(26);
|
|
22579
|
+
const totalBuyQty = data.readInt32LE(30);
|
|
22580
|
+
const open = data.readFloatLE(34);
|
|
22581
|
+
const close = data.readFloatLE(38);
|
|
22582
|
+
const high = data.readFloatLE(42);
|
|
22583
|
+
const low = data.readFloatLE(46);
|
|
22584
|
+
const tick = {
|
|
22585
|
+
securityId,
|
|
22586
|
+
LTP: ltp,
|
|
22587
|
+
open,
|
|
22588
|
+
high,
|
|
22589
|
+
low,
|
|
22590
|
+
close,
|
|
22591
|
+
volume,
|
|
22592
|
+
bestBidPrice: 0,
|
|
22593
|
+
bestAskPrice: 0,
|
|
22594
|
+
bestBidQty: totalBuyQty,
|
|
22595
|
+
bestAskQty: totalSellQty,
|
|
22596
|
+
exchangeSegment,
|
|
22597
|
+
timestamp: ltt > 0 ? ltt * 1000 : Date.now()
|
|
22598
|
+
};
|
|
22599
|
+
const symbol = this.tokenToSymbol.get(fullKey) ?? this.tokenToSymbol.get(String(securityId));
|
|
22600
|
+
const unified = fromTick3(tick, symbol);
|
|
22601
|
+
unified.token = fullKey;
|
|
22602
|
+
this.dispatchTick(unified);
|
|
22603
|
+
}
|
|
22505
22604
|
}
|
|
22506
22605
|
handleJsonMessage(data) {
|
|
22507
22606
|
if (data["type"] === "ticker_data") {
|
|
22508
22607
|
const tick = data;
|
|
22509
|
-
const
|
|
22510
|
-
const symbol = this.tokenToSymbol.get(
|
|
22608
|
+
const fullKey = tick.exchangeSegment ? `${tick.exchangeSegment}|${tick.securityId}` : String(tick.securityId);
|
|
22609
|
+
const symbol = this.tokenToSymbol.get(fullKey) ?? this.tokenToSymbol.get(String(tick.securityId));
|
|
22511
22610
|
const unified = fromTick3(tick, symbol);
|
|
22611
|
+
unified.token = fullKey;
|
|
22512
22612
|
this.dispatchTick(unified);
|
|
22513
22613
|
}
|
|
22514
22614
|
}
|
|
@@ -22516,10 +22616,10 @@ class DhanSocket {
|
|
|
22516
22616
|
if (!this.ws || this.state !== "CONNECTED")
|
|
22517
22617
|
return;
|
|
22518
22618
|
const instruments = tokens.map((t) => {
|
|
22519
|
-
const
|
|
22619
|
+
const [segment, id] = splitToken(t);
|
|
22520
22620
|
return {
|
|
22521
|
-
ExchangeSegment:
|
|
22522
|
-
SecurityId:
|
|
22621
|
+
ExchangeSegment: segment,
|
|
22622
|
+
SecurityId: id
|
|
22523
22623
|
};
|
|
22524
22624
|
});
|
|
22525
22625
|
const request = {
|
|
@@ -22533,10 +22633,10 @@ class DhanSocket {
|
|
|
22533
22633
|
if (!this.ws || this.state !== "CONNECTED")
|
|
22534
22634
|
return;
|
|
22535
22635
|
const instruments = tokens.map((t) => {
|
|
22536
|
-
const
|
|
22636
|
+
const [segment, id] = splitToken(t);
|
|
22537
22637
|
return {
|
|
22538
|
-
ExchangeSegment:
|
|
22539
|
-
SecurityId:
|
|
22638
|
+
ExchangeSegment: segment,
|
|
22639
|
+
SecurityId: id
|
|
22540
22640
|
};
|
|
22541
22641
|
});
|
|
22542
22642
|
const request = {
|
|
@@ -22560,7 +22660,7 @@ class DhanSocket {
|
|
|
22560
22660
|
this.heartbeatTimer = setInterval(() => {
|
|
22561
22661
|
if (this.ws && this.state === "CONNECTED") {
|
|
22562
22662
|
try {
|
|
22563
|
-
this.ws.
|
|
22663
|
+
this.ws.ping();
|
|
22564
22664
|
} catch {}
|
|
22565
22665
|
}
|
|
22566
22666
|
}, 30000);
|
|
@@ -22695,23 +22795,7 @@ class DhanInstruments {
|
|
|
22695
22795
|
yield row;
|
|
22696
22796
|
}
|
|
22697
22797
|
}
|
|
22698
|
-
async
|
|
22699
|
-
try {
|
|
22700
|
-
const response = await fetch(DHAN_INSTRUMENTS_URL, { method: "HEAD" });
|
|
22701
|
-
if (!response.ok)
|
|
22702
|
-
return true;
|
|
22703
|
-
const etag = response.headers.get("etag");
|
|
22704
|
-
const lastModified = response.headers.get("last-modified");
|
|
22705
|
-
if (etag && lastSync.etag)
|
|
22706
|
-
return etag !== lastSync.etag;
|
|
22707
|
-
if (lastModified && lastSync.lastModified)
|
|
22708
|
-
return lastModified !== lastSync.lastModified;
|
|
22709
|
-
return true;
|
|
22710
|
-
} catch {
|
|
22711
|
-
return true;
|
|
22712
|
-
}
|
|
22713
|
-
}
|
|
22714
|
-
async search(query, exchange) {
|
|
22798
|
+
async searchAPI(query, exchange) {
|
|
22715
22799
|
if (!this.accessToken) {
|
|
22716
22800
|
return Err(new Error("Dhan search requires authentication. Call setCredentials() first."));
|
|
22717
22801
|
}
|
|
@@ -22754,16 +22838,6 @@ class DhanInstruments {
|
|
|
22754
22838
|
return Err(err instanceof Error ? err : new Error(String(err)));
|
|
22755
22839
|
}
|
|
22756
22840
|
}
|
|
22757
|
-
async resolve(symbol, exchange) {
|
|
22758
|
-
const result = await this.search(symbol, exchange);
|
|
22759
|
-
if (!result.ok)
|
|
22760
|
-
return result;
|
|
22761
|
-
const match = result.value.find((e) => e.tradingSymbol === symbol && e.exchange === exchange);
|
|
22762
|
-
if (!match) {
|
|
22763
|
-
return Err(new Error(`Instrument ${symbol} not found on ${exchange} (Dhan)`));
|
|
22764
|
-
}
|
|
22765
|
-
return Ok(match);
|
|
22766
|
-
}
|
|
22767
22841
|
normalize(raw) {
|
|
22768
22842
|
const fields = raw;
|
|
22769
22843
|
const securityId = fields["SEM_SMST_SECURITY_ID"] ?? fields["securityId"] ?? "";
|
|
@@ -22822,13 +22896,23 @@ class DhanBroker {
|
|
|
22822
22896
|
id = "dhan";
|
|
22823
22897
|
name = "Dhan";
|
|
22824
22898
|
instruments;
|
|
22899
|
+
has = {
|
|
22900
|
+
bulkDump: true,
|
|
22901
|
+
searchAPI: true,
|
|
22902
|
+
optionChain: true,
|
|
22903
|
+
historicalCandles: true,
|
|
22904
|
+
websocket: true,
|
|
22905
|
+
pnlReport: false
|
|
22906
|
+
};
|
|
22825
22907
|
session = null;
|
|
22826
22908
|
socket = null;
|
|
22827
22909
|
clientId = "";
|
|
22828
22910
|
instrumentsImpl;
|
|
22829
|
-
|
|
22911
|
+
_iMaster;
|
|
22912
|
+
constructor(options) {
|
|
22830
22913
|
this.instrumentsImpl = new DhanInstruments;
|
|
22831
22914
|
this.instruments = this.instrumentsImpl;
|
|
22915
|
+
this._iMaster = new InstrumentMaster(options);
|
|
22832
22916
|
}
|
|
22833
22917
|
async authenticate(creds) {
|
|
22834
22918
|
this.clientId = creds.userId ?? "";
|
|
@@ -22850,9 +22934,31 @@ class DhanBroker {
|
|
|
22850
22934
|
return null;
|
|
22851
22935
|
return new Date(this.session.expiresAt);
|
|
22852
22936
|
}
|
|
22937
|
+
async sync(force) {
|
|
22938
|
+
return this._iMaster.syncBroker(this.id, this.instruments, force);
|
|
22939
|
+
}
|
|
22940
|
+
resolve(input) {
|
|
22941
|
+
return this._iMaster.resolve(input);
|
|
22942
|
+
}
|
|
22943
|
+
search(query, exchange, instrumentType, limit) {
|
|
22944
|
+
return this._iMaster.search(query, exchange, instrumentType, limit);
|
|
22945
|
+
}
|
|
22853
22946
|
async placeOrder(params) {
|
|
22854
22947
|
try {
|
|
22855
|
-
|
|
22948
|
+
let resolvedParams = params;
|
|
22949
|
+
if (!params.exchange) {
|
|
22950
|
+
const resolved = this._iMaster.resolve(params.tradingSymbol);
|
|
22951
|
+
if (!resolved.ok) {
|
|
22952
|
+
const asyncResolved = await this._iMaster.resolveAsync(params.tradingSymbol, this.id, this.instruments);
|
|
22953
|
+
if (!asyncResolved.ok) {
|
|
22954
|
+
return Err(new Error(`Cannot resolve "${params.tradingSymbol}". Either run broker.sync() first to use unified nsekit symbols, or provide exchange and the broker-native tradingSymbol directly.`));
|
|
22955
|
+
}
|
|
22956
|
+
resolvedParams = { ...params, exchange: asyncResolved.value.exchange };
|
|
22957
|
+
} else {
|
|
22958
|
+
resolvedParams = { ...params, exchange: resolved.value.exchange };
|
|
22959
|
+
}
|
|
22960
|
+
}
|
|
22961
|
+
const dhanParams = toOrderParams3(resolvedParams, this.clientId);
|
|
22856
22962
|
const res = await this.request("POST", "/orders", dhanParams);
|
|
22857
22963
|
return Ok({
|
|
22858
22964
|
orderId: res.orderId,
|
|
@@ -22866,20 +22972,18 @@ class DhanBroker {
|
|
|
22866
22972
|
}
|
|
22867
22973
|
async modifyOrder(orderId, params) {
|
|
22868
22974
|
try {
|
|
22975
|
+
const rawOrder = await this.request("GET", `/orders/${orderId}`);
|
|
22976
|
+
const original = Array.isArray(rawOrder) ? rawOrder[0] : rawOrder;
|
|
22869
22977
|
const payload = {
|
|
22870
22978
|
dhanClientId: this.clientId,
|
|
22871
|
-
orderId
|
|
22979
|
+
orderId,
|
|
22980
|
+
orderType: params.type ? ORDER_TYPE_TO_DHAN[params.type] ?? original.orderType : original.orderType,
|
|
22981
|
+
validity: params.validity ?? original.validity ?? "DAY",
|
|
22982
|
+
quantity: params.quantity ?? original.quantity,
|
|
22983
|
+
price: params.price ?? original.price
|
|
22872
22984
|
};
|
|
22873
|
-
if (params.price !== undefined)
|
|
22874
|
-
payload["price"] = params.price;
|
|
22875
|
-
if (params.quantity !== undefined)
|
|
22876
|
-
payload["quantity"] = params.quantity;
|
|
22877
22985
|
if (params.triggerPrice !== undefined)
|
|
22878
22986
|
payload["triggerPrice"] = params.triggerPrice;
|
|
22879
|
-
if (params.type !== undefined)
|
|
22880
|
-
payload["orderType"] = params.type;
|
|
22881
|
-
if (params.validity !== undefined)
|
|
22882
|
-
payload["validity"] = params.validity;
|
|
22883
22987
|
const res = await this.request("PUT", `/orders/${orderId}`, payload);
|
|
22884
22988
|
return Ok({
|
|
22885
22989
|
orderId: res.orderId ?? orderId,
|
|
@@ -22946,7 +23050,11 @@ class DhanBroker {
|
|
|
22946
23050
|
return Ok([]);
|
|
22947
23051
|
return Ok(raw.map((h) => fromHolding3(h)));
|
|
22948
23052
|
} catch (err) {
|
|
22949
|
-
|
|
23053
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
23054
|
+
if (msg.includes("No holdings available") || msg.includes("DH-1111")) {
|
|
23055
|
+
return Ok([]);
|
|
23056
|
+
}
|
|
23057
|
+
return Err(err instanceof Error ? err : new Error(msg));
|
|
22950
23058
|
}
|
|
22951
23059
|
}
|
|
22952
23060
|
async getLTP(symbols) {
|
|
@@ -23506,6 +23614,14 @@ class PaperBroker {
|
|
|
23506
23614
|
id = "paper";
|
|
23507
23615
|
name = "Paper Trading";
|
|
23508
23616
|
instruments;
|
|
23617
|
+
has = {
|
|
23618
|
+
bulkDump: false,
|
|
23619
|
+
searchAPI: false,
|
|
23620
|
+
optionChain: false,
|
|
23621
|
+
historicalCandles: false,
|
|
23622
|
+
websocket: false,
|
|
23623
|
+
pnlReport: true
|
|
23624
|
+
};
|
|
23509
23625
|
session = null;
|
|
23510
23626
|
engine;
|
|
23511
23627
|
positions = new Map;
|
|
@@ -23516,6 +23632,7 @@ class PaperBroker {
|
|
|
23516
23632
|
initialBalance;
|
|
23517
23633
|
subscriptions = new Map;
|
|
23518
23634
|
connectionState = "DISCONNECTED";
|
|
23635
|
+
_iMaster;
|
|
23519
23636
|
dataSource = null;
|
|
23520
23637
|
dataSourceSub = null;
|
|
23521
23638
|
subIdCounter = 0;
|
|
@@ -23524,6 +23641,10 @@ class PaperBroker {
|
|
|
23524
23641
|
this.initialBalance = config?.initialBalance ?? 1e7;
|
|
23525
23642
|
this.balance = this.initialBalance;
|
|
23526
23643
|
this.engine = new PaperFillEngine(config?.fillConfig);
|
|
23644
|
+
this._iMaster = new InstrumentMaster({
|
|
23645
|
+
redis: config?.redis,
|
|
23646
|
+
instrumentFilePath: config?.instrumentFilePath
|
|
23647
|
+
});
|
|
23527
23648
|
this.engine.setFillCallback((orderId, update) => {
|
|
23528
23649
|
this.onOrderFill(orderId, update);
|
|
23529
23650
|
});
|
|
@@ -23531,6 +23652,20 @@ class PaperBroker {
|
|
|
23531
23652
|
setDataSource(broker) {
|
|
23532
23653
|
this.dataSource = broker;
|
|
23533
23654
|
}
|
|
23655
|
+
async sync(_force) {
|
|
23656
|
+
return Ok({
|
|
23657
|
+
brokerId: "paper",
|
|
23658
|
+
lastSyncAt: Date.now(),
|
|
23659
|
+
instrumentCount: 0,
|
|
23660
|
+
source: "network"
|
|
23661
|
+
});
|
|
23662
|
+
}
|
|
23663
|
+
resolve(input) {
|
|
23664
|
+
return this._iMaster.resolve(input);
|
|
23665
|
+
}
|
|
23666
|
+
search(query, exchange, instrumentType, limit) {
|
|
23667
|
+
return this._iMaster.search(query, exchange, instrumentType, limit);
|
|
23668
|
+
}
|
|
23534
23669
|
async authenticate(_creds) {
|
|
23535
23670
|
this.session = {
|
|
23536
23671
|
accessToken: "paper-session",
|
|
@@ -23798,7 +23933,8 @@ class PaperBroker {
|
|
|
23798
23933
|
for (const sub of this.subscriptions.values()) {}
|
|
23799
23934
|
}
|
|
23800
23935
|
updatePositionOnFill(order, update) {
|
|
23801
|
-
const { tradingSymbol,
|
|
23936
|
+
const { tradingSymbol, side, product } = order.params;
|
|
23937
|
+
const exchange = order.params.exchange ?? "NSE";
|
|
23802
23938
|
const posKey = `${exchange}:${tradingSymbol}:${product}`;
|
|
23803
23939
|
if (!this.positions.has(posKey)) {
|
|
23804
23940
|
this.positions.set(posKey, {
|
|
@@ -23855,7 +23991,7 @@ class PaperBroker {
|
|
|
23855
23991
|
brokerOrderId: pending.orderId,
|
|
23856
23992
|
broker: "paper",
|
|
23857
23993
|
tradingSymbol: pending.params.tradingSymbol,
|
|
23858
|
-
exchange: pending.params.exchange,
|
|
23994
|
+
exchange: pending.params.exchange ?? "NSE",
|
|
23859
23995
|
side: pending.params.side,
|
|
23860
23996
|
type: pending.params.type,
|
|
23861
23997
|
product: pending.params.product,
|
|
@@ -23874,17 +24010,17 @@ class PaperBroker {
|
|
|
23874
24010
|
}
|
|
23875
24011
|
}
|
|
23876
24012
|
// src/index.ts
|
|
23877
|
-
var VERSION = "0.
|
|
23878
|
-
function createBroker(brokerId) {
|
|
24013
|
+
var VERSION = "0.3.0";
|
|
24014
|
+
function createBroker(brokerId, options) {
|
|
23879
24015
|
switch (brokerId) {
|
|
23880
24016
|
case "zerodha":
|
|
23881
|
-
return new ZerodhaBroker;
|
|
24017
|
+
return new ZerodhaBroker(options);
|
|
23882
24018
|
case "finvasia":
|
|
23883
|
-
return new FinvasiaBroker;
|
|
24019
|
+
return new FinvasiaBroker(options);
|
|
23884
24020
|
case "dhan":
|
|
23885
|
-
return new DhanBroker;
|
|
24021
|
+
return new DhanBroker(options);
|
|
23886
24022
|
case "paper":
|
|
23887
|
-
return new PaperBroker;
|
|
24023
|
+
return new PaperBroker(options);
|
|
23888
24024
|
default: {
|
|
23889
24025
|
const exhaustive = brokerId;
|
|
23890
24026
|
throw new Error(`Unknown broker: ${exhaustive}`);
|