Skip to content

Commit f8b3946

Browse files
authored
Merge pull request #124 from stoqey/fix-md-only
feat(md-only): implement market-data-only mode
2 parents f511649 + c65ff24 commit f8b3946

13 files changed

Lines changed: 857 additions & 1017 deletions

File tree

.eslintignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

.eslintrc.js

Lines changed: 0 additions & 46 deletions
This file was deleted.

.github/workflows/publish.yml

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,64 @@ on:
55
branches:
66
- "master"
77

8+
permissions:
9+
contents: read
10+
811
jobs:
912
bump-version:
10-
name: "publish"
13+
name: "bump version"
1114
runs-on: ubuntu-latest
15+
permissions:
16+
contents: write
1217

1318
steps:
1419
- name: "Checkout source code"
15-
uses: "actions/checkout@v4"
20+
uses: actions/checkout@v6
1621
with:
1722
ref: ${{ github.ref }}
1823

1924
# Setup Node.js
2025
- name: "Setup Node.js"
21-
uses: "actions/setup-node@v4"
26+
uses: actions/setup-node@v6
2227
with:
23-
node-version: 18.19.1
28+
node-version: "24"
2429
cache: "yarn" # caches the yarn cache folder not node_modules
2530

2631
# Automated Version Bump
2732
- name: "Automated Version Bump"
28-
uses: "phips28/gh-action-bump-version@master"
33+
uses: "phips28/gh-action-bump-version@215e27a882516826c59df7f09da8c67d5f375cbd"
2934
with:
3035
tag-prefix: ""
3136
env:
3237
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3338

39+
publish:
40+
name: "publish"
41+
needs: bump-version
42+
runs-on: ubuntu-latest
43+
permissions:
44+
contents: read
45+
id-token: write
46+
47+
steps:
48+
- name: "Checkout source code"
49+
uses: actions/checkout@v6
50+
with:
51+
ref: master
52+
3453
# Install packages with yarn
54+
- name: "Setup Node.js"
55+
uses: actions/setup-node@v6
56+
with:
57+
node-version: "24"
58+
registry-url: "https://registry.npmjs.org"
59+
package-manager-cache: false
60+
3561
- name: "Install"
3662
run: yarn install --frozen-lockfile
3763

3864
# Publish the package
3965
- name: "Publishing to Npm registry"
40-
run: |
41-
npm config set //registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN
42-
npm publish
66+
run: npm publish
4367
env:
4468
CI: true
45-
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,30 @@ await ibkr();
5252
// your code
5353
```
5454

55+
### Market-data-only mode
56+
57+
Set `MD_ONLY=true` or `IBKR_MD_ONLY=true` before initialization when a process only needs contract lookup and market data:
58+
59+
```sh
60+
IBKR_MD_ONLY=true
61+
```
62+
63+
```ts
64+
import ibkr, { MarketDataManager } from '@stoqey/ibkr';
65+
66+
await ibkr();
67+
68+
const mkdManager = MarketDataManager.Instance;
69+
const contractDetails = await mkdManager.getContract({
70+
symbol: "ES",
71+
secType: "FUT",
72+
});
73+
```
74+
75+
In market-data-only mode, the package still connects to IBKR and initializes `MarketDataManager`. Contract lookup, contract details, historical data, realtime bars, and tick-by-tick market data remain available.
76+
77+
It skips account summary updates, account/portfolio subscriptions, open-order subscriptions, and order/trade event state. Use this for scanners, feeders, and symbol-search clients. Do not use it for execution clients that place orders or need live portfolio/order state.
78+
5579
### Accounts Summary e.t.c
5680
```ts
5781
import { AccountSummary } from "@stoqey/ibkr";
@@ -226,4 +250,4 @@ Join our Discord community to get help, share ideas, and connect with other deve
226250
<div align="center" >
227251
<img style="background:#231f20;color:white; width:100%;padding:10px" src="./docs/logo_interactive-brokers_white.png"></img>
228252
<h3>Stoqey Inc<h3>
229-
</div>
253+
</div>

eslint.config.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const tsParser = require("@typescript-eslint/parser");
2+
const tsPlugin = require("@typescript-eslint/eslint-plugin");
3+
const importPlugin = require("eslint-plugin-import");
4+
5+
module.exports = [
6+
{
7+
ignores: ["**/*.test.ts", "src/test.ts"],
8+
},
9+
{
10+
files: ["src/**/*.ts"],
11+
languageOptions: {
12+
parser: tsParser,
13+
parserOptions: {
14+
project: "./tsconfig.json",
15+
sourceType: "module",
16+
},
17+
},
18+
plugins: {
19+
"@typescript-eslint": tsPlugin,
20+
import: importPlugin,
21+
},
22+
rules: {
23+
...tsPlugin.configs.recommended.rules,
24+
...importPlugin.configs.errors.rules,
25+
...importPlugin.configs.warnings.rules,
26+
"@typescript-eslint/array-type": "off",
27+
"@typescript-eslint/no-explicit-any": "off",
28+
"@typescript-eslint/no-unused-vars": "off",
29+
"@typescript-eslint/explicit-function-return-type": "off",
30+
"@typescript-eslint/no-empty-function": "off",
31+
"@typescript-eslint/no-require-imports": "off",
32+
"@typescript-eslint/no-this-alias": "off",
33+
"@typescript-eslint/no-wrapper-object-types": "off",
34+
"import/default": "off",
35+
"import/order": "off",
36+
"import/no-duplicates": "off",
37+
"import/no-named-as-default": "off",
38+
"import/no-named-as-default-member": "off",
39+
"import/no-unresolved": "off",
40+
"import/named": "off",
41+
"import/namespace": "off",
42+
"sort-imports": "off",
43+
},
44+
},
45+
];

