├── AquaQFeedHandlerWhitepaper.pdf
├── CMakeLists.txt
├── README.md
├── icons
├── Thumbs.db
├── apple.png
├── linux.png
└── windows.png
└── src
├── fakefeed.c
├── fakefeed.h
├── k.h
├── main.c
├── run.q
├── run.sh
├── socketpair.h
└── w32
├── exports.def
├── fakefeed.def
└── q.lib
/AquaQFeedHandlerWhitepaper.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataIntellectTech/kdb-feedhandler-tutorial/861616dd8d92d0c4b0a734ab0592e40ccb504dc0/AquaQFeedHandlerWhitepaper.pdf
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.6)
2 | project(fakefeed C)
3 |
4 | # Create the binary directory for makefile output and copy over
5 | # a test q script.
6 | file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
7 | file(COPY "src/run.sh" DESTINATION "${CMAKE_SOURCE_DIR}/bin")
8 | file(COPY "src/run.q" DESTINATION "${CMAKE_SOURCE_DIR}/bin")
9 |
10 | set(FEED_SOURCES "src/fakefeed.c")
11 | set(PROJ_SOURCES "src/main.c")
12 |
13 | # Set some operating system dependent flags to be passed to the
14 | # compilers.
15 | if(UNIX)
16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -fpic -std=gnu99")
17 | elseif(WIN32)
18 | set(LINK_LIBS "${CMAKE_SOURCE_DIR}/src/w32/q.lib" "ws2_32.lib")
19 | set(PROJ_SOURCES ${PROJ_SOURCES} "src/w32/exports.def")
20 | set(FEED_SOURCES ${FEED_SOURCES} "src/w32/fakefeed.def")
21 | endif()
22 |
23 | LINK_DIRECTORIES(${CMAKE_BINARY_DIR})
24 |
25 | # Define how the library should be linked to the other objects.
26 | add_library(fakefeed SHARED ${FEED_SOURCES})
27 | set_target_properties(fakefeed PROPERTIES PREFIX "")
28 |
29 | add_library(feedhandler SHARED ${PROJ_SOURCES})
30 | target_link_libraries(feedhandler fakefeed ${LINK_LIBS})
31 | set_target_properties(feedhandler PROPERTIES PREFIX "")
32 |
33 | # Move the finished binaries into the binary folder if installing.
34 | INSTALL(TARGETS feedhandler fakefeed DESTINATION "${CMAKE_SOURCE_DIR}/bin")
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KDB+ Feed Handler Tutorial
2 |
3 | This project demonstrates how to build a feedhandler that interfaces with kdb+.
4 |
5 | Additional PDF documentation on the C API can be found [here][gitpdfdoc]
6 |
7 | Installation & Setup
8 | --------------------
9 |
10 | ### Extra Resources
11 |
12 | This project uses CMake 2.6+ to build across multiple platforms. It has been tested on Linux and
13 | Windows. Execute the following commands on all platforms to create platform appropriate build
14 | files within the `build` directory.
15 |
16 | ```sh
17 | mkdir build; cd build; cmake ..
18 | ```
19 |
20 | ###
Building on Linux
21 |
22 | On Linux, you just need to run make install to complete the build process
23 | and find the binary output in the `../bin` directory.
24 |
25 | ```sh
26 | make install && cd ../bin
27 | ```
28 |
29 | ###
Building on Windows
30 |
31 | On Windows platforms you will need to have the msbuild.exe available on your path. CMake creates
32 | two Visual Studio projects that need to be built. The `INSTALL` project will not modify any of the
33 | code and will just move the binaries from the `../build` directory to the `../bin` directory. An
34 | extra `libqtoc.lib` file will be produced on Windows, which can be ignored after the build process.
35 |
36 | ```bat
37 | msbuild ./ALL_BUILD.vcxproj /p:Configuration=Release
38 | msbuild ./INSTALL.vcxproj /p:Configuration=Release
39 | cd ../bin
40 | ```
41 |
42 | Running the Examples
43 | --------------------
44 |
45 | The resulting directory after running a build should look like this:
46 |
47 | bin/ -- contains the fakefeed.[dll/so] and feedhandler.[dll/so] libraries and run.q
48 | build/ -- contains the makefiles/visual studio projects
49 | src/ -- contains the source code
50 | CMakeLists.txt
51 |
52 | Once the build is complete, navigate to the `bin` directory and execute:
53 |
54 | q run.q
55 |
56 | on Windows plaforms or on Linux:
57 |
58 | ./run.sh
59 |
60 | The `run.sh` script just sets the `LD_LIBRARY_PATH` to look in the current directory before running
61 | the run.q script.
62 |
63 | This will load the C shared objects and bind the functions to names (*init* and *halt*). Instructions
64 | and example commands should be displayed as soon as the the run.q script loads.
65 |
66 | ```apl
67 | ##
68 | # run.q
69 | #
70 | # Example q script that loads in two functions from the feedhandler library
71 | # and defines two tables (quote and trade). Calling the init function will
72 | # start the feed handler and push quotes and trades into their respective
73 | # tables. The halt function will stop the feed handler and release any
74 | # resources it held.
75 | #
76 | # AquaQ Analytics
77 | # kdb+ consultancy, training and support
78 | #
79 | # For questions, comments, requests or bug reports, please contact us
80 | # w: www.aquaq.co.uk
81 | # e: support@aquaq.co.uk
82 | #
83 | # examples:
84 | # init[] to start the feed handler
85 | # halt[] to stop the feed handler
86 | #
87 |
88 | q) init[]
89 | q) count trade
90 | 75376
91 | q) count quote
92 | 848361
93 | q) halt[]
94 | q) -10#quote
95 | time sym exg asksize bidsize askprice bidprice sequence cond
96 | ----------------------------------------------------------------------------------------------------
97 | 2015.04.02D13:00:33.806996000 `YHOO `LSE 463i 303i 20.2 18.45 131364i 0x434040204f220200f88d
98 | 2015.04.02D13:00:33.806996000 `MSFT `LSE 118i 45i 84.6 83.06 74369i 0x40204949867f00000080
99 | 2015.04.02D13:00:33.806996000 `APPL `LSE 191i 110i 81.9 81.852 120771i 0x49464349621013404d62
100 | 2015.04.02D13:00:33.806996000 `IBM `LSE 180i 409i 86.7 85.364 98308i 0x4343435a000000001806
101 | 2015.04.02D13:00:33.806996000 `YHOO `LSE 331i 138i 87.4 85.584 110350i 0x46405a46fb000000e502
102 | ...
103 | ```
104 |
105 | Other Resources
106 | ---------------
107 |
108 | This resource is intended to suppliment the existing Kx Wiki sections on interfacting with C
109 | and provide some concrete examples. Readers should look at the following pages on the Kx Wiki:
110 |
111 | * [Interfacing With C][kxwikiinterface]
112 | * [Extending With C][kxwikiextend]
113 |
114 | [aquaqwebsite]: http://www.aquaq.co.uk "AquaQ Analytics Website"
115 | [aquaqresources]: http://www.aquaq.co.uk/resources "AquaQ Analytics Website Resources"
116 | [gitpdfdoc]: https://github.com/markrooney/kdb-c-interface/blob/master/docs/InterfacingWithC.pdf
117 | [kxwikiinterface]: http://code.kx.com/wiki/Cookbook/InterfacingWithC "Kx Wiki Interfacing with C"
118 | [kxwikiextend]: http://code.kx.com/wiki/Cookbook/ExtendingWithC "Kx Wiki Extending with C"
119 |
--------------------------------------------------------------------------------
/icons/Thumbs.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataIntellectTech/kdb-feedhandler-tutorial/861616dd8d92d0c4b0a734ab0592e40ccb504dc0/icons/Thumbs.db
--------------------------------------------------------------------------------
/icons/apple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataIntellectTech/kdb-feedhandler-tutorial/861616dd8d92d0c4b0a734ab0592e40ccb504dc0/icons/apple.png
--------------------------------------------------------------------------------
/icons/linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataIntellectTech/kdb-feedhandler-tutorial/861616dd8d92d0c4b0a734ab0592e40ccb504dc0/icons/linux.png
--------------------------------------------------------------------------------
/icons/windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataIntellectTech/kdb-feedhandler-tutorial/861616dd8d92d0c4b0a734ab0592e40ccb504dc0/icons/windows.png
--------------------------------------------------------------------------------
/src/fakefeed.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "fakefeed.h"
6 |
7 | #define arraylen(x) (sizeof(x)/sizeof(*(x)))
8 | #define itemfrom(x) x[rand()%arraylen(x)]
9 |
10 | char *syms[5] = { "IBM", "APPL", "GOOG", "MSFT", "YHOO" };
11 | char *exgs[3] = { "CME", "LSE", "BARK" };
12 | char conds[6] = { 'C', 'F', 'I', '@', ' ', 'Z' };
13 |
14 | void GenerateCore(FeedData *data)
15 | {
16 | data->core.sym = itemfrom(syms);
17 | data->core.exg = itemfrom(exgs);
18 |
19 | for (int i = 0; i < 4; i++)
20 | data->core.cond[i] = itemfrom(conds);
21 |
22 | data->core.sequence = rand() % 200000;
23 | }
24 |
25 | void GenerateQuote(FeedData *data)
26 | {
27 | data->type = FF_QUOTE_MSG;
28 | GenerateCore(data);
29 |
30 | data->msg.quote.asksize = rand() % 500;
31 | data->msg.quote.bidsize = rand() % 500;
32 | data->msg.quote.askprice = rand() % 1000 / 10.0;
33 | data->msg.quote.bidprice = (data->msg.quote.askprice) - (rand() % 1000 / 500.0);
34 | }
35 |
36 | void GenerateTrade(FeedData *data)
37 | {
38 | data->type = FF_TRADE_MSG;
39 | GenerateCore(data);
40 |
41 | data->msg.trade.size = rand() % 500;
42 | data->msg.trade.volume = rand () % 1000;
43 | data->msg.trade.price = rand() % 5000 / 10.0;
44 | }
45 |
46 | void ProcessFeed(int (*fn) (const FeedData *))
47 | {
48 | static FeedData feedData;
49 | srand(time(NULL));
50 |
51 | do {
52 | if (rand() % 10) {
53 | GenerateQuote(&feedData);
54 | } else {
55 | GenerateTrade(&feedData);
56 | }
57 | } while (fn(&feedData) == FF_CONTINUE_FEED);
58 | }
59 |
--------------------------------------------------------------------------------
/src/fakefeed.h:
--------------------------------------------------------------------------------
1 | #ifndef fakefeed_h
2 | #define fakefeed_h
3 |
4 | #define FF_TRADE_MSG 0x01
5 | #define FF_QUOTE_MSG 0x02
6 |
7 | #define FF_CONTINUE_FEED 0x40
8 | #define FF_HALT_FEED 0x80
9 |
10 | typedef struct _CoreMessage {
11 | char *sym;
12 | char *exg;
13 | int sequence;
14 | char cond[4];
15 | } CoreMessage;
16 |
17 | typedef struct _TradeMessage {
18 | int size;
19 | int volume;
20 | double price;
21 | } TradeMessage;
22 |
23 | typedef struct _QuoteMessage {
24 | int asksize;
25 | int bidsize;
26 | double askprice;
27 | double bidprice;
28 | } QuoteMessage;
29 |
30 | typedef struct _FeedData {
31 | int type;
32 | CoreMessage core;
33 | union {
34 | TradeMessage trade;
35 | QuoteMessage quote;
36 | } msg;
37 | } FeedData;
38 |
39 | /**
40 | * ProcessFeed is a simple function that populates the statically allocated
41 | * FeedData struct automatically and provides a pointer to it via a callback
42 | * function for each message.
43 | */
44 | void ProcessFeed(int (*) (const FeedData *));
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/src/k.h:
--------------------------------------------------------------------------------
1 | #ifndef KX
2 | #define KX
3 | typedef char*S,C;typedef unsigned char G;typedef short H;typedef int I;typedef long long J;typedef float E;typedef double F;typedef void V;
4 | #ifdef __cplusplus
5 | extern"C"{
6 | #endif
7 | #ifndef KXVER
8 | #error "Set KXVER=3 for kdb+3.0 or standalone c-api after 2011-04-20. Otherwise set KXVER=2"
9 | #endif
10 | #if KXVER>=3
11 | typedef struct k0{signed char m,a,t;C u;I r;union{G g;H h;I i;J j;E e;F f;S s;struct k0*k;struct{J n;G G0[1];};};}*K;
12 | typedef struct{G g[16];}U;
13 | #define kU(x) ((U*)kG(x))
14 | #define xU ((U*)xG)
15 | extern K ku(U),ktn(I,J),kpn(S,J);
16 | extern I setm(I);
17 | #define DO(n,x) {J i=0,_i=(n);for(;i<_i;++i){x;}}
18 | #else
19 | typedef struct k0{I r;H t,u;union{G g;H h;I i;J j;E e;F f;S s;struct k0*k;struct{I n;G G0[1];};};}*K;
20 | extern K ktn(I,I),kpn(S,I);
21 | #define DO(n,x) {I i=0,_i=(n);for(;i<_i;++i){x;}}
22 | #endif
23 | #ifdef __cplusplus
24 | }
25 | #endif
26 | //#include
27 | // vector accessors, e.g. kF(x)[i] for float&datetime
28 | #define kG(x) ((x)->G0)
29 | #define kC(x) kG(x)
30 | #define kH(x) ((H*)kG(x))
31 | #define kI(x) ((I*)kG(x))
32 | #define kJ(x) ((J*)kG(x))
33 | #define kE(x) ((E*)kG(x))
34 | #define kF(x) ((F*)kG(x))
35 | #define kS(x) ((S*)kG(x))
36 | #define kK(x) ((K*)kG(x))
37 |
38 | // type bytes qtype ctype accessor
39 | #define KB 1 // 1 boolean char kG
40 | #define UU 2 // 16 guid U kU
41 | #define KG 4 // 1 byte char kG
42 | #define KH 5 // 2 short short kH
43 | #define KI 6 // 4 int int kI
44 | #define KJ 7 // 8 long long kJ
45 | #define KE 8 // 4 real float kE
46 | #define KF 9 // 8 float double kF
47 | #define KC 10 // 1 char char kC
48 | #define KS 11 // * symbol char* kS
49 |
50 | #define KP 12 // 8 timestamp long kJ (nanoseconds from 2000.01.01)
51 | #define KM 13 // 4 month int kI (months from 2000.01.01)
52 | #define KD 14 // 4 date int kI (days from 2000.01.01)
53 |
54 | #define KN 16 // 8 timespan long kJ (nanoseconds)
55 | #define KU 17 // 4 minute int kI
56 | #define KV 18 // 4 second int kI
57 | #define KT 19 // 4 time int kI (millisecond)
58 |
59 | #define KZ 15 // 8 datetime double kF (DO NOT USE)
60 |
61 | // table,dict
62 | #define XT 98 // x->k is XD
63 | #define XD 99 // kK(x)[0] is keys. kK(x)[1] is values.
64 |
65 | #ifdef __cplusplus
66 | extern"C"{
67 | extern V m9();
68 | #else
69 | extern V m9(V);
70 | #endif
71 | extern I khpun(const S,I,const S,I),khpu(const S,I,const S),khp(const S,I),okx(K),ymd(I,I,I),dj(I);extern V r0(K),sd0(I),kclose(I);extern S sn(S,I),ss(S);
72 | extern K ktj(I,J),ka(I),kb(I),kg(I),kh(I),ki(I),kj(J),ke(F),kf(F),kc(I),ks(S),kd(I),kz(F),kt(I),sd1(I,K(*)(I)),dl(V*f,I),
73 | knk(I,...),kp(S),ja(K*,V*),js(K*,S),jk(K*,K),jv(K*k,K),k(I,const S,...),xT(K),xD(K,K),ktd(K),r1(K),krr(const S),orr(const S),dot(K,K),b9(I,K),d9(K);
74 | #ifdef __cplusplus
75 | }
76 | #endif
77 |
78 | // nulls(n?) and infinities(w?)
79 | #define nh ((I)0xFFFF8000)
80 | #define wh ((I)0x7FFF)
81 | #define ni ((I)0x80000000)
82 | #define wi ((I)0x7FFFFFFF)
83 | #define nj ((J)0x8000000000000000LL)
84 | #define wj 0x7FFFFFFFFFFFFFFFLL
85 | #if WIN32 || _WIN32
86 | #define nf (log(-1.0))
87 | #define wf (-log(0.0))
88 | #define isnan _isnan
89 | #define finite _finite
90 | extern double log(double);
91 | #else
92 | #define nf (0/0.0)
93 | #define wf (1/0.0)
94 | #define closesocket(x) close(x)
95 | #endif
96 |
97 | // remove more clutter
98 | #define O printf
99 | #define R return
100 | #define Z static
101 | #define P(x,y) {if(x)R(y);}
102 | #define U(x) P(!(x),0)
103 | #define SW switch
104 | #define CS(n,x) case n:x;break;
105 | #define CD default
106 |
107 | #define ZV Z V
108 | #define ZK Z K
109 | #define ZH Z H
110 | #define ZI Z I
111 | #define ZJ Z J
112 | #define ZE Z E
113 | #define ZF Z F
114 | #define ZC Z C
115 | #define ZS Z S
116 |
117 | #define K1(f) K f(K x)
118 | #define K2(f) K f(K x,K y)
119 | #define TX(T,x) (*(T*)((G*)(x)+8))
120 | #define xr x->r
121 | #define xt x->t
122 | #define xu x->u
123 | #define xn x->n
124 | #define xx xK[0]
125 | #define xy xK[1]
126 | #define xg TX(G,x)
127 | #define xh TX(H,x)
128 | #define xi TX(I,x)
129 | #define xj TX(J,x)
130 | #define xe TX(E,x)
131 | #define xf TX(F,x)
132 | #define xs TX(S,x)
133 | #define xk TX(K,x)
134 | #define xG x->G0
135 | #define xH ((H*)xG)
136 | #define xI ((I*)xG)
137 | #define xJ ((J*)xG)
138 | #define xE ((E*)xG)
139 | #define xF ((F*)xG)
140 | #define xS ((S*)xG)
141 | #define xK ((K*)xG)
142 | #define xC xG
143 | #define xB ((G*)xG)
144 |
145 | #endif
146 |
147 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | ////
2 | // feedhandler.c
3 | //
4 | // A simple example of how to implement a feed handler that can be compiled as a shared
5 | // library. It uses a background thread for work to keep the main q process thread responsive
6 | // and then uses a socket to push updates to the main thread when it is ready. Error handling
7 | // is kept to a minimum for demonstration purposes.
8 | //
9 | // @updated: 27/03/2015
10 | // @authors: Mark Rooney
11 | //
12 | // AquaQ Analytics
13 | // kdb+ consultancy, training and support
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | // We define two custom thread and socket types (thread_t and socket_t based on the operating
22 | // system that we are based on).
23 | #ifdef WIN32
24 | #include
25 | #include
26 | #include
27 |
28 | #define thread_t HANDLE;
29 | #define socket_t SOCKET;
30 | #else
31 | #include
32 | #include
33 |
34 | #define thread_t pthread_t;
35 | #define socket_t int;
36 | #endif
37 |
38 | #define KXVER 3
39 | #include "k.h"
40 | #include "socketpair.h"
41 | #include "fakefeed.h"
42 |
43 | thread_t thread;
44 | socket_t sockets[2];
45 |
46 | static int FEED_STATE = FF_CONTINUE_FEED;
47 |
48 | #define col(name, type) ktn((type), 0)
49 | #define BUFFER_SIZE 81920
50 |
51 | K create_trade_schema()
52 | {
53 | return knk(7,
54 | col("sym",KS),
55 | col("exg",KS),
56 | col("size",KI),
57 | col("volume",KI),
58 | col("sequence",KI),
59 | col("price",KF),
60 | col("cond", 0));
61 | }
62 |
63 | K create_quote_schema()
64 | {
65 | return knk(8,
66 | col("sym",KS),
67 | col("exg",KS),
68 | col("asksize",KI),
69 | col("bidsize",KI),
70 | col("askprice",KF),
71 | col("bidprice",KF),
72 | col("sequence", KI),
73 | col("cond", 0));
74 | }
75 |
76 | void SendToKDB(char *table, K data)
77 | {
78 | static char buf[BUFFER_SIZE];
79 |
80 | K bytes = b9(-1, data);
81 | r0(data);
82 |
83 | int len = strlen(table);
84 |
85 | // write the table name into the buffer as a string first.
86 | memcpy(buf, (char *) &len, sizeof(int));
87 | memcpy(&buf[sizeof(int)], table, len);
88 |
89 | // copy the data into the buffer to be sent.
90 | memcpy(&buf[sizeof(int) + len], (char *) &bytes->n, sizeof(J));
91 | memcpy(&buf[sizeof(int) + len + sizeof(J)], kG(bytes), (size_t) bytes->n);
92 |
93 | send(sockets[0], buf, (int) (sizeof(int) + len + sizeof(J) + bytes->n), 0);
94 | r0(bytes);
95 | }
96 |
97 | static K trades = (K) 0;
98 | static K quotes = (K) 0;
99 |
100 | static int ProcessMessage(const FeedData *data)
101 | {
102 | static int sent = 0;
103 |
104 | K condvec;
105 |
106 | if (trades == NULL) {
107 | trades = create_trade_schema();
108 | }
109 |
110 | if (quotes == NULL) {
111 | quotes = create_quote_schema();
112 | }
113 |
114 | switch(data->type) {
115 | case FF_TRADE_MSG:
116 | js(&kK(trades)[0], ss(data->core.sym));
117 | js(&kK(trades)[1], ss(data->core.exg));
118 | ja(&kK(trades)[2], (void *) &data->msg.trade.size);
119 | ja(&kK(trades)[3], (void *) &data->msg.trade.volume);
120 | ja(&kK(trades)[4], (void *) &data->core.sequence);
121 | ja(&kK(trades)[5], (void *) &data->msg.trade.price);
122 |
123 | condvec = ktn(4, KC);
124 | memcpy(&kC(condvec)[0], &data->core.cond, 4);
125 | jk(&kK(trades)[6], condvec);
126 |
127 | break;
128 | case FF_QUOTE_MSG:
129 | js(&kK(quotes)[0], ss(data->core.sym));
130 | js(&kK(quotes)[1], ss(data->core.exg));
131 | ja(&kK(quotes)[2], (void *) &data->msg.quote.asksize);
132 | ja(&kK(quotes)[3], (void *) &data->msg.quote.bidsize);
133 | ja(&kK(quotes)[4], (void *) &data->msg.quote.askprice);
134 | ja(&kK(quotes)[5], (void *) &data->msg.quote.bidprice);
135 | ja(&kK(quotes)[6], (void *) &data->core.sequence);
136 |
137 | condvec = ktn(4, KC);
138 | memcpy(&kC(condvec)[0], &data->core.cond, 4);
139 | jk(&kK(quotes)[7], condvec);
140 |
141 | break;
142 | }
143 |
144 | if (++sent >= 10) {
145 | SendToKDB("quote", quotes); quotes = NULL;
146 | SendToKDB("trade", trades); trades = NULL;
147 | sent = 0;
148 | }
149 |
150 | return FEED_STATE;
151 | }
152 |
153 | void read_bytes(size_t numbytes, char (*buf)[BUFFER_SIZE])
154 | {
155 | int total = 0;
156 |
157 | do {
158 | total += recv(sockets[1], &buf[total], (int)(numbytes - total), 0);
159 | } while (total < numbytes);
160 | }
161 |
162 | K recieve_data(I x)
163 | {
164 | static char buf[BUFFER_SIZE];
165 |
166 | read_bytes(sizeof(int), &buf);
167 | int tnamesize = 0;
168 | memcpy(&tnamesize, buf, sizeof(int));
169 |
170 | read_bytes(tnamesize, &buf);
171 | buf[tnamesize] = '\0';
172 |
173 | K tname = ks(buf);
174 |
175 | read_bytes(sizeof(J), &buf);
176 | J size = 0;
177 | memcpy(&size, buf, sizeof(J));
178 |
179 | read_bytes(size, &buf);
180 | K bytes = ktn(KG, size);
181 | memcpy(kG(bytes), &buf, (size_t) size);
182 |
183 | K result = k(0, ".u.upd", tname, d9(bytes), (K) 0);
184 | r0(bytes);
185 |
186 | if (result != 0) {
187 | r0(result);
188 | }
189 |
190 | return (K) 0;
191 | }
192 |
193 | #ifdef WIN32
194 | static unsigned __stdcall process_feed(void *ptr)
195 | {
196 | ProcessFeed(ProcessMessage);
197 | }
198 |
199 | static void start_thread()
200 | {
201 | thread = _beginthreadex(NULL, 0, process_feed, NULL, NULL, 0);
202 | }
203 | #else
204 | static void *process_feed(void *input)
205 | {
206 | ProcessFeed(ProcessMessage);
207 | m9();
208 | }
209 |
210 | static void start_thread()
211 | {
212 | pthread_create(&thread, NULL, process_feed, (void *)sockets[0]);
213 | }
214 | #endif
215 |
216 | K init(K x)
217 | {
218 | dumb_socketpair(sockets, 0);
219 | sd1(sockets[1], recieve_data);
220 |
221 | FEED_STATE = FF_CONTINUE_FEED;
222 | start_thread();
223 |
224 | return (K) 0;
225 | }
226 |
227 | K halt(K x)
228 | {
229 | FEED_STATE = FF_HALT_FEED;
230 |
231 | // if (sockets[0] != -1) close(sockets[0]);
232 | if (sockets[1] != -1) sd0(sockets[1]);
233 |
234 | return (K) 0;
235 | }
236 |
--------------------------------------------------------------------------------
/src/run.q:
--------------------------------------------------------------------------------
1 | init:`:./feedhandler 2:(`init;1)
2 | halt:`:./feedhandler 2:(`halt;1)
3 |
4 | trade:([]time:`timestamp$(); sym:`g#`symbol$(); exg:`symbol$(); size:(); volume:(); sequence:(); price:(); cond:());
5 | quote:([]time:`timestamp$(); sym:`g#`symbol$(); exg:`symbol$(); asksize:(); bidsize:(); askprice:(); bidprice:(); sequence:(); cond:());
6 |
7 | .u.upd:{[t;x] insert[t] each .z.p,'flip x; }
--------------------------------------------------------------------------------
/src/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export LD_LIBRARY_PATH="./"
4 | rlwrap q run.q
5 |
--------------------------------------------------------------------------------
/src/socketpair.h:
--------------------------------------------------------------------------------
1 | /* socketpair.c
2 | Copyright 2007, 2010 by Nathan C. Myers
3 | Redistribution and use in source and binary forms, with or without modification,
4 | are permitted provided that the following conditions are met:
5 |
6 | Redistributions of source code must retain the above copyright notice, this
7 | list of conditions and the following disclaimer.
8 |
9 | Redistributions in binary form must reproduce the above copyright notice,
10 | this list of conditions and the following disclaimer in the documentation
11 | and/or other materials provided with the distribution.
12 |
13 | The name of the author must not be used to endorse or promote products
14 | derived from this software without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | /* Changes:
29 | * 2014-02-12: merge David Woodhouse, Ger Hobbelt improvements
30 | * git.infradead.org/users/dwmw2/openconnect.git/commitdiff/bdeefa54
31 | * github.com/GerHobbelt/selectable-socketpair
32 | * always init the socks[] to -1/INVALID_SOCKET on error, both on Win32/64
33 | * and UNIX/other platforms
34 | * 2013-07-18: Change to BSD 3-clause license
35 | * 2010-03-31:
36 | * set addr to 127.0.0.1 because win32 getsockname does not always set it.
37 | * 2010-02-25:
38 | * set SO_REUSEADDR option to avoid leaking some windows resource.
39 | * Windows System Error 10049, "Event ID 4226 TCP/IP has reached
40 | * the security limit imposed on the number of concurrent TCP connect
41 | * attempts." Bleah.
42 | * 2007-04-25:
43 | * preserve value of WSAGetLastError() on all error returns.
44 | * 2007-04-22: (Thanks to Matthew Gregan )
45 | * s/EINVAL/WSAEINVAL/ fix trivial compile failure
46 | * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout
47 | * of a child process.
48 | * add argument make_overlapped
49 | */
50 |
51 | #include
52 |
53 | #ifdef WIN32
54 | # include /* socklen_t, et al (MSVC20xx) */
55 | # include
56 | # include
57 | #else
58 | # include
59 | # include
60 | # include
61 | #endif
62 |
63 | #ifdef WIN32
64 |
65 | /* dumb_socketpair:
66 | * If make_overlapped is nonzero, both sockets created will be usable for
67 | * "overlapped" operations via WSASend etc. If make_overlapped is zero,
68 | * socks[0] (only) will be usable with regular ReadFile etc., and thus
69 | * suitable for use as stdin or stdout of a child process. Note that the
70 | * sockets must be closed with closesocket() regardless.
71 | */
72 |
73 | int dumb_socketpair(SOCKET socks[2], int make_overlapped)
74 | {
75 | union {
76 | struct sockaddr_in inaddr;
77 | struct sockaddr addr;
78 | } a;
79 | SOCKET listener;
80 | int e;
81 | socklen_t addrlen = sizeof(a.inaddr);
82 | DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0);
83 | int reuse = 1;
84 |
85 | if (socks == 0) {
86 | WSASetLastError(WSAEINVAL);
87 | return SOCKET_ERROR;
88 | }
89 | socks[0] = socks[1] = -1;
90 |
91 | listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
92 | if (listener == -1)
93 | return SOCKET_ERROR;
94 |
95 | memset(&a, 0, sizeof(a));
96 | a.inaddr.sin_family = AF_INET;
97 | a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
98 | a.inaddr.sin_port = 0;
99 |
100 | for (;;) {
101 | if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,
102 | (char*) &reuse, (socklen_t) sizeof(reuse)) == -1)
103 | break;
104 | if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
105 | break;
106 |
107 | memset(&a, 0, sizeof(a));
108 | if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
109 | break;
110 | // win32 getsockname may only set the port number, p=0.0005.
111 | // ( http://msdn.microsoft.com/library/ms738543.aspx ):
112 | a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
113 | a.inaddr.sin_family = AF_INET;
114 |
115 | if (listen(listener, 1) == SOCKET_ERROR)
116 | break;
117 |
118 | socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
119 | if (socks[0] == -1)
120 | break;
121 | if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
122 | break;
123 |
124 | socks[1] = accept(listener, NULL, NULL);
125 | if (socks[1] == -1)
126 | break;
127 |
128 | closesocket(listener);
129 | return 0;
130 | }
131 |
132 | e = WSAGetLastError();
133 | closesocket(listener);
134 | closesocket(socks[0]);
135 | closesocket(socks[1]);
136 | WSASetLastError(e);
137 | socks[0] = socks[1] = -1;
138 | return SOCKET_ERROR;
139 | }
140 | #else
141 | int dumb_socketpair(int socks[2], int dummy)
142 | {
143 | if (socks == 0) {
144 | errno = EINVAL;
145 | return -1;
146 | }
147 | dummy = socketpair(AF_LOCAL, SOCK_STREAM, 0, socks);
148 | if (dummy)
149 | socks[0] = socks[1] = -1;
150 | return dummy;
151 | }
152 | #endif
153 |
--------------------------------------------------------------------------------
/src/w32/exports.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | init
3 | halt
--------------------------------------------------------------------------------
/src/w32/fakefeed.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | ProcessFeed
--------------------------------------------------------------------------------
/src/w32/q.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataIntellectTech/kdb-feedhandler-tutorial/861616dd8d92d0c4b0a734ab0592e40ccb504dc0/src/w32/q.lib
--------------------------------------------------------------------------------