-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add alpaca feed/feed_consumer stock examples
- Loading branch information
Showing
10 changed files
with
193 additions
and
16 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
.py("klongpy.ws") | ||
.pyf("iso8601";"parse_date") | ||
|
||
.comment("****") | ||
|
||
feed type: | ||
t trades (includes corrections and cancelErrors) | ||
q quotes | ||
b bars | ||
|
||
<feed type>.<symbol or *> | ||
|
||
e.g. | ||
|
||
b.MSFT minute bar for MSFT | ||
|
||
or | ||
|
||
b.* for all minute bars | ||
|
||
**** | ||
|
||
auth:::{["action" "auth"]} | ||
auth,"key",,.os.env?"ALPACA_API_KEY" | ||
auth,"secret",,.os.env?"ALPACA_SECRET_KEY" | ||
|
||
:" subscription handler " | ||
mkbars::{{2_x}'x@&{#x?"b."}'x} | ||
mktrades::{[]} | ||
mkquotes::{[]} | ||
psmsg::{[d];d:::{["action" "subscribe"]};d,"bars",,mkbars(x);d,"trades",,mktrades(x);d,"quotes",,mkquotes(x)} | ||
unionValues::{[q];q:::{};{{q,x,1}'x@1}'x;{x@0}'q} | ||
updSubscription::{[v q];.d("subscribing: ");v::unionValues(x);v::psmsg(v);.p(v);wsc(v)} | ||
|
||
:" Map of clients handles to their subscribed tickers " | ||
clients:::{} | ||
rmclient::{x_clients} | ||
|
||
:" Handle server auth request " | ||
sendAuth::{.p("sending auth");.p(auth);x(auth)} | ||
handleUnknown::{.d("unhandled");.p(y)} | ||
handleLogin::{.p("logged in")} | ||
handleControl::{[msg];msg::y?"msg";:[msg="connected";sendAuth(x);:[msg="authenticated";handleLogin(x;y);handleAuthFailure(x;y)]]} | ||
handleSubscribed::{.p(y)} | ||
|
||
handlers:::{} | ||
handlers,"success",handleControl | ||
handlers,"subscription",handleSubscribed | ||
handleStatus::{[h];.p(y);h::handlers?(y?"T");:[h;h(x;y);handleUnknown(x;y)]} | ||
|
||
:" convert the RFC-3339 formatted timestamp " | ||
mkts::{[d ts];d::.pyc("parse_date";,x;:{});.pyc(d,,"timestamp";[];:{})} | ||
|
||
:" send the message to all subscribed clients " | ||
send::{.d("sending ");.d(k);.d(" to client ");.p(y);y(:update,,z)} | ||
match::{[ev k subscription];ev::x;k::y;subscription::z;all::ev,".*";:[subscription?all;1;:[subscription?k;1;0]]} | ||
broadcast::{[ev k data];ev::x;k::y;data::z;{:[match(ev;k;x@1);send(k;x@0;data);0]}'clients} | ||
handleData::{[ev sym k];.d("data: ");.p(y);ev::(y?"T");sym::(y?"S");y,"t",mkts(y?"t");k::ev,".",sym;broadcast(ev;k;y)} | ||
|
||
handleMsg::{:[(y?"T")="b";handleData(x;y);handleStatus(x;y)]} | ||
|
||
.ws.m::{[c];c::x;{handleMsg(c;x)}'y} | ||
|
||
wsuri:::[(#.os.argv);.os.argv@0;"wss://stream.data.alpaca.markets/v2/sip"] | ||
.d("connecting to ");.p(wsuri) | ||
wsc::.ws(wsuri) | ||
|
||
:" Called by clients to subscribe to ticker updates " | ||
updClientSub::{clients,x,,(clients?x),,y;.d("clients: ");.p(clients)} | ||
subscribe::{.d("subscribing client: ");.p(.cli.h,,x);updClientSub(.cli.h;x);updSubscription(clients);x} | ||
|
||
:" Setup the IPC server and callbacks " | ||
.srv(8888) | ||
.srv.o::{.d("client connected: ");.p(x);clients,x,,[]} | ||
.srv.c::{.d("client disconnected: ");.p(x);rmclient(x);updSubscription(clients);.d("clients left: ");.p(#clients)} | ||
.srv.e::{.d("error: ");.p(x);.p(y)} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
.py("klongpy.db") | ||
|
||
.comment("****") | ||
|
||
Feed consumer for listening to streaming stock bars from Alpaca. | ||
|
||
Data is received from the feed server (that's connected to Alpaca) and stored in the database. | ||
|
||
Sample bars data: | ||
|
||
{ | ||
"T": "b", | ||
"S": "SPY", | ||
"o": 388.985, | ||
"h": 389.13, | ||
"l": 388.975, | ||
"c": 389.12, | ||
"v": 49378, | ||
"t": "2021-02-22T19:15:00Z" (converted to timestamp on server) | ||
} | ||
|
||
TODO: add delta sync against feed server | ||
|
||
**** | ||
|
||
time::{[t0];t0::.pc();x();.pc()-t0} | ||
time1::{[t0];t0::.pc();x(y);.pc()-t0} | ||
|
||
tbs::.tables("/tmp/tables/consumer") | ||
|
||
:" Create a new table with appropriate columns for the Alpaca data " | ||
cols::["S" "o" "h" "l" "c" "v" "t"] | ||
colsFromData::{{(x@0),,[]}'x} | ||
colsFromNames::{{x,,[]}'x} | ||
newt::{.table(colsFromNames(cols))} | ||
|
||
:" Attempt to load the prices table from disk " | ||
prices::tbs?"prices" | ||
prices:::[:_prices;newt();prices] | ||
|
||
:" Create a database so we can inspect the data " | ||
q:::{} | ||
q,"prices",,prices | ||
db::.db(q) | ||
|
||
stats::{[q];q::db("select count(*) from prices");.d("rows: ");.p(q);q} | ||
lastCnt::stats() | ||
|
||
:" Flush the prices table every minute " | ||
store::{[q];.p("");q::stats();:[q>lastCnt;tbs,"prices",prices;.p("no change")];lastCnt::q;1} | ||
timeStore::{[r];r::time(store);.d("store ms: ");.p(r)} | ||
.timer("store";60;timeStore) | ||
|
||
:"Connect to the broadcast server" | ||
.p("connecting to server on port 8888") | ||
cli::.cli(8888) | ||
|
||
cli(:subscribe,,["b.MSFT" "b.AAPL" "b.GOOG"]) | ||
|
||
:" A basic bollinger band strategy " | ||
mean::{(+/x)%#x} | ||
std::{((+/((x-y)^2))%#x)^0.5} | ||
bollinger::{[m s];m::mean(x);s::std(x;mean(x));(m+2*s),(m-2*s)} | ||
signal::{[upper lower p];upper::x@0;lower::x@1;p::y@0;:[p<lower;"buy";:[p>upper;"sell";"hold"]]} | ||
|
||
analyze::{[b c];c::db("select c from prices order by S desc limit 20");b::bollinger(c);.d("signal: ");.p(signal(b;c))} | ||
timeAnalyze::{time(analyze)} | ||
analyzeComplete::{.d("analyze ms: ");.p(x)} | ||
asyncAnalyze::.async(timeAnalyze;analyzeComplete) | ||
|
||
updateDb::{[u d];u::x;d::{u?x}'cols;.d("insert: ");.d(d);.insert(prices;d)} | ||
timeUpdateDb::{[ms];ms::time1(updateDb;x);.d(" ");.d(ms);.p(" ms")} | ||
|
||
:" Called by server when there is a subscription update." | ||
update::{timeUpdateDb(x);asyncAnalyze()} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions
6
examples/ws/polygon.kg → examples/stocks/polygon/ws/stream.kg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters