diff options
| author | Dan Rostovtsev <dan@rostovtsev.org> | 2026-04-06 15:48:14 -0400 |
|---|---|---|
| committer | Dan Rostovtsev <dan@rostovtsev.org> | 2026-04-06 15:48:14 -0400 |
| commit | 0716a22d1fab76a18606ec031d33914ccbc56633 (patch) | |
| tree | d63cc7ee4fd73bac935a776d09dc0ec78c8335e2 /scripts | |
| parent | 2c6cf786c151118232533a6cfbc769ce1514aa9e (diff) | |
* doc/ibkr.org: Docs for using the IBKR API.
* manifest.scm: Guix Manifest of all project dependencies.
* scripts/run-gateway.bash: A script for building and deploying the
IBKR Client Gateway.
* src/ibkr/api.scm: Support for specific endpoints, and generic tools
for using the IBKR API.
* src/ibkr/types.scm: Basic types for the IBKR endpoints. Orders,
positions, securities, etc.
* test/*.json: IBKR response and request examples for testing.
* test/api.scm: Response handling and endpoint construction.
* test/types.scm: Tests JSON parsing of IBKR requests and responses.
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/compile-docs.el | 6 | ||||
| -rwxr-xr-x | scripts/keepalive.bash | 7 | ||||
| -rw-r--r-- | scripts/paper-trade-test.scm | 95 | ||||
| -rw-r--r-- | scripts/preview-order.scm | 17 | ||||
| -rwxr-xr-x | scripts/run-gateway.bash | 8 | ||||
| -rwxr-xr-x | scripts/start-gateway.bash (renamed from scripts/deploy.bash) | 0 | ||||
| -rwxr-xr-x | scripts/tickle.py | 5 |
7 files changed, 126 insertions, 12 deletions
diff --git a/scripts/compile-docs.el b/scripts/compile-docs.el new file mode 100644 index 0000000..e13f7a8 --- /dev/null +++ b/scripts/compile-docs.el @@ -0,0 +1,6 @@ +(require 'ox-texinfo) +(let ((infile "./doc/ibkr.org") + (outfile "./doc/ibkr.texi")) + (with-temp-buffer + (insert-file-contents infile) + (org-export-to-file 'texinfo outfile))) diff --git a/scripts/keepalive.bash b/scripts/keepalive.bash deleted file mode 100755 index 3b2a1ae..0000000 --- a/scripts/keepalive.bash +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/bash - -while [ 0 ]; do - ./scripts/tickle.py - echo teehee - sleep 60 -done diff --git a/scripts/paper-trade-test.scm b/scripts/paper-trade-test.scm new file mode 100644 index 0000000..29d1218 --- /dev/null +++ b/scripts/paper-trade-test.scm @@ -0,0 +1,95 @@ +(use-modules (ibkr api) (ibkr types) + (json) + (srfi srfi-1) (srfi srfi-64) + (ice-9 format)) + +;; connect +(display "connecting to ibkr api\n") +(define base "http://localhost:5000") +(format #t "connected: ~a\n" (auth-status-connected (auth-status base))) +(sleep 1) + +;; check mkt +(display "querying market data\n") +(define ibkr (contract-for-stock-ticker base "IBKR" "NASDAQ")) +(define ibkr-id (contract-id ibkr)) +(define ibkr-ref-px (contract-snapshot base ibkr-id 'last-trade)) +(format #t "contract-id(IBKR)=~a\n" ibkr-id) +(format #t "last-trade(IBKR)=$~a\n" ibkr-ref-px) +(sleep 1) + +;; acct info +(display "querying account info\n") +(define accts (accounts base)) +(define acct (car accts)) +(define acct-id (account-id acct)) +(define pos-t0 (positions base acct-id)) +(define bal-t0 (ledger-cash-balance (ledger base acct-id "USD"))) +(format #t "balance(t0)=$~a\n" bal-t0) +(format #t "account-type=~a\n" (account-type acct)) +(if (not (equal? (account-type acct) "DEMO")) + (exit 1)) +(sleep 1) + +;; buy +(define buy (make-order acct-id ibkr-id "MARKET" "BUY" "IOC" 10.0)) +(format #t "buy-order=~a\n" buy) +(define buy-preview (order-preview base acct-id buy)) +(format #t "buy-preview=~a\n" buy-preview) +(define buy-warning (order-submit base acct-id buy)) ;; no market data? +(format #t "buy-warning=~a\n" buy-warning) +(define buy-reply (order-confirm base (order-warning-id buy-warning))) +(format #t "buy-reply=~a\n" buy-reply) +(define buy-oid (order-reply-order-id buy-reply)) +(format #t "buy-oid=~a\n" buy-oid) +(format #t "sleeping to wait for fill\n") (sleep 5) ;; wait for fill +(define buy-status (order-status base buy-oid)) +(format #t "buy-status=~a\n" buy-status) +(define buy-px (string->number (order-status-average-price buy-status))) +(define buy-qty (string->number (order-status-quantity buy-status))) +(define pos-t1 (positions base acct-id)) +(define bal-t1 (ledger-cash-balance (ledger base acct-id "USD"))) + +(display "sleeping to avoid rate limit\n") (sleep 5) + +;; sell +(define sell (make-order acct-id ibkr-id "MARKET" "SELL" "IOC" 10.0)) +(format #t "sell-order=~a\n" sell) +(define sell-preview (order-preview base acct-id sell)) +(format #t "sell-preview=~a\n" sell-preview) +(define sell-warning (order-submit base acct-id sell)) ;; no market data? +(format #t "sell-warning=~a\n" sell-warning) +(define sell-reply (order-confirm base (order-warning-id sell-warning))) +(format #t "sell-reply=~a\n" sell-reply) +(define sell-oid (order-reply-order-id sell-reply)) +(format #t "sell-oid=~a\n" sell-oid) +(format #t "sleeping to wait for fill\n") (sleep 5) ;; wait for fill +(define sell-status (order-status base sell-oid)) +(format #t "sell-status=~a\n" buy-status) +(define sell-px (string->number (order-status-average-price sell-status))) +(define sell-qty (string->number (order-status-quantity sell-status))) +(define pos-t2 (positions base acct-id)) +(define bal-t2 (ledger-cash-balance (ledger base acct-id "USD"))) + +;; checks +(define (position poslst contract-id) + (find + (lambda (p) + (equal? (string->number (position-contract-id p)) contract-id)) + poslst)) +(define (abs-rel-diff a b) (/ (* 2 (abs (- a b))) (+ (abs a) (abs b)))) +(define (within-n-percent n a b) (< (* 100 (abs-rel-diff a b)) n)) +(test-begin "paper-trade") +(test-approximate "ibkr-qty-t0" 0 (position-quantity (position pos-t0 ibkr-id)) 1e-3) +(test-approximate "ibkr-qty-t1" 10 (position-quantity (position pos-t1 ibkr-id)) 1e-3) +(test-approximate "ibkr-qty-t2" 0 (position-quantity (position pos-t2 ibkr-id)) 1e-3) +(test-approximate "ibkr-buy-qty" 10 buy-qty 1e-3) +(test-approximate "ibkr-sell-qty" 10 sell-qty 1e-3) +(test-assert "buy-px-close-to-ref-px" (within-n-percent 5 buy-px ibkr-ref-px)) +(test-assert "sell-px-close-to-ref-px" (within-n-percent 5 sell-px ibkr-ref-px)) + +;; don't forget commission! +(test-approximate "bal-t1-expected" (- bal-t0 (* 10.0 buy-px)) bal-t1 1.05) +(test-approximate "bal-t2-expected" (+ bal-t1 (* 10.0 sell-px)) bal-t2 1.05) + +(test-end "paper-trade") diff --git a/scripts/preview-order.scm b/scripts/preview-order.scm new file mode 100644 index 0000000..5550a88 --- /dev/null +++ b/scripts/preview-order.scm @@ -0,0 +1,17 @@ +(use-modules (ibkr api) (ibkr types) (ice-9 format)) +(define base "http://localhost:5000") + +(format #t "auth-status=~a\n" (auth-status base)) +(define accts (accounts base)) +(format #t "accounts=~a\n" accts) +(define acct-id (account-id (car accts))) +(format #t "positions=~a\n" (positions base acct-id)) +(format #t "ledger=~a\n" (ledger base acct-id "USD")) +(format #t "stocks-by-symbol(IBKR)=~a\n" (stocks-by-symbol base "IBKR")) +(define ibkr-id (contract-id (contract-for-stock-ticker base "IBKR" "NASDAQ"))) +(format #t "contract-id(IBKR)=~a\n" ibkr-id) +(format #t "last-trade=~a\n" (contract-snapshot base ibkr-id 'last-trade)) +(define order (make-order acct-id ibkr-id "MARKET" "BUY" "IOC" 100.0)) +(format #t "order=~a\n" order) +(format #t "order-json=\"[~a]\"\n" (order->json order)) +(format #t "order-preview=~a\n" (order-preview base acct-id order)) diff --git a/scripts/run-gateway.bash b/scripts/run-gateway.bash new file mode 100755 index 0000000..fdd07c3 --- /dev/null +++ b/scripts/run-gateway.bash @@ -0,0 +1,8 @@ +#!/usr/bin/bash + +./scripts/start-gateway.bash > gw.out 2> gw.err & + +while [ 0 ]; do + sleep 60 + curl -G http://localhost:5000/v1/api/tickle > /dev/null 2> /dev/null +done diff --git a/scripts/deploy.bash b/scripts/start-gateway.bash index 0fd8193..0fd8193 100755 --- a/scripts/deploy.bash +++ b/scripts/start-gateway.bash diff --git a/scripts/tickle.py b/scripts/tickle.py deleted file mode 100755 index 59902d0..0000000 --- a/scripts/tickle.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python3 - -import requests - -requests.get("http://localhost:5000/v1/api/tickle") |
