Legere potes quid in basi KDB+, in lingua programmandi Q sint, quae vires et debilitates in praecedentibus meis sunt.
introduction
KDB+ datorum columnarum in maximas notitiarum copia feruntur, certo modo (praesertim tempore). Imprimis adhibetur in institutis nummariis, ripae, pecuniae collocandae, manipulos assecurationis. Lingua Q lingua est interna KDB+ quae te cum hac notitia efficaciter operari sinit. In Q doetrina brevitas et efficacia est, et claritas immolatur. Hoc iustificatur ex eo quod lingua vector difficilis erit ad intelligendum in omni casu, et brevitas et ubertas recordationis permittit te videre multo maiorem partem programmatis in uno velo, quod tandem facilius intellegitur.
In hoc articulo programma in Q currum plenam efficiendum et experiri forsitan velis. Ad hoc faciendum, ipsa Q. egere potes liberam 32-bit versionem in kx societatis paginae -
DE PECCATO quaestio
Fons est qui mensam mittit cum singulis 25 milliseconds notitia. Cum KDB+ principaliter in rebus oeconomicis adhibetur, ponemus hanc esse tabulam negotiorum (artium), quae habet sequentes columnas: tempus (tempus milliseconds), sym (comitatio designatio in commercio stirpis - IBM, AAPL,. Intervallum XXV millisecondum arbitrarium est, nec nimium parvum nec longum. Praesentia eius significat notitias ad servitium iam buffered. Facile esset ad efficiendum buffering in parte muneris, inter dynamica buffering pendentia in onere currenti, sed pro simplicitate fixum intervallum ponemus.
Ministerium singulis momentis pro singulis advenientibus symbolo computare debet e sym columnae statuto functionum aggregationis - max pretis, avg pretii, summae magnitudinis, etc. utilis notitia. Pro simplicitate, ponemus omnes functiones incrementaliter computari posse, i.e. ut novum valorem obtineat, satis est duos numeros cognoscere, veteres et advenientes valores. Exempli gratia, munera max, mediocris, summa proprietatem hanc habent, sed munus mediana non habet.
Volumus etiam, ut rivus notitiae advenientis tempus iussum sit. Haec nobis facultas operandi solum ultimo minuto dabit. Re, satis est cum momentis currentibus et prioribus elaborare posse si quaedam recentia updates sunt. Pro simplici hoc casu non consideramus.
Aggregatio munera
Munera aggregationis debita infra recensentur. Earum quam plurimas accepi, ut onus in ministerium augerem;
- magno - max pretio - maximum pretium per minute.
- low - min price - minimum price per minute.
- firstPrice - first price - first price per minute.
- lastPrice - last price - last price per minute.
- firstSize - first size - first trade size per minute.
- lastSize - last size - last trade size in minutam.
- numTrades - count i - number of artium per minute.
- Volume - summa magnitudo - summa commercii magnitudinum per minutum.
- pvolume - summa pretia - summa pretia per minutias, pro avgPrice requisiti.
- - sum turnover price* size - total volumen transactionum per minute.
- avgPrice - pvolume%numTrades - mediocris pretium per minute.
- avgSize - volume%numTrades - mediocris artis magnitudo per minute.
- vwap - turnover% volume - mediocris pretium per minute praegravatis negotii magnitudine.
- cumVolume - summa volubilis - magnitudine rerum per totum tempus congesta.
De puncto non conspicuo statim discutiamus β quomodo has columnas primum initializes et minutas singulas subsequentes. Nonnullae primae quantitatis columnae singulis temporibus initiales fieri debent, earumque valor indefinitus est. Aliae figurae voluminis semper ad 0. Exstant etiam columnae quae accessum coniunctum requirunt - exempli gratia, cum Volumen ex priori minuto exscribendum sit, et primum ad 0. Ponamus omnes istos parametros utentes dictionarii notitia type (analogus to a record):
// list ! list β ΡΠΎΠ·Π΄Π°ΡΡ ΡΠ»ΠΎΠ²Π°ΡΡ, 0n β float null, 0N β long null, `sym β ΡΠΈΠΏ ΡΠΈΠΌΠ²ΠΎΠ», `sym1`sym2 β ΡΠΏΠΈΡΠΎΠΊ ΡΠΈΠΌΠ²ΠΎΠ»ΠΎΠ²
initWith:`sym`time`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover`avgPrice`avgSize`vwap`cumVolume!(`;00:00;0n;0n;0n;0n;0N;0N;0;0;0.0;0.0;0n;0n;0n;0);
aggCols:reverse key[initWith] except `sym`time; // ΡΠΏΠΈΡΠΎΠΊ Π²ΡΠ΅Ρ
Π²ΡΡΠΈΡΠ»ΡΠ΅ΠΌΡΡ
ΠΊΠΎΠ»ΠΎΠ½ΠΎΠΊ, reverse ΠΎΠ±ΡΡΡΠ½Π΅Π½ Π½ΠΈΠΆΠ΅
Addidi sym et tempus glossarium commoditatis, nunc initWith linea parata facta est e tabula finali aggregata, ubi superest ut rectam sym et tempus apponas. Ad mensam novos ordines addere potes.
Nos aggCols egebimus, cum munus aggregationis creando. Elenchus invertendus est ob ordinem quo aestimantur expressiones in Q (a dextra ad sinistram). Finis est curare calculus ab alto usque ad cumVolume, quoniam aliquae columnae a superioribus pendent.
Columnae quae ex priori novo minuto exscribendae sunt, ad commodam sym columnam additur:
rollColumns:`sym`cumVolume;
Nunc columnas dividamus in partes secundum quomodo renovandae sunt. Tria genera distingui possunt;
- Accumulatores (volumen, turnover,...) β accessum valorem priori adiciendum est.
- Peculiari puncto (alto, humili, ..) - prima valoris in minuto ex notitia advenientis accipitur, reliqua functione utentes computantur.
- Requiem. Semper ratione usus functionis.
Diffinimus variabiles hasce classes:
accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;
Calculus ordo
Mensam aggregatam in duobus gradibus renovabimus. Ad efficientiam venientem tabulam primo abhorremus ita ut unus tantum ordo sit cuiusque characteris et momenti. Quod omnia munera nostra sunt cautiones incrementales et associativas quod effectus accessus additi gradus non mutatur. Mensam recusare poteras utens eligere:
select high:max price, low:min price β¦ by sym,time.minute from table
Haec methodus incommodum habet - copia columnarum calculi praedefinita est. Fortunate, in Q, selectis etiam munus impletur ubi rationes dynamice creatae substituere potes;
?[table;whereClause;byClause;selectClause]
Formam argumentorum non singillatim describam, in casu tantum ac voces selectae nontriviales erunt et dictionaria columnarum formarum sint locutiones. Quapropter munus recusationis sic definiri potest:
selExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover!parse each ("max price";"min price";"first price";"last price";"first size";"last size";"count i";"sum size";"sum price";"sum price*size"); // each ΡΡΠΎ ΡΡΠ½ΠΊΡΠΈΡ map Π² Q Π΄Π»Ρ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠΏΠΈΡΠΊΠ°
preprocess:?[;();`sym`time!`sym`time.minute;selExpression];
Ad evidentiam, usus sum functione parse, quae filum cum expressione Q vertit in valorem qui ad munus coaevum transiri potest et quod in munere selecto requiritur. Notandum etiam quod preprocessus definitur proiectio (i.e., functio cum argumentis partim definitis) functionis selectae, unum argumentum deesse. Si praeprocessionem applicamus ad mensam, compressam mensam accipiemus.
Secundus gradus mensam aggregatam adaequat. Primum algorithmum in pseudocode scribamus:
for each sym in inputTable
idx: row index in agg table for sym+currentTime;
aggTable[idx;`high]: aggTable[idx;`high] | inputTable[sym;`high];
aggTable[idx;`volume]: aggTable[idx;`volume] + inputTable[sym;`volume];
β¦
In Q, commune est functionum tabularum reducere pro ansulis uti. Sed quia Q est lingua vector et omnes operationes ad omnia simul symbola facile possumus, deinde ad primam approximationem sine ansa facere possumus, operationes in omnibus symbolis simul peragentes;
idx:calcIdx inputTable;
row:aggTable idx;
aggTable[idx;`high]: row[`high] | inputTable`high;
aggTable[idx;`volume]: row[`volume] + inputTable`volume;
β¦
Sed ulterius progredi possumus, Q habet operator singularem et valde potentem - operator assignatio generalis. Permittit te mutare certa bona in structura notitia multiplici utens indice indices, munerum et argumentorum. In nostro casu sic spectat:
idx:calcIdx inputTable;
rows:aggTable idx;
// .[target;(idx0;idx1;..);function;argument] ~ target[idx 0;idx 1;β¦]: function[target[idx 0;idx 1;β¦];argument], Π² Π½Π°ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°Π΅ ΡΡΠ½ΠΊΡΠΈΡ β ΡΡΠΎ ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π½ΠΈΠ΅
.[aggTable;(idx;aggCols);:;flip (row[`high] | inputTable`high;row[`volume] + inputTable`volume;β¦)];
Infeliciter, tabulae assignare debes index ordinum, non columnarum, et matricem (album columnarum ad indicem ordinum) transponere debes, functione flip. Haec carus est pro magna mensa, sic loco singulae columnae divisim assignationem generalem applicamus, functione geographica adhibita (quae sicut apostropha spectat);
.[aggTable;;:;]'[(idx;)each aggCols; (row[`high] | inputTable`high;row[`volume] + inputTable`volume;β¦)];
Munus proiectura iterum utimur. Etiam notandum est quod in Q, elenchum creans munus quoque esse et appellare possumus eum utentem singulas functiones ut indicem tabularum accipias.
Ut statuta columnarum calcularum non figatur, hanc expressionem alacriter efficiemus. Prius functiones definias ad singulas columnas computandas, variabilium versuum et inp utentium, referre ad notitias aggregatas et initus;
aggExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`avgPrice`avgSize`vwap`cumVolume!
("row[`high]|inp`high";"row[`low]&inp`low";"row`firstPrice";"inp`lastPrice";"row`firstSize";"inp`lastSize";"pvolume%numTrades";"volume%numTrades";"turnover%volume";"row[`cumVolume]+inp`volume");
Quaedam sunt speciales columnae, earum prima dignitas non pensari debet. Determinare possumus eam esse primam per columnam [`numTrades] β si contineat 0, primum valorem. Q munus selectum habet - ?[Index Boolean;list1;list2] - qui valorem eligit ex indice 1 vel 2 secundum conditionem primae argumenti:
// high -> ?[isFirst;inp`high;row[`high]|inp`high]
// @ - ΡΠΎΠΆΠ΅ ΠΎΠ±ΠΎΠ±ΡΠ΅Π½Π½ΠΎΠ΅ ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π½ΠΈΠ΅ Π΄Π»Ρ ΡΠ»ΡΡΠ°Ρ ΠΊΠΎΠ³Π΄Π° ΠΈΠ½Π΄Π΅ΠΊΡ Π½Π΅Π³Π»ΡΠ±ΠΎΠΊΠΈΠΉ
@[`aggExpression;specialCols;{[x;y]"?[isFirst;inp`",y,";",x,"]"};string specialCols];
Hic vocavi munus generale cum mea functione (expressio in crispo adstringit). Praesens valorem (primum argumentum) recipit et argumentum adiectum, quod in 4to parametro praetereo.
Seorsim adiciamus oratores altilium, quia idem est illis munus;
// volume -> row[`volume]+inp`volume
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
Haec signa consueta est assignatio per Q, sed indicem valorum statim assigno. Postremo munus praecipuum crearemus;
// ":",/:aggExprs ~ map[{":",x};aggExpr] => ":row[`high]|inp`high" ΠΏΡΠΈΡΠ²ΠΎΠΈΠΌ Π²ΡΡΠΈΡΠ»Π΅Π½Π½ΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ, ΠΏΠΎΡΠΎΠΌΡ ΡΡΠΎ Π½Π΅ΠΊΠΎΡΠΎΡΡΠ΅ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠΈ Π·Π°Π²ΠΈΡΡΡ ΠΎΡ ΡΠΆΠ΅ Π²ΡΡΠΈΡΠ»Π΅Π½Π½ΡΡ
Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ
// string[cols],'exprs ~ map[,;string[cols];exprs] => "high:row[`high]|inp`high" Π·Π°Π²Π΅ΡΡΠΈΠΌ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π½ΠΈΡ. ,β ΡΠ°ΡΡΠΈΡΡΠΎΠ²ΡΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΊ map[concat]
// ";" sv exprs β String from Vector (sv), ΡΠΎΠ΅Π΄ΠΈΠ½ΡΠ΅Ρ ΡΠΏΠΈΡΠΎΠΊ ΡΡΡΠΎΠΊ Π²ΡΡΠ°Π²Π»ΡΡ β;β ΠΏΠΎΡΡΠ΅Π΄ΠΈΠ½Π΅
updateAgg:value "{[aggTable;idx;inp] row:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols;(",(";"sv string[aggCols],'":",/:aggExpression aggCols),")]}";
Hac expressione, dynamice munus creo ex filo quod supra dictum est continet. Eventus sic erit:
{[aggTable;idx;inp] rows:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols ;(cumVolume:row[`cumVolume]+inp`cumVolume;β¦ ; high:?[isFirst;inp`high;row[`high]|inp`high])]}
Columna aestimatio ordinis invertitur eo quia ordo aestimationis in Q est a dextro ad sinistrum.
Nunc habemus duas praecipuas functiones ad calculos necessarias, tantum opus est ut paulo infrastructura addatur et ad servitium promptum.
Gradus finales
Praeprocessionem habemus et renovationes Agg functiones quae totum opus faciunt. Sed adhuc necessarium est ut rectam transitum per minutas et indices pro aggregatione curaret. Primum munus initum definiamus;
init:{
tradeAgg:: 0#enlist[initWith]; // ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΏΡΡΡΡΡ ΡΠΈΠΏΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΡΠ°Π±Π»ΠΈΡΡ, enlist ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅Ρ ΡΠ»ΠΎΠ²Π°ΡΡ Π² ΡΠ°Π±Π»ΠΈΡΡ, Π° 0# ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ Π²Π·ΡΡΡ 0 ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΠΈΠ· Π½Π΅Π΅
currTime::00:00; // Π½Π°ΡΠ½Π΅ΠΌ Ρ 0, :: ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ, ΡΡΠΎ ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π½ΠΈΠ΅ Π² Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΡ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ
currSyms::`u#`symbol$(); // `u# - ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅Ρ ΡΠΏΠΈΡΠΎΠΊ Π² Π΄Π΅ΡΠ΅Π²ΠΎ, Π΄Π»Ρ ΡΡΠΊΠΎΡΠ΅Π½ΠΈΡ ΠΏΠΎΠΈΡΠΊΠ° ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ²
offset::0; // ΠΈΠ½Π΄Π΅ΠΊΡ Π² tradeAgg, Π³Π΄Π΅ Π½Π°ΡΠΈΠ½Π°Π΅ΡΡΡ ΡΠ΅ΠΊΡΡΠ°Ρ ΠΌΠΈΠ½ΡΡΠ°
rollCache:: `sym xkey update `u#sym from rollColumns#tradeAgg; // ΠΊΡΡ Π΄Π»Ρ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ
Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ roll ΠΊΠΎΠ»ΠΎΠ½ΠΎΠΊ, ΡΠ°Π±Π»ΠΈΡΠ° Ρ ΠΊΠ»ΡΡΠΎΠΌ sym
}
Etiam munus volvi definiemus, quod currens minutum mutabit;
roll:{[tm]
if[currTime>tm; :init[]]; // Π΅ΡΠ»ΠΈ ΠΏΠ΅ΡΠ΅Π²Π°Π»ΠΈΠ»ΠΈ Π·Π° ΠΏΠΎΠ»Π½ΠΎΡΡ, ΡΠΎ ΠΏΡΠΎΡΡΠΎ Π²ΡΠ·ΠΎΠ²Π΅ΠΌ init
rollCache,::offset _ rollColumns#tradeAgg; // ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ ΠΊΡΡ β Π²Π·ΡΡΡ roll ΠΊΠΎΠ»ΠΎΠ½ΠΊΠΈ ΠΈΠ· aggTable, ΠΎΠ±ΡΠ΅Π·Π°ΡΡ, Π²ΡΡΠ°Π²ΠΈΡΡ Π² rollCache
offset::count tradeAgg;
currSyms::`u#`$();
}
Munus nos oportet addere novas characteres:
addSyms:{[syms]
currSyms,::syms; // Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² ΡΠΏΠΈΡΠΎΠΊ ΠΈΠ·Π²Π΅ΡΡΠ½ΡΡ
// Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π² ΡΠ°Π±Π»ΠΈΡΡ sym, time ΠΈ rollColumns Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π²ΡΠΈΡΡ ΠΎΠ±ΠΎΠ±ΡΠ΅Π½Π½ΡΠΌ ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π½ΠΈΠ΅ΠΌ.
// Π€ΡΠ½ΠΊΡΠΈΡ ^ ΠΏΠΎΠ΄ΡΡΠ°Π²Π»ΡΠ΅Ρ Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Π΄Π»Ρ roll ΠΊΠΎΠ»ΠΎΠ½ΠΎΠΊ, Π΅ΡΠ»ΠΈ ΡΠΈΠΌΠ²ΠΎΠ»Π° Π½Π΅Ρ Π² ΠΊΡΡΠ΅. value flip table Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ ΡΠΏΠΈΡΠΎΠΊ ΠΊΠΎΠ»ΠΎΠ½ΠΎΠΊ Π² ΡΠ°Π±Π»ΠΈΡΠ΅.
`tradeAgg upsert @[count[syms]#enlist initWith;`sym`time,cols rc;:;(syms;currTime), (initWith cols rc)^value flip rc:rollCache ([] sym: syms)];
}
Ac denique munus upd (nomen traditum huic functioni pro Q servitiis), quod a cliente dicitur, notitias addere;
upd:{[tblName;data] // tblName Π½Π°ΠΌ Π½Π΅ Π½ΡΠΆΠ½ΠΎ, Π½ΠΎ ΠΎΠ±ΡΡΠ½ΠΎ ΡΠ΅ΡΠ²ΠΈΡ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠ°Π±Π»ΠΈΡ
tm:exec distinct time from data:() xkey preprocess data; // preprocess & calc time
updMinute[data] each tm; // Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π΄Π°Π½Π½ΡΠ΅ Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΌΠΈΠ½ΡΡΡ
};
updMinute:{[data;tm]
if[tm<>currTime; roll tm; currTime::tm]; // ΠΏΠΎΠΌΠ΅Π½ΡΠ΅ΠΌ ΠΌΠΈΠ½ΡΡΡ, Π΅ΡΠ»ΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ
data:select from data where time=tm; // ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ
if[count msyms:syms where not (syms:data`sym)in currSyms; addSyms msyms]; // Π½ΠΎΠ²ΡΠ΅ ΡΠΈΠΌΠ²ΠΎΠ»Ρ
updateAgg[`tradeAgg;offset+currSyms?syms;data]; // ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ Π°Π³ΡΠ΅Π³ΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΡΠ°Π±Π»ΠΈΡΡ. Π€ΡΠ½ΠΊΡΠΈΡ ? ΠΈΡΠ΅Ρ ΠΈΠ½Π΄Π΅ΠΊΡ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΡΠΏΠΈΡΠΊΠ° ΡΠΏΡΠ°Π²Π° Π² ΡΠΏΠΈΡΠΊΠ΅ ΡΠ»Π΅Π²Π°.
};
Id omne. Hic est integer codicis nostri officium, ut pollicitus est, paucas lineas;
initWith:`sym`time`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover`avgPrice`avgSize`vwap`cumVolume!(`;00:00;0n;0n;0n;0n;0N;0N;0;0;0.0;0.0;0n;0n;0n;0);
aggCols:reverse key[initWith] except `sym`time;
rollColumns:`sym`cumVolume;
accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;
selExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`numTrades`volume`pvolume`turnover!parse each ("max price";"min price";"first price";"last price";"first size";"last size";"count i";"sum size";"sum price";"sum price*size");
preprocess:?[;();`sym`time!`sym`time.minute;selExpression];
aggExpression:`high`low`firstPrice`lastPrice`firstSize`lastSize`avgPrice`avgSize`vwap`cumVolume!("row[`high]|inp`high";"row[`low]&inp`low";"row`firstPrice";"inp`lastPrice";"row`firstSize";"inp`lastSize";"pvolume%numTrades";"volume%numTrades";"turnover%volume";"row[`cumVolume]+inp`volume");
@[`aggExpression;specialCols;{"?[isFirst;inp`",y,";",x,"]"};string specialCols];
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
updateAgg:value "{[aggTable;idx;inp] row:aggTable idx; isFirst_0=row`numTrades; .[aggTable;;:;]'[(idx;)each aggCols;(",(";"sv string[aggCols],'":",/:aggExpression aggCols),")]}"; / '
init:{
tradeAgg::0#enlist[initWith];
currTime::00:00;
currSyms::`u#`symbol$();
offset::0;
rollCache:: `sym xkey update `u#sym from rollColumns#tradeAgg;
};
roll:{[tm]
if[currTime>tm; :init[]];
rollCache,::offset _ rollColumns#tradeAgg;
offset::count tradeAgg;
currSyms::`u#`$();
};
addSyms:{[syms]
currSyms,::syms;
`tradeAgg upsert @[count[syms]#enlist initWith;`sym`time,cols rc;:;(syms;currTime),(initWith cols rc)^value flip rc:rollCache ([] sym: syms)];
};
upd:{[tblName;data] updMinute[data] each exec distinct time from data:() xkey preprocess data};
updMinute:{[data;tm]
if[tm<>currTime; roll tm; currTime::tm];
data:select from data where time=tm;
if[count msyms:syms where not (syms:data`sym)in currSyms; addSyms msyms];
updateAgg[`tradeAgg;offset+currSyms?syms;data];
};
temptationis
Inhibeamus observantiam ministerii. Quod ut facias, illud in processu separato (pone signum in servicio.q fasciculi) curramus et munus initum vocamus:
q service.q βp 5566
q)init[]
In alio consolare, incipit in secundo processu Q et coniunge primo;
h:hopen `:host:5566
h:hopen 5566 // Π΅ΡΠ»ΠΈ ΠΎΠ±Π° Π½Π° ΠΎΠ΄Π½ΠΎΠΌ Ρ
ΠΎΡΡΠ΅
Primum indicem faciamus symbolorum - 10000 frusta et munus addere ad mensam temere creandam. In secundo console;
syms:`IBM`AAPL`GOOG,-9997?`8
rnd:{[n;t] ([] sym:n?syms; time:t+asc n#til 25; price:n?10f; size:n?10)}
Tria symbola realia addidi in albo, quo facilius ea in tabula quaererem. Munus rnd mensam temere cum n ordinibus creat, ubi tempus ab t ad t+25 milliseconds variatur.
Nunc experiri potes ut notitias mittens ad officium (primas decem horas adde);
{h (`upd;`trade;rnd[10000;x])} each `time$00:00 + til 60*10
Potes inspicere in servitio quod mensa renovata est:
c 25 200
select from tradeAgg where sym=`AAPL
-20#select from tradeAgg where sym=`AAPL
effectus:
sym|time|high|low|firstPrice|lastPrice|firstSize|lastSize|numTrades|volume|pvolume|turnover|avgPrice|avgSize|vwap|cumVolume
--|--|--|--|--|--------------------------------
AAPL|09:27|9.258904|9.258904|9.258904|9.258904|8|8|1|8|9.258904|74.07123|9.258904|8|9.258904|2888
AAPL|09:28|9.068162|9.068162|9.068162|9.068162|7|7|1|7|9.068162|63.47713|9.068162|7|9.068162|2895
AAPL|09:31|4.680449|0.2011121|1.620827|0.2011121|1|5|4|14|9.569556|36.84342|2.392389|3.5|2.631673|2909
AAPL|09:33|2.812535|2.812535|2.812535|2.812535|6|6|1|6|2.812535|16.87521|2.812535|6|2.812535|2915
AAPL|09:34|5.099025|5.099025|5.099025|5.099025|4|4|1|4|5.099025|20.3961|5.099025|4|5.099025|2919
Nunc onere experiamur ut sciamus quanti notitia muneris per minutias processum facere possit. Fac me monere te intervallum renovationis 25 milliseconds constituisse. Proinde officium (mediocris) aptum est saltem viginti millium secundorum per renovationem ad utentes tempus dare petendi notitias. Intra sequentia in secundo processu:
tm:10:00:00.000
stressTest:{[n] 1 string[tm]," "; times,::h ({st:.z.T; upd[`trade;x]; .z.T-st};rnd[n;tm]); tm+:25}
start:{[n] times::(); do[4800;stressTest[n]]; -1 " "; `min`avg`med`max!(min times;avg times;med times;max times)}
(IV)DCCC duo minuta est. Tentare potes primum pro 4800 ordinibus singulis 1000 milliseconds currentem:
start 1000
In casu meo, effectus est circiter duorum millium secundorum per update. Itaque statim numerum versuum ad 10.000 augebo;
start 10000
effectus:
min| 00:00:00.004
avg| 9.191458
med| 9f
max| 00:00:00.030
Iterum nihil speciale, sed hoc est 24 decies centena millia linearum per minutias, 400 mille per secundam. Plus quam 25 millium secundorum millium secundorum renovatio retardatur tantum 5 vicibus, ut videtur, cum minutum mutatur. Crescamus ad 100.000:
start 100000
effectus:
min| 00:00:00.013
avg| 25.11083
med| 24f
max| 00:00:00.108
q)sum times
00:02:00.532
Ut videre potes, ministerium vix tolerare potes, sed tamen administrat meatum manere. Tale volumen notitiarum (CCXL milium ordinum per minutum) perquam magnum est, in quo casu commune est ut complures clones (vel etiam justos clones) servitii emittant, quorum unumquemque tantum partem characterum procedit. Tamen, eventus gravis est ad linguam interpretandam quae principaliter in notitia repono.
Quaeri potest, cur tempus non-lineaaliter cum magnitudine uniuscuiusque renovationis crescat. Ratio est, quia recusatum munus est actu functionis C, quae multo efficacior est quam renovatio Agg. Incipiens a quadam magnitudine renovationis (circa 10.000), renovatio Agg lacunam suam attingit ac deinde tempus exsecutionis eius in magnitudine renovationis non pendet. Ob praelibatum gradum Q ut religio possit tales notitias volumina concoquere. Hoc elucidat quanti momenti sit eligere ius algorithmum cum operando cum magnis data. Aliud punctum est recta tabularia notitiarum in memoria. Si notitia electronica non reponeretur vel tempore non ordinata essemus, tunc nota fierimus cum tali re quae deesset TLB cache - absentia memoriae paginae electronicae in processu electronici cella. Investigatio inscriptionis circiter XXX vicibus accipit si parum prospere, et si notitiae dissipatae sunt, servitium pluries retardare potest.
conclusio,
In hoc articulo demonstravi datorum KDB+ et Q apta esse non solum ad magnas notitias accommodandas et facile per selectas accessiones, sed etiam ad operas processus notitias conficiendas, quae centenis decies centena milium versuum/gigabytorum notitiarum concoquendarum capaces sunt. Q processus . Lingua ipsa Q permittit ad exsecutionem algorithmorum valde concisam et efficacem pertinentium ad processus notitiae ex natura sua vectoris, in dialecto SQL interpres constructa et functiones bibliothecae felicissimae.
Notabo hanc partem iustam esse quid Q facere possit, et alias singulares notas habere. Exempli gratia, protocollum IPC simplicissimum, quod limitem inter singulos Q processuum delet et centum horum processuum in unum retis coniungere sinit, quae in justo servientium in diversis mundi partibus collocari potest.
Source: www.habr.com