@ethosagent/tools-india-broker-zerodha 0.1.0
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/CHANGELOG.md +3 -0
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +735 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +850 -0
- package/dist/index.js.map +1 -0
- package/dist/panel.d.ts +24 -0
- package/dist/panel.js +394 -0
- package/dist/panel.js.map +1 -0
- package/package.json +116 -0
- package/skills/portfolio_review.md +30 -0
- package/skills/position_sizing.md +4 -0
- package/skills/trade_confirmation.md +36 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/auth.ts","../src/kite-client.ts","../src/store.ts","../src/schema.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { buildLoginUrl, exchangeToken, validateToken } from './auth';\nimport {\n cancelOrder,\n fetchHoldings,\n fetchMargins,\n fetchOrders,\n fetchPositions,\n placeOrder,\n} from './kite-client';\nimport type { HoldingRow } from './store';\nimport { ZerodhaStore } from './store';\n\n// -- Helpers -----------------------------------------------------------------\n\nfunction getPackageRoot(): string {\n const __filename = fileURLToPath(import.meta.url);\n return join(dirname(__filename), '..');\n}\n\nfunction getFlag(args: string[], flag: string): string | undefined {\n const i = args.indexOf(flag);\n return i !== -1 ? args[i + 1] : undefined;\n}\n\nfunction hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag);\n}\n\nfunction getDbPath(): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n const dbPath = process.env.ZERODHA_DB ?? `${home}/.ethos/zerodha/zerodha.db`;\n const dir = dirname(dbPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n return dbPath;\n}\n\nfunction secretsDir(): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n return `${home}/.ethos/secrets/brokers/zerodha`;\n}\n\nfunction readSecret(name: string): string | null {\n try {\n const path = join(secretsDir(), name);\n return readFileSync(path, 'utf-8').trim();\n } catch {\n return null;\n }\n}\n\nfunction writeSecret(name: string, value: string): void {\n const dir = secretsDir();\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(join(dir, name), value, { mode: 0o600 });\n}\n\nfunction getCredentials(): { apiKey: string; accessToken: string } {\n const apiKey = readSecret('apiKey');\n const accessToken = readSecret('accessToken');\n if (!apiKey || !accessToken) {\n console.error(\n 'Missing credentials. Store api_key and access_token in ~/.ethos/secrets/brokers/zerodha/'\n );\n process.exit(1);\n }\n return { apiKey, accessToken };\n}\n\nfunction printHelp(): void {\n console.log(`zerodha-broker — Zerodha Kite Connect CLI for Ethos agents\n\nCommands:\n auth Print login URL and instructions\n auth --request-token TOKEN Exchange request_token for access_token\n auth status Check if stored access token is valid\n\n holdings Print all equity holdings with P&L\n positions Print open positions (intraday + overnight)\n orders Print today's order book\n margins Print available funds and margin utilisation\n\n order --symbol SYM --qty N --side BUY|SELL --type MARKET|LIMIT [--price P]\n Simulate an order (dry-run)\n order --confirm ... Place a real order\n cancel --order-id ID Cancel a pending order\n\n log [--limit N] Print agent order log (default: last 20)\n clean Wipe local cache and order log\n\n version\n help\n\nEnvironment:\n ZERODHA_DB=~/.ethos/zerodha/zerodha.db (default)\n\nExamples:\n zerodha-broker auth\n zerodha-broker auth --request-token abc123\n zerodha-broker auth status\n zerodha-broker holdings\n zerodha-broker order --symbol RELIANCE --qty 10 --side BUY --type LIMIT --price 2980\n zerodha-broker order --symbol RELIANCE --qty 10 --side BUY --type LIMIT --price 2980 --confirm\n`);\n}\n\n// -- Commands ----------------------------------------------------------------\n\nasync function cmdAuth(args: string[]): Promise<void> {\n const requestToken = getFlag(args, '--request-token');\n\n if (args[1] === 'status') {\n const { apiKey, accessToken } = getCredentials();\n const result = await validateToken(apiKey, accessToken);\n if (result.valid) {\n console.log(`Token valid. User: ${result.userId}. Expires: ${result.expiresHint}`);\n } else {\n console.log(`Token expired or invalid. ${result.expiresHint}`);\n console.log(`Run: zerodha-broker auth --request-token TOKEN`);\n }\n return;\n }\n\n if (requestToken) {\n const apiKey = readSecret('apiKey');\n const apiSecret = readSecret('apiSecret');\n if (!apiKey || !apiSecret) {\n console.error('Missing apiKey or apiSecret in ~/.ethos/secrets/brokers/zerodha/');\n process.exit(1);\n }\n\n console.log('Exchanging request_token for access_token...');\n const result = await exchangeToken(apiKey, apiSecret, requestToken);\n writeSecret('accessToken', result.access_token);\n console.log(`Success! User: ${result.user_id}`);\n console.log(`Access token stored. Valid until midnight IST.`);\n return;\n }\n\n // Default: print login URL\n const apiKey = readSecret('apiKey');\n if (!apiKey) {\n console.error('Missing apiKey in ~/.ethos/secrets/brokers/zerodha/apiKey');\n process.exit(1);\n }\n const url = buildLoginUrl(apiKey);\n console.log(`Open this URL in your browser to log in:\\n\\n ${url}\\n`);\n console.log('After login, copy the request_token from the redirect URL and run:');\n console.log(' zerodha-broker auth --request-token TOKEN');\n}\n\nasync function cmdHoldings(): Promise<void> {\n const { apiKey, accessToken } = getCredentials();\n const holdings = await fetchHoldings({ apiKey, accessToken });\n\n if (holdings.length === 0) {\n console.log('No holdings found.');\n return;\n }\n\n // Also cache them\n const store = new ZerodhaStore(getDbPath());\n try {\n const now = Date.now();\n const rows: HoldingRow[] = holdings.map((h) => ({\n symbol: h.tradingsymbol,\n exchange: h.exchange,\n isin: h.isin,\n quantity: h.quantity,\n t1Quantity: h.t1_quantity,\n avgPrice: h.average_price,\n ltp: h.last_price,\n pnl: h.pnl,\n pnlPct:\n h.average_price > 0\n ? Number(((h.pnl / (h.quantity * h.average_price)) * 100).toFixed(2))\n : null,\n dayChange: h.day_change_percentage,\n product: h.product,\n refreshedAt: now,\n }));\n store.replaceHoldings(rows);\n } finally {\n store.close();\n }\n\n console.log('Symbol Qty Avg Price LTP P&L P&L%');\n console.log('─'.repeat(70));\n for (const h of holdings) {\n const pnlPct =\n h.average_price > 0 ? ((h.pnl / (h.quantity * h.average_price)) * 100).toFixed(2) : '0.00';\n console.log(\n `${h.tradingsymbol.padEnd(16)}${String(h.quantity).padStart(4)} ${h.average_price.toFixed(2).padStart(10)} ${h.last_price.toFixed(2).padStart(10)} ${h.pnl.toFixed(2).padStart(10)} ${pnlPct.padStart(6)}%`\n );\n }\n}\n\nasync function cmdPositions(): Promise<void> {\n const { apiKey, accessToken } = getCredentials();\n const positions = await fetchPositions({ apiKey, accessToken });\n\n if (positions.day.length === 0 && positions.net.length === 0) {\n console.log('No open positions.');\n return;\n }\n\n if (positions.day.length > 0) {\n console.log('Day positions:');\n for (const p of positions.day) {\n console.log(\n ` ${p.tradingsymbol} ${p.product} qty=${p.quantity} avg=${p.average_price} ltp=${p.last_price} pnl=${p.pnl}`\n );\n }\n }\n\n if (positions.net.length > 0) {\n console.log('Net positions:');\n for (const p of positions.net) {\n console.log(\n ` ${p.tradingsymbol} ${p.product} qty=${p.quantity} avg=${p.average_price} ltp=${p.last_price} pnl=${p.pnl}`\n );\n }\n }\n}\n\nasync function cmdOrders(): Promise<void> {\n const { apiKey, accessToken } = getCredentials();\n const orders = await fetchOrders({ apiKey, accessToken });\n\n if (orders.length === 0) {\n console.log('No orders today.');\n return;\n }\n\n for (const o of orders) {\n console.log(\n `${o.order_id} ${o.tradingsymbol} ${o.transaction_type} qty=${o.quantity} type=${o.order_type} price=${o.price} status=${o.status} ${o.order_timestamp}`\n );\n }\n}\n\nasync function cmdMargins(): Promise<void> {\n const { apiKey, accessToken } = getCredentials();\n const margins = await fetchMargins({ apiKey, accessToken });\n const eq = margins.equity;\n\n console.log(`Equity margins:`);\n console.log(` Net available: INR ${eq.net}`);\n console.log(` Opening balance: INR ${eq.available.opening_balance}`);\n console.log(` M2M unrealised: INR ${eq.utilised.m2m_unrealised}`);\n console.log(` Exposure used: INR ${eq.utilised.exposure}`);\n console.log(` Option premium: INR ${eq.utilised.option_premium}`);\n console.log(` Equity enabled: ${eq.enabled}`);\n}\n\nasync function cmdOrder(args: string[]): Promise<void> {\n const symbol = getFlag(args, '--symbol');\n const qtyStr = getFlag(args, '--qty');\n const side = getFlag(args, '--side') as 'BUY' | 'SELL' | undefined;\n const orderType = getFlag(args, '--type') as 'MARKET' | 'LIMIT' | undefined;\n const priceStr = getFlag(args, '--price');\n const confirm = hasFlag(args, '--confirm');\n\n if (!symbol || !qtyStr || !side || !orderType) {\n console.error('Required: --symbol, --qty, --side, --type');\n process.exit(1);\n }\n\n const quantity = Number.parseInt(qtyStr, 10);\n const price = priceStr ? Number.parseFloat(priceStr) : undefined;\n const exchange = (getFlag(args, '--exchange') ?? 'NSE') as 'NSE' | 'BSE';\n\n if (confirm) {\n const { apiKey, accessToken } = getCredentials();\n const result = await placeOrder(\n { apiKey, accessToken },\n {\n exchange,\n tradingsymbol: symbol,\n transaction_type: side,\n quantity,\n order_type: orderType,\n product: 'CNC',\n price,\n }\n );\n console.log(`Order placed: ${result.order_id}`);\n\n // Log to store\n const store = new ZerodhaStore(getDbPath());\n try {\n store.logOrder({\n id: crypto.randomUUID(),\n createdAt: Date.now(),\n symbol,\n exchange,\n transaction: side,\n quantity,\n orderType,\n price: price ?? null,\n product: 'CNC',\n dryRun: false,\n kiteOrderId: result.order_id,\n status: 'placed',\n rejectionReason: null,\n agentSession: null,\n });\n } finally {\n store.close();\n }\n } else {\n const priceDesc =\n orderType === 'LIMIT' && price != null ? `LIMIT ${price.toFixed(2)}` : 'MARKET';\n console.log(\n `DRY RUN: Would place ${side} ${quantity} ${symbol} @ ${priceDesc} on ${exchange} (CNC)`\n );\n console.log('Add --confirm to place the order for real.');\n\n // Log dry-run to store\n const store = new ZerodhaStore(getDbPath());\n try {\n store.logOrder({\n id: crypto.randomUUID(),\n createdAt: Date.now(),\n symbol,\n exchange,\n transaction: side,\n quantity,\n orderType,\n price: price ?? null,\n product: 'CNC',\n dryRun: true,\n kiteOrderId: null,\n status: 'dry_run',\n rejectionReason: null,\n agentSession: null,\n });\n } finally {\n store.close();\n }\n }\n}\n\nasync function cmdCancel(args: string[]): Promise<void> {\n const orderId = getFlag(args, '--order-id');\n if (!orderId) {\n console.error('Required: --order-id');\n process.exit(1);\n }\n\n const { apiKey, accessToken } = getCredentials();\n const result = await cancelOrder({ apiKey, accessToken }, orderId);\n console.log(`Order cancelled: ${result.order_id}`);\n}\n\nfunction cmdLog(args: string[]): void {\n const limitStr = getFlag(args, '--limit');\n const limit = limitStr ? Number.parseInt(limitStr, 10) : 20;\n\n const store = new ZerodhaStore(getDbPath());\n try {\n const log = store.getOrderLog(limit);\n if (log.length === 0) {\n console.log('No orders in log.');\n return;\n }\n\n for (const o of log) {\n const ts = new Date(o.createdAt).toISOString();\n const dryTag = o.dryRun ? '[DRY]' : '[REAL]';\n console.log(\n `${ts} ${dryTag} ${o.transaction} ${o.quantity} ${o.symbol} @ ${o.orderType} ${o.price ?? 'MKT'} status=${o.status} kite_id=${o.kiteOrderId ?? 'n/a'}`\n );\n }\n } finally {\n store.close();\n }\n}\n\nfunction cmdClean(): void {\n const store = new ZerodhaStore(getDbPath());\n try {\n const result = store.clean();\n console.log(`Cleared tables: ${result.tablesCleared.join(', ')}`);\n } finally {\n store.close();\n }\n}\n\n// -- Main --------------------------------------------------------------------\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const command = args[0];\n\n if (!command || command === '--help' || command === '-h' || command === 'help') {\n printHelp();\n return;\n }\n\n if (command === 'version') {\n const pkgPath = join(getPackageRoot(), 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n console.log(pkg.version);\n return;\n }\n\n if (command === 'auth') {\n await cmdAuth(args);\n return;\n }\n\n if (command === 'holdings') {\n await cmdHoldings();\n return;\n }\n\n if (command === 'positions') {\n await cmdPositions();\n return;\n }\n\n if (command === 'orders') {\n await cmdOrders();\n return;\n }\n\n if (command === 'margins') {\n await cmdMargins();\n return;\n }\n\n if (command === 'order') {\n await cmdOrder(args);\n return;\n }\n\n if (command === 'cancel') {\n await cmdCancel(args);\n return;\n }\n\n if (command === 'log') {\n cmdLog(args);\n return;\n }\n\n if (command === 'clean') {\n cmdClean();\n return;\n }\n\n console.error(`Unknown command: ${command}\\nRun \"zerodha-broker help\" for usage.`);\n process.exit(1);\n}\n\nmain().catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n","import { createHash } from 'node:crypto';\n\nconst KITE_SESSION_URL = 'https://api.kite.trade/session/token';\n\nexport interface TokenExchangeResult {\n access_token: string;\n refresh_token: string;\n user_id: string;\n login_time: string;\n}\n\n// Step 1: Generate the login URL for the user to open in browser\nexport function buildLoginUrl(apiKey: string): string {\n return `https://kite.trade/connect/login?v=3&api_key=${apiKey}`;\n}\n\n// Step 2: Compute checksum for request_token exchange\n// checksum = sha256(api_key + request_token + api_secret)\nexport function computeChecksum(apiKey: string, requestToken: string, apiSecret: string): string {\n return createHash('sha256')\n .update(apiKey + requestToken + apiSecret)\n .digest('hex');\n}\n\n// Step 3: Exchange request_token for access_token\nexport async function exchangeToken(\n apiKey: string,\n apiSecret: string,\n requestToken: string\n): Promise<TokenExchangeResult> {\n const checksum = computeChecksum(apiKey, requestToken, apiSecret);\n\n const body = new URLSearchParams();\n body.set('api_key', apiKey);\n body.set('request_token', requestToken);\n body.set('checksum', checksum);\n\n const res = await fetch(KITE_SESSION_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n });\n\n const json = (await res.json()) as {\n status: string;\n data: TokenExchangeResult;\n message?: string;\n };\n\n if (json.status !== 'success') {\n throw new Error(`Token exchange failed: ${json.message ?? 'unknown error'}`);\n }\n\n return json.data;\n}\n\n// Validate that current access token is still alive\nexport async function validateToken(\n apiKey: string,\n accessToken: string\n): Promise<{ valid: boolean; userId?: string; expiresHint?: string }> {\n try {\n const res = await fetch('https://api.kite.trade/user/profile', {\n method: 'GET',\n headers: {\n Authorization: `token ${apiKey}:${accessToken}`,\n 'X-Kite-Version': '3',\n },\n });\n\n if (res.status === 403) {\n return { valid: false, expiresHint: 'Token expired' };\n }\n\n const json = (await res.json()) as {\n status: string;\n data?: { user_id: string };\n error_type?: string;\n };\n\n if (json.error_type === 'TokenException') {\n return { valid: false, expiresHint: 'Token expired' };\n }\n\n if (json.status === 'success' && json.data) {\n return {\n valid: true,\n userId: json.data.user_id,\n expiresHint: 'tonight at midnight IST',\n };\n }\n\n return { valid: false, expiresHint: 'Unknown validation error' };\n } catch {\n return { valid: false, expiresHint: 'Network error during validation' };\n }\n}\n","const KITE_BASE = 'https://api.kite.trade';\n\nexport interface KiteCredentials {\n apiKey: string;\n accessToken: string;\n}\n\nfunction authHeaders(creds: KiteCredentials): Record<string, string> {\n return {\n Authorization: `token ${creds.apiKey}:${creds.accessToken}`,\n 'X-Kite-Version': '3',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n}\n\n// -- Error classes -----------------------------------------------------------\n\nexport class KiteTokenExpiredError extends Error {\n readonly code = 'TOKEN_EXPIRED';\n constructor(message = 'Kite access token expired. Renew via zerodha-broker auth.') {\n super(message);\n this.name = 'KiteTokenExpiredError';\n }\n}\n\nexport class KiteApiError extends Error {\n constructor(\n message: string,\n readonly errorType: string,\n readonly statusCode: number\n ) {\n super(message);\n this.name = 'KiteApiError';\n }\n}\n\n// -- Response handling -------------------------------------------------------\n\ninterface KiteResponse<T> {\n status: string;\n data: T;\n message?: string;\n error_type?: string;\n}\n\nasync function kiteGet<T>(creds: KiteCredentials, path: string): Promise<T> {\n const res = await fetch(`${KITE_BASE}${path}`, {\n method: 'GET',\n headers: authHeaders(creds),\n });\n\n const body = (await res.json()) as KiteResponse<T>;\n\n if (res.status === 403 || body.error_type === 'TokenException') {\n throw new KiteTokenExpiredError(body.message);\n }\n\n if (body.status === 'error') {\n throw new KiteApiError(\n body.message ?? 'Unknown error',\n body.error_type ?? 'Unknown',\n res.status\n );\n }\n\n return body.data;\n}\n\n// -- Account -----------------------------------------------------------------\n\nexport interface KiteProfile {\n user_id: string;\n user_name: string;\n email: string;\n user_type: string;\n broker: string;\n}\n\nexport interface KiteMargins {\n equity: {\n enabled: boolean;\n net: number;\n available: { live_balance: number; opening_balance: number };\n utilised: { m2m_unrealised: number; option_premium: number; exposure: number };\n };\n}\n\nexport async function fetchProfile(creds: KiteCredentials): Promise<KiteProfile> {\n return kiteGet<KiteProfile>(creds, '/user/profile');\n}\n\nexport async function fetchMargins(creds: KiteCredentials): Promise<KiteMargins> {\n return kiteGet<KiteMargins>(creds, '/user/margins');\n}\n\n// -- Portfolio ---------------------------------------------------------------\n\nexport interface KiteHolding {\n tradingsymbol: string;\n exchange: string;\n isin: string;\n quantity: number;\n t1_quantity: number;\n average_price: number;\n last_price: number;\n pnl: number;\n day_change: number;\n day_change_percentage: number;\n product: string;\n}\n\nexport interface KitePosition {\n tradingsymbol: string;\n exchange: string;\n product: string;\n quantity: number;\n overnight_quantity: number;\n average_price: number;\n last_price: number;\n pnl: number;\n m2m: number;\n unrealised: number;\n realised: number;\n}\n\nexport async function fetchHoldings(creds: KiteCredentials): Promise<KiteHolding[]> {\n return kiteGet<KiteHolding[]>(creds, '/portfolio/holdings');\n}\n\nexport async function fetchPositions(\n creds: KiteCredentials\n): Promise<{ day: KitePosition[]; net: KitePosition[] }> {\n return kiteGet<{ day: KitePosition[]; net: KitePosition[] }>(creds, '/portfolio/positions');\n}\n\n// -- Orders ------------------------------------------------------------------\n\nexport interface KiteOrder {\n order_id: string;\n exchange: string;\n tradingsymbol: string;\n transaction_type: 'BUY' | 'SELL';\n order_type: string;\n quantity: number;\n price: number;\n trigger_price: number;\n average_price: number;\n filled_quantity: number;\n status: string;\n status_message: string | null;\n order_timestamp: string;\n product: string;\n variety: string;\n}\n\nexport async function fetchOrders(creds: KiteCredentials): Promise<KiteOrder[]> {\n return kiteGet<KiteOrder[]>(creds, '/orders');\n}\n\n// -- Order placement ---------------------------------------------------------\n\nexport interface PlaceOrderParams {\n exchange: 'NSE' | 'BSE';\n tradingsymbol: string;\n transaction_type: 'BUY' | 'SELL';\n quantity: number;\n order_type: 'MARKET' | 'LIMIT' | 'SL' | 'SL-M';\n product: 'CNC' | 'MIS' | 'NRML';\n price?: number;\n trigger_price?: number;\n variety?: 'regular' | 'amo';\n validity?: 'DAY' | 'IOC';\n}\n\nexport interface PlaceOrderResult {\n order_id: string;\n}\n\nexport async function placeOrder(\n creds: KiteCredentials,\n params: PlaceOrderParams\n): Promise<PlaceOrderResult> {\n const variety = params.variety ?? 'regular';\n\n const body = new URLSearchParams();\n body.set('exchange', params.exchange);\n body.set('tradingsymbol', params.tradingsymbol);\n body.set('transaction_type', params.transaction_type);\n body.set('quantity', String(params.quantity));\n body.set('order_type', params.order_type);\n body.set('product', params.product);\n body.set('validity', params.validity ?? 'DAY');\n if (params.price != null) body.set('price', String(params.price));\n if (params.trigger_price != null) body.set('trigger_price', String(params.trigger_price));\n\n const res = await fetch(`${KITE_BASE}/orders/${variety}`, {\n method: 'POST',\n headers: authHeaders(creds),\n body: body.toString(),\n });\n\n const json = (await res.json()) as KiteResponse<PlaceOrderResult>;\n\n if (res.status === 403 || json.error_type === 'TokenException') {\n throw new KiteTokenExpiredError(json.message);\n }\n\n if (json.status === 'error') {\n throw new KiteApiError(\n json.message ?? 'Order placement failed',\n json.error_type ?? 'Unknown',\n res.status\n );\n }\n\n return json.data;\n}\n\nexport async function cancelOrder(\n creds: KiteCredentials,\n orderId: string,\n variety = 'regular'\n): Promise<{ order_id: string }> {\n const res = await fetch(`${KITE_BASE}/orders/${variety}/${orderId}`, {\n method: 'DELETE',\n headers: authHeaders(creds),\n });\n\n const json = (await res.json()) as KiteResponse<{ order_id: string }>;\n\n if (res.status === 403 || json.error_type === 'TokenException') {\n throw new KiteTokenExpiredError(json.message);\n }\n\n if (json.status === 'error') {\n throw new KiteApiError(\n json.message ?? 'Order cancellation failed',\n json.error_type ?? 'Unknown',\n res.status\n );\n }\n\n return json.data;\n}\n","import Database from 'better-sqlite3';\nimport { migrate } from './schema';\n\nexport interface HoldingRow {\n symbol: string;\n exchange: string;\n isin: string | null;\n quantity: number;\n t1Quantity: number;\n avgPrice: number;\n ltp: number | null;\n pnl: number | null;\n pnlPct: number | null;\n dayChange: number | null;\n product: string;\n refreshedAt: number;\n}\n\nexport interface OrderLogRow {\n id: string;\n createdAt: number;\n symbol: string;\n exchange: string;\n transaction: 'BUY' | 'SELL';\n quantity: number;\n orderType: string;\n price: number | null;\n product: string;\n dryRun: boolean;\n kiteOrderId: string | null;\n status: string;\n rejectionReason: string | null;\n agentSession: string | null;\n}\n\nexport const TTL = {\n HOLDINGS: 60 * 60 * 1000, // 1 hour\n} as const;\n\nexport class ZerodhaStore {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n migrate(this.db);\n }\n\n close(): void {\n this.db.close();\n }\n\n // -- Holdings cache --------------------------------------------------------\n\n replaceHoldings(holdings: HoldingRow[]): void {\n const now = Date.now();\n const tx = this.db.transaction(() => {\n this.db.prepare('DELETE FROM holdings_cache').run();\n const stmt = this.db.prepare(`\n INSERT INTO holdings_cache\n (symbol, exchange, isin, quantity, t1_quantity, avg_price, ltp, pnl, pnl_pct, day_change, product, refreshed_at)\n VALUES\n (@symbol, @exchange, @isin, @quantity, @t1Quantity, @avgPrice, @ltp, @pnl, @pnlPct, @dayChange, @product, @refreshedAt)\n `);\n for (const h of holdings) {\n stmt.run({\n symbol: h.symbol,\n exchange: h.exchange,\n isin: h.isin,\n quantity: h.quantity,\n t1Quantity: h.t1Quantity,\n avgPrice: h.avgPrice,\n ltp: h.ltp,\n pnl: h.pnl,\n pnlPct: h.pnlPct,\n dayChange: h.dayChange,\n product: h.product,\n refreshedAt: h.refreshedAt,\n });\n }\n this.db\n .prepare('INSERT OR REPLACE INTO sync_meta (key, fetched_at, status) VALUES (?, ?, ?)')\n .run('holdings', now, 'ok');\n });\n tx();\n }\n\n getHoldings(): HoldingRow[] {\n const rows = this.db.prepare('SELECT * FROM holdings_cache').all() as Array<{\n symbol: string;\n exchange: string;\n isin: string | null;\n quantity: number;\n t1_quantity: number;\n avg_price: number;\n ltp: number | null;\n pnl: number | null;\n pnl_pct: number | null;\n day_change: number | null;\n product: string;\n refreshed_at: number;\n }>;\n return rows.map((r) => ({\n symbol: r.symbol,\n exchange: r.exchange,\n isin: r.isin,\n quantity: r.quantity,\n t1Quantity: r.t1_quantity,\n avgPrice: r.avg_price,\n ltp: r.ltp,\n pnl: r.pnl,\n pnlPct: r.pnl_pct,\n dayChange: r.day_change,\n product: r.product,\n refreshedAt: r.refreshed_at,\n }));\n }\n\n isStale(key: string, ttlMs: number): boolean {\n const row = this.db.prepare('SELECT fetched_at FROM sync_meta WHERE key = ?').get(key) as\n | { fetched_at: number }\n | undefined;\n if (!row) return true;\n return Date.now() - row.fetched_at > ttlMs;\n }\n\n getLastFetchedAt(key: string): number {\n const row = this.db.prepare('SELECT fetched_at FROM sync_meta WHERE key = ?').get(key) as\n | { fetched_at: number }\n | undefined;\n return row?.fetched_at ?? 0;\n }\n\n setSyncMeta(key: string, status = 'ok'): void {\n this.db\n .prepare('INSERT OR REPLACE INTO sync_meta (key, fetched_at, status) VALUES (?, ?, ?)')\n .run(key, Date.now(), status);\n }\n\n // -- Order audit log -------------------------------------------------------\n\n logOrder(row: OrderLogRow): void {\n this.db\n .prepare(\n `INSERT INTO order_log\n (id, created_at, symbol, exchange, transaction_type, quantity, order_type, price, product, dry_run, kite_order_id, status, rejection_reason, agent_session)\n VALUES\n (@id, @createdAt, @symbol, @exchange, @transactionType, @quantity, @orderType, @price, @product, @dryRun, @kiteOrderId, @status, @rejectionReason, @agentSession)`\n )\n .run({\n id: row.id,\n createdAt: row.createdAt,\n symbol: row.symbol,\n exchange: row.exchange,\n transactionType: row.transaction,\n quantity: row.quantity,\n orderType: row.orderType,\n price: row.price,\n product: row.product,\n dryRun: row.dryRun ? 1 : 0,\n kiteOrderId: row.kiteOrderId,\n status: row.status,\n rejectionReason: row.rejectionReason,\n agentSession: row.agentSession,\n });\n }\n\n getOrderLog(limit = 50): OrderLogRow[] {\n const rows = this.db\n .prepare('SELECT * FROM order_log ORDER BY created_at DESC LIMIT ?')\n .all(limit) as Array<{\n id: string;\n created_at: number;\n symbol: string;\n exchange: string;\n transaction_type: 'BUY' | 'SELL';\n quantity: number;\n order_type: string;\n price: number | null;\n product: string;\n dry_run: number;\n kite_order_id: string | null;\n status: string;\n rejection_reason: string | null;\n agent_session: string | null;\n }>;\n return rows.map((r) => ({\n id: r.id,\n createdAt: r.created_at,\n symbol: r.symbol,\n exchange: r.exchange,\n transaction: r.transaction_type,\n quantity: r.quantity,\n orderType: r.order_type,\n price: r.price,\n product: r.product,\n dryRun: r.dry_run === 1,\n kiteOrderId: r.kite_order_id,\n status: r.status,\n rejectionReason: r.rejection_reason,\n agentSession: r.agent_session,\n }));\n }\n\n clean(): { tablesCleared: string[] } {\n this.db.prepare('DELETE FROM holdings_cache').run();\n this.db.prepare('DELETE FROM order_log').run();\n this.db.prepare('DELETE FROM sync_meta').run();\n return { tablesCleared: ['holdings_cache', 'order_log', 'sync_meta'] };\n }\n}\n","import type Database from 'better-sqlite3';\n\n// -- Holdings snapshot -------------------------------------------------------\n// One row per symbol. Overwritten on each holdings refresh.\n// Purpose: lets agents query holdings without a live API call.\nexport const SQL_CREATE_HOLDINGS_CACHE = `\n CREATE TABLE IF NOT EXISTS holdings_cache (\n symbol TEXT PRIMARY KEY,\n exchange TEXT NOT NULL,\n isin TEXT,\n quantity INTEGER NOT NULL,\n t1_quantity INTEGER NOT NULL DEFAULT 0,\n avg_price REAL NOT NULL,\n ltp REAL,\n pnl REAL,\n pnl_pct REAL,\n day_change REAL,\n product TEXT NOT NULL,\n refreshed_at INTEGER NOT NULL\n ) STRICT;\n`;\n\n// -- Order audit log ---------------------------------------------------------\n// Every order the agent proposes or places, with outcome.\nexport const SQL_CREATE_ORDER_LOG = `\n CREATE TABLE IF NOT EXISTS order_log (\n id TEXT PRIMARY KEY,\n created_at INTEGER NOT NULL,\n symbol TEXT NOT NULL,\n exchange TEXT NOT NULL,\n transaction_type TEXT NOT NULL,\n quantity INTEGER NOT NULL,\n order_type TEXT NOT NULL,\n price REAL,\n product TEXT NOT NULL,\n dry_run INTEGER NOT NULL,\n kite_order_id TEXT,\n status TEXT NOT NULL,\n rejection_reason TEXT,\n agent_session TEXT\n ) STRICT;\n`;\n\n// -- Sync meta ---------------------------------------------------------------\nexport const SQL_CREATE_SYNC_META = `\n CREATE TABLE IF NOT EXISTS sync_meta (\n key TEXT PRIMARY KEY,\n fetched_at INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'ok'\n ) STRICT;\n`;\n\nexport function migrate(db: Database.Database): void {\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n db.exec(SQL_CREATE_HOLDINGS_CACHE);\n db.exec(SQL_CREATE_ORDER_LOG);\n db.exec(SQL_CREATE_SYNC_META);\n}\n"],"mappings":"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","names":["apiKey"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Tool, EthosPlugin } from '@ethosagent/plugin-sdk';
|
|
2
|
+
|
|
3
|
+
interface TokenExchangeResult {
|
|
4
|
+
access_token: string;
|
|
5
|
+
refresh_token: string;
|
|
6
|
+
user_id: string;
|
|
7
|
+
login_time: string;
|
|
8
|
+
}
|
|
9
|
+
declare function buildLoginUrl(apiKey: string): string;
|
|
10
|
+
declare function exchangeToken(apiKey: string, apiSecret: string, requestToken: string): Promise<TokenExchangeResult>;
|
|
11
|
+
declare function validateToken(apiKey: string, accessToken: string): Promise<{
|
|
12
|
+
valid: boolean;
|
|
13
|
+
userId?: string;
|
|
14
|
+
expiresHint?: string;
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
interface HoldingRow {
|
|
18
|
+
symbol: string;
|
|
19
|
+
exchange: string;
|
|
20
|
+
isin: string | null;
|
|
21
|
+
quantity: number;
|
|
22
|
+
t1Quantity: number;
|
|
23
|
+
avgPrice: number;
|
|
24
|
+
ltp: number | null;
|
|
25
|
+
pnl: number | null;
|
|
26
|
+
pnlPct: number | null;
|
|
27
|
+
dayChange: number | null;
|
|
28
|
+
product: string;
|
|
29
|
+
refreshedAt: number;
|
|
30
|
+
}
|
|
31
|
+
interface OrderLogRow {
|
|
32
|
+
id: string;
|
|
33
|
+
createdAt: number;
|
|
34
|
+
symbol: string;
|
|
35
|
+
exchange: string;
|
|
36
|
+
transaction: 'BUY' | 'SELL';
|
|
37
|
+
quantity: number;
|
|
38
|
+
orderType: string;
|
|
39
|
+
price: number | null;
|
|
40
|
+
product: string;
|
|
41
|
+
dryRun: boolean;
|
|
42
|
+
kiteOrderId: string | null;
|
|
43
|
+
status: string;
|
|
44
|
+
rejectionReason: string | null;
|
|
45
|
+
agentSession: string | null;
|
|
46
|
+
}
|
|
47
|
+
declare const TTL: {
|
|
48
|
+
readonly HOLDINGS: number;
|
|
49
|
+
};
|
|
50
|
+
declare class ZerodhaStore {
|
|
51
|
+
private db;
|
|
52
|
+
constructor(dbPath: string);
|
|
53
|
+
close(): void;
|
|
54
|
+
replaceHoldings(holdings: HoldingRow[]): void;
|
|
55
|
+
getHoldings(): HoldingRow[];
|
|
56
|
+
isStale(key: string, ttlMs: number): boolean;
|
|
57
|
+
getLastFetchedAt(key: string): number;
|
|
58
|
+
setSyncMeta(key: string, status?: string): void;
|
|
59
|
+
logOrder(row: OrderLogRow): void;
|
|
60
|
+
getOrderLog(limit?: number): OrderLogRow[];
|
|
61
|
+
clean(): {
|
|
62
|
+
tablesCleared: string[];
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** v2 plugin entry point — registers all tools via EthosPluginApi. */
|
|
67
|
+
declare const plugin: EthosPlugin;
|
|
68
|
+
/** Backward-compatible activate function for v1 hosts. */
|
|
69
|
+
declare function activate(api: {
|
|
70
|
+
registerTool(tool: Tool): void;
|
|
71
|
+
}): void;
|
|
72
|
+
declare function createZerodhaTools(): Tool<unknown>[];
|
|
73
|
+
|
|
74
|
+
export { type HoldingRow, type OrderLogRow, TTL, type TokenExchangeResult, ZerodhaStore, activate, buildLoginUrl, createZerodhaTools as createTools, createZerodhaTools, exchangeToken, plugin, validateToken };
|