package.json

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"LICENSE"
1212
],
1313
"scripts": {
14-
"lint": "tslint \"src/**/*.ts\" --project tsconfig.json",
14+
"lint": "eslint ./src --ext=ts",
1515
"build": "rimraf dist && tsc",
1616
"dev": "nodemon src/dev",
1717
"account": "mocha src/account/*test.ts --exit",
@@ -68,26 +68,16 @@
6868
"@types/lodash": "^4.17.16",
6969
"@types/mocha": "^10.0.10",
7070
"@types/node": "^22.13.10",
71-
"@types/source-map-support": "^0.5.10",
72-
"@typescript-eslint/eslint-plugin": "^8.26.1",
73-
"@typescript-eslint/parser": "^8.26.1",
71+
"@typescript-eslint/eslint-plugin": "^8.59.3",
72+
"@typescript-eslint/parser": "^8.59.3",
7473
"chai": "^5.2.0",
75-
"eslint": "^9.22.0",
76-
"eslint-config-prettier": "^10.1.1",
77-
"eslint-loader": "^4.0.2",
74+
"eslint": "^9.39.2",
7875
"eslint-plugin-import": "^2.31.0",
79-
"eslint-plugin-json": "^4.0.1",
80-
"eslint-plugin-prettier": "^5.2.3",
81-
"eslint-plugin-simple-import-sort": "^12.1.1",
82-
"eslint-plugin-typescript": "^0.14.0",
8376
"husky": "^9.1.7",
84-
"lint-staged": "^15.5.0",
85-
"mocha": "^11.1.0",
77+
"lint-staged": "^17.0.4",
78+
"mocha": "^11.7.5",
8679
"nodemon": "^3.1.9",
87-
"prettier": "^2.0.5",
88-
"rimraf": "^2.5.4",
89-
"tslint": "^6.1.3",
90-
"tslint-config-standard": "^9.0.0",
80+
"rimraf": "^6.1.3",
9181
"tsx": "^4.19.2",
9282
"typescript": "^5.8.2"
9383
},
@@ -100,8 +90,11 @@
10090
"async-mutex": "^0.5.0",
10191
"debug": "^4.4.0",
10292
"dotenv": "^16.4.7",
103-
"lodash": "^4.17.21",
93+
"lodash": "^4.18.1",
10494
"moment": "^2.30.1",
10595
"rxjs": "^7.8.2"
96+
},
97+
"resolutions": {
98+
"mocha/serialize-javascript": "7.0.3"
10699
}
107100
}

src/account/AccountSummary.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IBApiNext } from "@stoqey/ib";
2-
import IBKRConnection from "../connection/IBKRConnection";
2+
import IBKRConnection, { isMarketDataOnly } from "../connection/IBKRConnection";
33
import { Subscription } from "rxjs";
44
import { log } from "../utils";
55
const DEFAULT_TAGS = "AccountType,NetLiquidation,TotalCashValue,SettledCash,AccruedCash,BuyingPower,EquityWithLoanValue,PreviousDayEquityWithLoanValue,GrossPositionValue,RegTEquity,RegTMargin,SMA,InitMarginReq,MaintMarginReq,AvailableFunds,ExcessLiquidity,Cushion,FullInitMarginReq,FullMaintMarginReq,FullAvailableFunds,FullExcessLiquidity,LookAheadNextChange,LookAheadInitMarginReq,LookAheadMaintMarginReq,LookAheadAvailableFunds,LookAheadExcessLiquidity,HighestSeverity,DayTradesRemaining,Leverage";
@@ -144,6 +144,10 @@ export class AccountSummary {
144144
}
145145

146146
init = () => {
147+
if (isMarketDataOnly()) {
148+
log("AccountSummary.init", "MD_ONLY enabled, skipping account summary init");
149+
return;
150+
}
147151
const ib = IBKRConnection.Instance.ib;
148152
if (!this.ib) {
149153
this.ib = ib;
@@ -158,6 +162,10 @@ export class AccountSummary {
158162
}
159163

160164
getAccountSummaryUpdates = (group: string = "All", tags: string = DEFAULT_TAGS) => {
165+
if (isMarketDataOnly()) {
166+
log("AccountSummary.getAccountSummaryUpdates", "MD_ONLY enabled, skipping account summary subscription");
167+
return;
168+
}
161169
this.GetAccountSummaryUpdates = this.ib.getAccountSummary(group, tags).subscribe((accountSummaryUpdate) => {
162170
const firstAccount = accountSummaryUpdate.all.values().next().value;
163171
const accountId = accountSummaryUpdate.all.keys().next().value;
@@ -184,7 +192,7 @@ export class AccountSummary {
184192
}
185193

186194
unsubscribeAccountSummary = () => {
187-
this.GetAccountSummaryUpdates.unsubscribe();
195+
this.GetAccountSummaryUpdates?.unsubscribe();
188196
}
189197

190198
}

0 commit comments

Comments
 (0)