Skip to content

Commit 807548d

Browse files
author
drzwz
committed
0 parents  commit 807548d

20 files changed

+436
-0
lines changed

.vs/ProjectSettings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"CurrentProjectSetting": null
3+
}

.vs/slnx.sqlite

68 KB
Binary file not shown.

Readme.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# qWindTick
2+
3+
Wind DataFeed for kdb+tick
4+
5+
## 功能
6+
7+
通过qWind/windkdb+接口订阅Wind实时行情,将行情发送到kdb+tick,供各类客户端订阅使用。
8+
9+
## 用法
10+
11+
1、下载qWindTick相关文件;下载kdb+,将q.k和q.exe放到指定文件夹下。
12+
13+
2、根据需要修改.\q\windmd.q里的拟订阅行情的证券代码。
14+
15+
3、运行qwindtibk.bat。
16+
17+
4、q或其它客户端向tickerplant订阅行情(详见kdb+tick:<http://code.kx.com/q/tutorials/startingq/tick/>
18+
19+
## 注:对qWindTick的kdb+tick作了一些修改,主要包括日期改用time,收盘改为16:00等。

q/q.k [download from kx.com]

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
q.k(download from kx.com)

q/qusers

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
kdbuser:kdbpassword

q/tick/cx.q

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/ cx.q
2+
/ example clients
3+
4+
x:.z.x 0 / client type
5+
s:`; / default all symbols
6+
d:`GOOG`IBM`MSFT / symbol selection
7+
t:`bar`taq`msg / default tables
8+
h:hopen `::5010:kdbuser:kdbpassword / connect to tickerplant
9+
10+
11+
/ rdb
12+
if[x~"rdb";
13+
upd:insert]
14+
15+
/ high low close volume
16+
if[x~"hlcv";
17+
t:`trade;
18+
hlcv:([sym:()]high:();low:();price:();size:());
19+
upd:{[t;x]hlcv::select max high,min low,last price,sum size by sym
20+
from(0!hlcv),select sym,high:price,low:price,price,size from x}]
21+
22+
/ last
23+
if[x~"last";
24+
upd:{[t;x].[t;();,;select by sym from x]}]
25+
26+
/ show only
27+
if[x~"show";
28+
tabcount:()!();
29+
/ count the incoming updates
30+
upd:{[t;x] tabcount+::(enlist t)!enlist count x};
31+
/ show the dictionary every t milliseconds
32+
.z.ts:{if[0<count tabcount;
33+
-1"current total received record counts at time ",string .z.T;
34+
show tabcount;
35+
-1"";]};
36+
if[0=system"t"; system"t 5000"]]
37+
38+
/ all trades with then current quote
39+
if[x~"tq";
40+
upd:{[t;x]$[t~`trade;
41+
@[{tq,:x lj q};x;""];
42+
q,:select by sym from x]}]
43+
44+
if[x~"vwap";t:`trade;
45+
upd:{[t;x]vwap+:select size wsum price,sum size by sym from x};
46+
upds:{[t;x]vwap+:select size wsum price,sum size by sym from x;show x}]
47+
48+
{h(".u.sub";x;s)} each t;

q/tick/hdb.q

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
if[not system"p";system"p 5012"];
2+
if[11h<>type key hsym `$ myhdbdir1: ssr[myhdbdir: getenv[`qhome],"\\..\\hdb"; "\\"; "/"]; system "md ",myhdbdir];
3+
system "l ",myhdbdir1;

q/tick/tick.q

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/ q tick.q sym . -p 5001 </dev/null >foo 2>&1 &
2+
/2014.03.12 remove license check
3+
/2013.09.05 warn on corrupt log
4+
/2013.08.14 allow <endofday> when -u is set
5+
/2012.11.09 use timestamp type rather than time. -19h/"t"/.z.Z -> -16h/"n"/.z.P
6+
/2011.02.10 i->i,j to avoid duplicate data if subscription whilst data in buffer
7+
/2009.07.30 ts day (and "d"$a instead of floor a)
8+
/2008.09.09 .k -> .q, 2.4
9+
/2008.02.03 tick/r.k allow no log
10+
/2007.09.03 check one day flip
11+
/2006.10.18 check type?
12+
/2006.07.24 pub then log
13+
/2006.02.09 fix(2005.11.28) .z.ts end-of-day
14+
/2006.01.05 @[;`sym;`g#] in tick.k load
15+
/2005.12.21 tick/r.k reset `g#sym
16+
/2005.12.11 feed can send .u.endofday
17+
/2005.11.28 zero-end-of-day
18+
/2005.10.28 allow`time on incoming
19+
/2005.10.10 zero latency
20+
"kdb+tick 2.8 2014.03.12"
21+
22+
if[not system"p";system"p 5010"];
23+
24+
25+
/q tick.q SRC [DST] [-p 5010] [-o h] //z.:SRC sym.q; DST log file path
26+
system"l tick/",(src:first .z.x,enlist"sym"),".q"
27+
28+
29+
\l tick/u.q
30+
\d .u
31+
ld:{if[not type key L::`$(-10_string L),string x;.[L;();:;()]];i::j::-11!(-2;L);if[0<=type i;-2 (string L)," is a corrupt log. Truncate to length ",(string last i)," and restart";exit 1];hopen L};
32+
tick:{init[];if[not min(`time`sym~2#key flip value@)each t;'`timesym];@[;`sym;`g#]each t;d::.z.D;if[l::count y;L::`$":",y,"/",x,10#".";l::ld d]};
33+
34+
//endofday:{end d;d+:1;if[l;hclose l;l::0(`.u.ld;d)]};
35+
endofday:{ wday:d mod 7; if[wday within 2 6; end d];d+:1; if[l;hclose l;l::0(`.u.ld;d)]}; // 只在周1-5保存数据(2i=mon 6i=fir)
36+
ts:{if[d<x;if[d<x-1;system"t 0";'"more than one day?"];endofday[]]};
37+
38+
39+
if[system"t";
40+
.z.ts:{pub'[t;value each t];@[`.;t;@[;`sym;`g#]0#];i::j;ts .z.D};
41+
upd:{[t;x]
42+
//if[not -16=type first first x;if[d<"d"$a:.z.P;.z.ts[]];a:"n"$a;x:$[0>type first x;a,x;(enlist(count first x)#a),x]]; //z.
43+
if[not (type first first x)in(-16h;-19h);if[d<"d"$a:.z.P;.z.ts[]];a:"n"$a;x:$[0>type first x;a,x;(enlist(count first x)#a),x]]; //z.
44+
t insert x;if[l;l enlist (`upd;t;x);j+:1];}
45+
];
46+
47+
if[not system"t";system"t 1000";
48+
//.z.ts:{ts .z.D};
49+
.z.ts:{ts `date$.z.Z+08:00:00}; //z. 收盘定在 16:00 数据保存日期=结算日
50+
upd:{[t;x]ts"d"$a:.z.P;
51+
//if[not -16=type first first x; a:"n"$a; x:$[0>type first x;a,x;(enlist(count first x)#a),x] ]; //z.
52+
//z.:如果x第0个元素不是time或timestamp,则添加一个time字段
53+
if[not (type first first x)in(-16h;-19h); a:"t"$a; x:$[0>type first x;a,x;(enlist(count first x)#a),x] ]; //z.
54+
//z.: f:key flip value t 相当于cols `t; enlist `a`b!1 2和flip `a`b!(1 2;3 4)均为表
55+
f:key flip value t;pub[t;$[0>type first x;enlist f!x;flip f!x]];if[l;l enlist (`upd;t;x);i+:1];}
56+
];
57+
58+
\d .
59+
.u.tick[src;.z.x 1];
60+
61+
\
62+
globals used
63+
.u.w - dictionary of tables->(handle;syms)
64+
.u.i - msg count in log file
65+
.u.j - total msg count (log file plus those held in buffer)
66+
.u.t - table names
67+
.u.L - tp log filename, e.g. `:./sym2008.09.11
68+
.u.l - handle to tp log file
69+
.u.d - date
70+
71+
/test
72+
>q tick.q
73+
>q tick/ssl.q
74+
75+
/run
76+
>q tick.q sym . -p 5010 /tick
77+
>q tick/r.q :5010 -p 5011 /rdb
78+
>q sym -p 5012 /hdb
79+
>q tick/ssl.q sym :5010 /feed

q/tick/tick/r.q

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/q tick/r.q [host]:port[:usr:pwd] [host]:port[:usr:pwd]
2+
/2008.09.09 .k ->.q
3+
4+
if[not system"p";system"p 5011"];
5+
6+
.z.zd:17 3 0; //z.
7+
if[not "w"=first string .z.o;system "sleep 1"];
8+
9+
//upd:insert;
10+
upd:{[t;x]$[t=`taq;`taq upsert `sym xkey x;t insert x];}; //z.
11+
12+
/ get the ticker plant and history ports, defaults are 5010,5012
13+
//.u.x:.z.x,(count .z.x)_(":5010";":5012");
14+
.u.x:.z.x,(count .z.x)_(":5010:kdbuser:kdbpassword";":5012:kdbuser:kdbpassword"); //z.
15+
16+
/ end of day: save, clear, hdb reload
17+
//z.:At end of day, the tickerplant sends messages to all its real time subscribers, telling them to execute their monadic end of day function called `.u.end. The tickerplant supplies a date which is typically the previous day’s date. When customizing your RTS, define .u.end to achieve whatever behavior you deem appropriate at end of day.
18+
//z.:t@:where `g=attr each t@\:`sym;: This line obtains the subset of tables in t that have the grouped attribute on their sym column. This is done because later these tables will be emptied out and their attribute information will be lost. Therefore we store this attribute information now so the attributes can be re-applied after the clear out.
19+
//z.:.Q.hdpf is a high level function which saves all in memory tables to disk in partitioned format, empties them out and then instructs the HDB to reload. Its inputs at runtime will be: (1)location of HDB,(2) `:. (current working directory – root of on-disk partitioned database),(3) x=2016.07.12 (input to .u.end as supplied by TP. This is the partition to write to),(4) `sym (column on which to sort/part the tables prior to persisting)
20+
//z.:@[;`sym;`g#] each t; applies the g attribute to the sym column of each table as previously discussed
21+
//.u.end:{t:tables`.;t@:where `g=attr each t@\:`sym;.Q.hdpf[`$":",.u.x 1;`:.;x;`sym];@[;`sym;`g#] each t;}; //orginal
22+
23+
k)hdpft:{[h;d;p;f;t](@[`.;;0#].Q.dpft[d;p;f]@)'t@>(#.:)'t;if[h:@[<:;h;0];h"\\l .";>h]}; //z. added;changed from .Q.hdpf
24+
.u.end:{t:enlist`bar;t@:where `g=attr each t@\:`sym;hdpft[`$":",.u.x 1;hsym[`$ssr[ssr[getenv[`qhome];"\\";"/"];"/q";"/hdb"]];x;`sym;t];@[;`sym;`g#] each t;}; // changed by z.; 修改保存路径;修改为只保存bar表;若要保存taq,请参照修改,并删除本文件最后一行)
25+
26+
/ init schema and sync up from log file;cd to hdb(so client save can run)
27+
//z.:This function is invoked at startup once the RDB has connected/subscribed to the TP. .u.rep takes two inputs. The first input, x, is a list of two-element lists, each containing a table name (as a symbol) and an empty schema for that table. The second argument to .u.rep, y, is a single two-element list. These inputs are supplied by the TP upon subscription.y is a pair where the last element is the TP logfile and the first element is the number of messages written to this logfile so far.
28+
//z.:(.[;();:;].)each x; ==((set[;].) each x;)This line just loops over the table name/empty table pairs and initializes these tables accordingly within the current working namespace (default namespace).
29+
//z.:-11!y; This line simply replays an appropriate number of messages from the start of the TP logfile.
30+
//z.:system "cd ",1_-10_string first reverse y; This changes the current working directory of the RDB to the root of the on-disk partitioned database. Therefore, when .Q.hdpf is invoked at EOD, the day’s records will be written to the correct place.
31+
.u.rep:{(.[;();:;].)each x;if[null first y;:()];-11!y;system "cd ",1_-10_string first reverse y};
32+
/ HARDCODE \cd if other than logdir/db
33+
34+
/ connect to ticker plant for (schema;(logcount;log))
35+
//z.:kicks the RDB into life. hopen `$":",.u.x 0 Reading this from the right, we obtain the location of the tickerplant process which is then passed into the hopen function. hopen returns a handle (connection) to the tickerplant. Through this handle, we then send a synchronous message to the tickerplant, telling it to do two things:1. Subscribe to all tables and to all symbols. 2. Obtain name/location of TP logfile and number of messages written by TP to said logfile . `.u `i: .u.i - msg count in log file `.u `L: .u.L - tp log filename, e.g. `:./sym2008.09.11
36+
37+
//z.:.u.sub is a dyadic function defined on the tickerplant. If passed null symbols (as is the case here), it will return a list of pairs (table name/empty table), consistent with the first input to .u.rep
38+
.u.rep .(hopen `$":",.u.x 0)"(.u.sub[`;`];`.u `i`L)"; //original
39+
40+
41+
//z.: ref: Building Real Time Tick Subscribers q_for_Gods_Aug_2014.pdf http://www.firstderivatives.com/downloads/q_for_Gods_July_2014.pdf
42+
43+
if[`taq in key `.;taq:`sym xkey taq]; //z.

q/tick/tick/sym.q

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
taq:([]time:`time$();sym:`g#`symbol$();prevclose:`real$();open:`real$();high:`real$();low:`real$();close:`real$();volume:`real$();openint:`real$();bid:`real$();bsize:`real$();ask:`real$();asize:`real$()); //trade & quote
2+
3+
bar:([]time:`time$();sym:`g#`symbol$();close:`real$();volume:`real$()); //trade
4+
5+
msg:([]time:`time$();sym:`g#`symbol$();src:`int$();dst:();t:`$();data:());
6+

0 commit comments

Comments
 (0)