├── 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 --------------------------------------------------------------------------------