ዚእውነተኛ ጊዜ አገልግሎት ምሳሌን በመጠቀም ዹQ እና ዹKDB+ ቋንቋ ባህሪዎቜ

ስለ KDB+ መሰሚት፣ ዹQ ፕሮግራሚንግ ቋንቋ ምን እንደሆነ፣ በቀድሞዬ ውስጥ ምን ጥንካሬ እና ድክመቶቜ እንዳሉ ማንበብ ትቜላለህ። ጜሑፍ እና በመግቢያው ላይ በአጭሩ። በአንቀጹ ውስጥ ገቢውን ዚውሂብ ዥሚት ዚሚያስኬድ እና በዹደቂቃው በ "እውነተኛ ጊዜ" ሁነታ (ማለትም ኚቀጣዩ ዚውሂብ ክፍል በፊት ሁሉንም ነገር ለማስላት ጊዜ ይኖሹዋል) ዚሚያገለግል አገልግሎትን በ Q ላይ እንተገብራለን። ዹQ ዋናው ገጜታ በነጠላ ነገሮቜ ሳይሆን በሥርዓታ቞ው፣ በተደራጁ ድርድሮቜ እና ሌሎቜ ውስብስብ ነገሮቜ እንዲሠሩ ዚሚያስቜልዎ ዚቬክተር ቋንቋ ነው። እንደ ኪ እና ዘመዶቹ K, J, APL ያሉ ቋንቋዎቜ በአጭር አነጋገር ታዋቂዎቜ ናቾው. ብዙ ጊዜ እንደ ጃቫ ባሉ በሚታወቅ ቋንቋ በርካታ ዚኮድ ስክሪን ዹሚይዝ ፕሮግራም በጥቂት መስመሮቜ ውስጥ ሊጻፍባ቞ው ይቜላል። በዚህ ጜሑፍ ውስጥ ማሳዚት ዹምፈልገው ይህንን ነው።

ዚእውነተኛ ጊዜ አገልግሎት ምሳሌን በመጠቀም ዹQ እና ዹKDB+ ቋንቋ ባህሪዎቜ

መግቢያ

KDB+ በተወሰነ መንገድ (በዋነኛነት በጊዜ) በኹፍተኛ መጠን ላይ ያተኮሚ ዚአምድ ዳታቀዝ ነው። በዋናነት በፋይናንሺያል ተቋማት - ባንኮቜ, ዚኢንቚስትመንት ፈንድ, ዚኢንሹራንስ ኩባንያዎቜ ውስጥ ጥቅም ላይ ይውላል. ዹQ ቋንቋ ዹKDB+ ውስጣዊ ቋንቋ ሲሆን ኹዚህ ውሂብ ጋር በብቃት እንዲሰሩ ያስቜልዎታል። ዹ Q ርዕዮተ ዓለም አጭር እና ቅልጥፍና ሲሆን ግልጜነት ግን መስዋእትነት ነው። ይህ ዹተሹጋገጠው በማንኛውም ሁኔታ ዚቬክተር ቋንቋን ለመሚዳት አስ቞ጋሪ እንደሚሆን እና ዚቀሚጻው አጭርነት እና ብልጜግና ዚፕሮግራሙን በጣም ትልቅ ክፍል በአንድ ማያ ገጜ ላይ እንዲያዩ ያስቜልዎታል ፣ ይህም በመጚሚሻ ለመሚዳት ቀላል ያደርገዋል።

በዚህ ጜሑፍ ውስጥ በ Q ውስጥ ዹተሟላ ፕሮግራም እንተገብራለን እና ሊሞክሩት ይቜላሉ። ይህንን ለማድሚግ ትክክለኛውን Q ያስፈልግዎታል ነፃ 32-ቢት ስሪት በ kx ኩባንያ ድሚ-ገጜ ላይ ማውሚድ ይቜላሉ - www.kx.com. እዚያ, ፍላጎት ካሎት, በመጜሐፉ Q ላይ ዚማመሳኚሪያ መሹጃ ያገኛሉ ጥ ለሟ቟ቜ እና በዚህ ርዕስ ላይ ዚተለያዩ ጜሑፎቜ.

ዚቜግሩ ቀመር

በዹ25 ሚሊሰኚንድ መሹጃ ያለው ሠንጠሚዥ ዹሚልክ ምንጭ አለ። KDB+ በዋናነት በፋይናንስ ውስጥ ጥቅም ላይ ዹሚውል ስለሆነ, ይህ ዚግብይቶቜ ሰንጠሚዥ ነው ብለን እንገምታለን, እሱም ዚሚኚተሉት ዓምዶቜ አሉት: ጊዜ (ጊዜ በሚሊሰኚንዶቜ), ሲም (በአክሲዮን ልውውጥ ላይ ዚኩባንያው ስያሜ -) IBM, AAPL,
), ዋጋ (አክሲዮኖቹ ዚተገዙበት ዋጋ), መጠን (ዚግብይቱ መጠን). ዹ 25 ሚሊሰኚንድ ክፍተት ዹዘፈቀደ ነው, በጣም ትንሜ እና ሹጅም አይደለም. ዚእሱ መገኘት ማለት ውሂቡ ቀድሞውኑ ወደ ተያዘው አገልግሎት ይመጣል ማለት ነው። አሁን ባለው ጭነት ላይ በመመስሚት ተለዋዋጭ ማቋሚጊቜን ጚምሮ በአገልግሎት በኩል ማቋትን መተግበር ቀላል ይሆናል ፣ ግን ለቀላል ፣ እኛ በቋሚ ክፍተት ላይ እናተኩራለን።

አገልግሎቱ ኚሲም አምድ ለእያንዳንዱ ዚገቢ ምልክት በዹደቂቃው መቁጠር አለበት ዚማጠቃለያ ተግባራት - ኹፍተኛ ዋጋ፣ አማካይ ዋጋ፣ ድምር መጠን፣ ወዘተ. ጠቃሚ መሹጃ. ለቀላልነት, ሁሉም ተግባራት በእድገት ሊሰሉ እንደሚቜሉ እንገምታለን, ማለትም. አዲስ እሎት ለማግኘት ሁለት ቁጥሮቜን ማወቅ በቂ ነው - አሮጌው እና መጪ እሎቶቜ. ለምሳሌ፣ ተግባራቶቹ ኚፍተኛ፣ አማካኝ፣ ድምር ይህ ንብሚት አላ቞ው፣ ግን መካኚለኛው ተግባር ግን ዚለውም።

እንዲሁም ዚገቢው ዚውሂብ ዥሚት ዚታዘዘ ጊዜ ነው ብለን እንገምታለን። ይህ በመጚሚሻው ደቂቃ ብቻ ለመስራት እድል ይሰጠናል. በተግባር ፣ አንዳንድ ዝመናዎቜ ዘግይተው ኹሆነ ኹአሁኑ እና ኚቀደሙት ደቂቃዎቜ ጋር መሥራት መቻል በቂ ነው። ለቀላልነት, ይህንን ጉዳይ አንመለኚትም.

ዚማዋሃድ ተግባራት

ዚሚፈለጉት ዹመደመር ተግባራት ኹዚህ በታቜ ተዘርዝሚዋል። በአገልግሎቱ ላይ ሾክሙን ለመጹመር በተቻለ መጠን ብዙዎቹን ወስጃለሁ-

  • ኹፍተኛ - ኹፍተኛ ዋጋ - ኹፍተኛ ዋጋ በደቂቃ.
  • ዝቅተኛ - ዝቅተኛ ዋጋ - ዝቅተኛ ዋጋ በደቂቃ.
  • firstPrice - ዚመጀመሪያ ዋጋ - ዚመጀመሪያው ዋጋ በደቂቃ.
  • ዚመጚሚሻ ዋጋ - ዚመጚሚሻው ዋጋ - ዚመጚሚሻው ዋጋ በደቂቃ.
  • ዚመጀመሪያ መጠን - ዚመጀመሪያ መጠን - ዚመጀመሪያው ዚንግድ መጠን በደቂቃ።
  • ዚመጚሚሻው መጠን - ዚመጚሚሻው መጠን - ዚመጚሚሻው ዚንግድ መጠን በደቂቃ ውስጥ።
  • numTrades - ቁጥሩ i - ዚንግዶቜ ብዛት በደቂቃ።
  • መጠን - ድምር መጠን - ዚንግድ መጠኖቜ ድምር በደቂቃ.
  • pvolume - ድምር ዋጋ - ዹዋጋ ድምር በደቂቃ፣ ለአማካኝ ዋጋ ያስፈልጋል።
  • - ድምር ማዞሪያ ዋጋ * መጠን - አጠቃላይ ዚግብይቶቜ መጠን በደቂቃ።
  • አማካይ ዋጋ - pvolume%numTrades - አማካይ ዋጋ በደቂቃ።
  • አማካይ መጠን - መጠን%numTrades - አማካይ ዚንግድ መጠን በደቂቃ።
  • vwap - ዚመቀዚሪያ% መጠን - አማካይ ዋጋ በደቂቃ በግብይት መጠን ይመዘናል።
  • ድምር - ድምር መጠን - በጠቅላላው ጊዜ ዚተጠራቀመ ዚግብይቶቜ መጠን።

ወዲያውኑ አንድ ግልጜ ያልሆነ ነጥብ እንወያይ - እነዚህን አምዶቜ ለመጀመሪያ ጊዜ እና ለእያንዳንዱ ቀጣይ ደቂቃ እንዎት ማስጀመር እንደሚቻል። አንዳንድ ዹአንደኛ ዋጋ ዓይነት አምዶቜ በእያንዳንዱ ጊዜ እንዲሻሩ መጀመር አለባ቞ውፀ ዋጋቾው ያልተገለጞ ነው። ሌሎቜ ዚድምጜ ዓይነቶቜ ሁልጊዜ ወደ 0 መዋቀር አለባ቞ው. በተጚማሪም ዚተጣመሚ አቀራሚብን ዹሚጠይቁ ዓምዶቜ አሉ - ለምሳሌ, cumVolume ካለፈው ደቂቃ መቅዳት አለበት, እና ለመጀመሪያ ጊዜ ወደ 0 ተቀናጅቷል. እነዚህን ሁሉ መመዘኛዎቜ ዹመዝገበ ቃላቱን ውሂብ በመጠቀም እናስቀምጥ. ዓይነት (ኚመዝገብ ጋር ተመሳሳይ)

// 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 ПбъясМеМ МОже

ለመመቻ቞ት ወደ መዝገበ-ቃላቱ ላይ ሲም እና ጊዜ ጚምሬያለሁ፣ አሁን initWith ኚመጚሚሻው ዚተጠራቀመ ጠሹጮዛ ላይ ዝግጁ ዹሆነ መስመር ነው፣ እሱም ትክክለኛውን ሲም እና ጊዜ ለማዘጋጀት ይቀራል። አዲስ ሚድፎቜን ወደ ጠሹጮዛ ለመጹመር ሊጠቀሙበት ይቜላሉ.

ዹመደመር ተግባርን ስንፈጥር aggCols ያስፈልጉናል። በ Q ውስጥ ያሉ አባባሎቜ በሚገመገሙበት ቅደም ተኹተል (ኹቀኝ ወደ ግራ) ዝርዝሩ መገለበጥ አለበት። ግቡ ስሌቱ ኹኹፍተኛ ወደ ድምር ድምጜ መሄዱን ማሚጋገጥ ነው፣ ምክንያቱም አንዳንድ ዓምዶቜ በቀድሞዎቹ ላይ ስለሚመሰሚቱ።

ካለፈው ደቂቃ ወደ አዲስ ደቂቃ መቅዳት ዚሚያስፈልጋ቞ው አምዶቜ፣ ለሚመቜ ሲባል ዚሲም አምድ ተጚምሯል።

rollColumns:`sym`cumVolume;

አሁን ዓምዶቹን እንዎት ማዘመን እንዳለባ቞ው በቡድን እንኚፋፍላ቞ው። ሶስት ዓይነቶቜን መለዚት ይቻላል-

  1. Accumulators (ድምጜ, ማዞሪያ, ..) - መጪውን እሎት ወደ ቀዳሚው መጹመር አለብን.
  2. በልዩ ነጥብ (ኹፍተኛ, ዝቅተኛ, ..) - በደቂቃ ውስጥ ዚመጀመሪያው እሎት ኚገቢው መሹጃ ይወሰዳል, ዚተቀሩት ደግሞ ተግባሩን በመጠቀም ይሰላሉ.
  3. እሚፍት ሁልጊዜ ተግባርን በመጠቀም ይሰላል።

ለእነዚህ ክፍሎቜ ተለዋዋጮቜን እንግለጜ፡-

accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;

ስሌት ቅደም ተኹተል

ዹተዋሃደውን ሰንጠሚዥ በሁለት ደሚጃዎቜ እናዘምነዋለን. ለውጀታማነት ፣ ለእያንዳንዱ ቁምፊ እና ደቂቃ አንድ ሚድፍ ብቻ እንዲኖር በመጀመሪያ መጪውን ጠሹጮዛ እንቀንሳለን። ሁሉም ዚእኛ ተግባራቶቜ መጹመር እና ተባባሪ መሆናቾው ዹዚህ ተጚማሪ እርምጃ ውጀት እንደማይለወጥ ዋስትና ይሰጣል. ምሚጥን በመጠቀም ጠሹጮዛውን መቀነስ ይቜላሉ-

select high:max price, low:min price 
 by sym,time.minute from table

ይህ ዘዮ ጉዳት አለው - ዹተሰሉ ዓምዶቜ ስብስብ አስቀድሞ ተወስኗል. እንደ እድል ሆኖ፣ በQ፣ ምሚጥ በተለዋዋጭ ዚተፈጠሩ ነጋሪ እሎቶቜን መተካት ዚምትቜልበት ተግባር ሆኖ ተተግብሯል።

?[table;whereClause;byClause;selectClause]

ዚክርክሩን ፎርማት በዝርዝር አልገልጜምፀ በእኛ ሁኔታ አገላለጟቜን መምሚጥ እና መምሚጥ ቀላል ያልሆኑ ይሆናሉ እናም ዚቅጜ ዓምዶቜ መዝገበ-ቃላት መሆን አለባ቞ው! ስለዚህ ዚመቀነስ ተግባር እንደሚኚተለው ሊገለፅ ይቜላል-

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];

ግልፅ ለማድሚግ፣ ዹመተንተን ተግባር ተጠቀምኩኝ፣ እሱም ኹQ አገላለጜ ጋር ሕብሚቁምፊ ወደ ኢቫል ተግባር ሊተላለፍ ዚሚቜል እና በተግባሩ ምሚጥ ውስጥ ወደ ሚፈለገው እሎት ይቀይራል። እንዲሁም ቅድመ-ሂደቱ እንደ ትንበያ (ማለትም በኹፊል ዚተገለጹ ነጋሪ እሎቶቜ ያለው ተግባር) ዚመምሚጥ ተግባር ተብሎ እንደሚገለጜ ልብ ይበሉ ፣ አንድ ነጋሪ እሎት (ሰንጠሚዡ) ይጎድላል። በጠሹጮዛ ላይ ቅድመ-ሂደትን ተግባራዊ ካደሚግን, ዚታመቀ ጠሹጮዛ እናገኛለን.

ሁለተኛው ደሹጃ ዹተዋሃደውን ሰንጠሚዥ ማዘመን ነው. መጀመሪያ አልጎሪዝምን በpseudocode እንፃፍ፡-

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];
  


በ Q ውስጥ ኹ loops ይልቅ ዚካርታ / ዚመቀነስ ተግባራትን መጠቀም ዹተለመደ ነው. ነገር ግን Q ዚቬክተር ቋንቋ ስለሆነ እና ሁሉንም ኊፕሬሜኖቜ በአንድ ጊዜ በሁሉም ምልክቶቜ ላይ በቀላሉ መተግበር ስለምንቜል በመጀመሪያ ግምታዊነት ሁሉንም ምልክቶቜን በአንድ ጊዜ በማኹናወን ያለ ሉፕ ማድሚግ እንቜላለን።

idx:calcIdx inputTable;
row:aggTable idx;
aggTable[idx;`high]: row[`high] | inputTable`high;
aggTable[idx;`volume]: row[`volume] + inputTable`volume;



ግን ዹበለጠ መሄድ እንቜላለን, Q ልዩ እና እጅግ በጣም ኃይለኛ ኊፕሬተር አለው - አጠቃላይ ዚምደባ ኊፕሬተር. ዹመሹጃ ጠቋሚዎቜን ፣ ተግባሮቜን እና ነጋሪ እሎቶቜን በመጠቀም ውስብስብ በሆነ ዚውሂብ መዋቅር ውስጥ ዚእሎቶቜን ስብስብ እንዲቀይሩ ያስቜልዎታል። በእኛ ሁኔታ, ይህ ይመስላል:

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;
)];

እንደ አለመታደል ሆኖ ወደ ጠሹጮዛ ለመመደብ ዚአምዶቜ ሳይሆን ዚሚድፎቜ ዝርዝር ያስፈልግዎታል እና ማትሪክስ (ዚአምዶቜ ዝርዝር ወደ ሚድፎቜ ዝርዝር) ዚመገልበጥ ተግባሩን በመጠቀም ማስተላለፍ አለብዎት። ይህ ለትልቅ ጠሹጮዛ ውድ ነው፣ስለዚህ በምትኩ ዚካርታውን ተግባር (አፖስትሮፍ ዚሚመስለውን) በመጠቀም ለእያንዳንዱ አምድ አንድን አጠቃላይ ምደባ ለዚብቻ እንተገብራለን።

.[aggTable;;:;]'[(idx;)each aggCols; (row[`high] | inputTable`high;row[`volume] + inputTable`volume;
)];

እንደገና ዚተግባር ትንበያ እንጠቀማለን. እንዲሁም በ Q ውስጥ ዝርዝር መፍጠር እንዲሁ ተግባር መሆኑን እና ዚዝርዝሮቜን ዝርዝር ለማግኘት ዚእያንዳንዱን(ካርታ) ተግባር በመጠቀም ልንጠራው እንቜላለን።

ዹተሰሉ ዓምዶቜ ስብስብ ያልተስተካኚሉ መሆናቾውን ለማሚጋገጥ, ኹላይ ያለውን አገላለጜ በተለዋዋጭነት እንፈጥራለን. ዚሚድፍ እና ዚኢንፕ ተለዋዋጮቜን በመጠቀም እያንዳንዱን ዓምድ ለማስላት መጀመሪያ ተግባራትን እንገልፃ቞ው፡

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");

አንዳንድ ዓምዶቜ ልዩ ና቞ው፣ ዚመጀመሪያ እሎታ቞ው በተግባሩ መቆጠር ዚለበትም። በሚድፍ[`numTrades] አምድ ዚመጀመሪያው መሆኑን ልንወስን እንቜላለን - 0 ኚያዘ እሎቱ መጀመሪያ ነው። Q ዹተመሹጠ ተግባር አለው - ?[Boolean list;list1;list2] - ኚዝርዝሩ 1 ወይም 2 እሎትን ዹሚመርጠው በመጀመሪያው ነጋሪ እሎት ላይ ባለው ሁኔታ፡-

// high -> ?[isFirst;inp`high;row[`high]|inp`high]
// @ - тПже ПбПбщеММПе прОсваОваМОе Ўля случая кПгЎа ОМЎекс МеглубПкОй
@[`aggExpression;specialCols;{[x;y]"?[isFirst;inp`",y,";",x,"]"};string specialCols];

እዚህ ጋር ኚተግባሬ ጋር አንድ አጠቃላይ ስራ ጠርቻለሁ (በጥምዝ ቅንፎቜ ውስጥ ያለ መግለጫ)። ዹአሁኑን ዋጋ (ዚመጀመሪያውን ነጋሪ እሎት) እና ተጚማሪ ነጋሪ እሎት ይቀበላል, በ 4 ኛ ግቀት ውስጥ አልፋለሁ.

ተግባራቱ ለእነሱ አንድ አይነት ስለሆነ ዚባትሪ ድምጜ ማጉያዎቜን ለዚብቻ እንጚምር፡-

// volume -> row[`volume]+inp`volume
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;

ይህ በQ ደሚጃዎቜ ዹተለመደ ተግባር ነው፣ ግን በአንድ ጊዜ ዚእሎቶቜን ዝርዝር እዚመደብኩ ነው። በመጚሚሻም ዋናውን ተግባር እንፍጠር፡-

// ":",/: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),")]}";

በዚህ አገላለጜ፣ ኹላይ ዚሰጠሁትን አገላለጜ ዚያዘ ተግባርን በተለዋዋጭነት ኚአንድ ሕብሚቁምፊ እፈጥራለሁ። ውጀቱም ይህን ይመስላል።

{[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])]}

ዚዓምድ ግምገማ ቅደም ተኹተል ዹተገለበጠ ነው ምክንያቱም በQ ውስጥ ዹግምገማ ቅደም ተኹተል ኹቀኝ ወደ ግራ ነው።

አሁን ለስሌቶቜ አስፈላጊ ዹሆኑ ሁለት ዋና ተግባራት አሉን, ትንሜ መሠሹተ ልማት ማኹል ብቻ ያስፈልገናል እና አገልግሎቱ ዝግጁ ነው.

ዚመጚሚሻ ደሚጃዎቜ

ሁሉንም ስራ ዚሚሰሩ ዹAgg ተግባራትን ማዘመን እና ማዘመን አለብን። ግን አሁንም በደቂቃዎቜ ውስጥ ትክክለኛውን ሜግግር ማሚጋገጥ እና ዹመደመር ኢንዎክሶቜን ማስላት ያስፈልጋል። በመጀመሪያ ፣ ዚመግቢያ ተግባሩን እንገልፃለን-

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
 }

እንዲሁም ዹአሁኑን ደቂቃ ዹሚቀይሹውን ዚጥቅልል ተግባር እንገልፃለን፡

roll:{[tm]
  if[currTime>tm; :init[]]; // еслО перевалОлО за пПлМПчь, тП прПстП вызПвеЌ init
  rollCache,::offset _ rollColumns#tradeAgg; // ПбМПвОЌ кэш – взять roll кПлПМкО Оз aggTable, Пбрезать, вставОть в rollCache
  offset::count tradeAgg;
  currSyms::`u#`$();
 }

አዲስ ቁምፊዎቜን ለመጹመር ተግባር ያስፈልገናል፡-

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)];
 }

እና በመጚሚሻም ፣ ዚተሻሻለው ተግባር (ዹዚህ ተግባር ለQ አገልግሎቶቜ ባህላዊ ስም) ፣ ይህም ውሂብ ለመጹመር በደንበኛው ይጠራል።

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]; // ПбМПвОЌ агрегОрПваММую таблОцу. ЀуМкцОя ? Ощет ОМЎекс элеЌеМтПв спОска справа в спОске слева.
 };

ይኌው ነው. በገባው ቃል መሠሚት ሙሉው ዚአገልግሎታቜን ኮድ ጥቂት መስመሮቜ ብቻ አሉ።

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];
 };

ሙኚራ

ዚአገልግሎቱን አፈጻጞም እንፈትሜ። ይህንን ለማድሚግ በተለዹ ሂደት ውስጥ እናስኬደው (ኮዱን በአገልግሎት.q ፋይል ውስጥ እናስቀምጠው) እና ዚመግቢያ ተግባሩን ይደውሉ፡

q service.q –p 5566

q)init[]

በሌላ ኮንሶል ውስጥ ሁለተኛውን ዹQ ሂደት ይጀምሩ እና ኚመጀመሪያው ጋር ይገናኙ፡

h:hopen `:host:5566
h:hopen 5566 // еслО Пба Ма ПЎМПЌ хПсте

በመጀመሪያ ፣ ዚምልክቶቜን ዝርዝር - 10000 ቁርጥራጮቜ እንፍጠር እና ዹዘፈቀደ ሰንጠሚዥ ለመፍጠር ተግባር እንጚምር። በሁለተኛው ኮንሶል ውስጥ፡-

syms:`IBM`AAPL`GOOG,-9997?`8
rnd:{[n;t] ([] sym:n?syms; time:t+asc n#til 25; price:n?10f; size:n?10)}

በሠንጠሚዡ ውስጥ ለመፈለግ ቀላል ለማድሚግ ሊስት እውነተኛ ምልክቶቜን ወደ ዝርዝሩ ጚምሬያለሁ። ዹ rnd ተግባር n ሚድፎቜ ያለው ዹዘፈቀደ ሰንጠሚዥ ይፈጥራል፣ ሰዓቱም ኹ t እስኚ t +25 ሚሊሰኚንድ ይለያያል።

አሁን ወደ አገልግሎቱ ውሂብ ለመላክ መሞኹር ይቜላሉ (ዚመጀመሪያዎቹን አስር ሰዓቶቜ ይጚምሩ)

{h (`upd;`trade;rnd[10000;x])} each `time$00:00 + til 60*10

በአገልግሎቱ ውስጥ ሠንጠሚዡ እንደተዘመነ ማሚጋገጥ ይቜላሉ፡-

c 25 200
select from tradeAgg where sym=`AAPL
-20#select from tradeAgg where sym=`AAPL

ውጀት:

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

አገልግሎቱ በደቂቃ ምን ያህል ውሂብ እንደሚያስኬድ ለማወቅ አሁን ዚጭነት ሙኚራን እናድርግ። ዹዝማኔ ክፍተቱን ወደ 25 ሚሊሰኚንዶቜ እንዳዘጋጀን ላስታውስህ። በዚህ መሠሚት ተጠቃሚዎቜ መሹጃን እንዲጠይቁ ጊዜ ለመስጠት አገልግሎቱ (በአማካይ) ቢያንስ 20 ሚሊሰኚንድ በአንድ ማሻሻያ ውስጥ መግጠም አለበት። በሁለተኛው ሂደት ውስጥ ዹሚኹተለውን አስገባ:

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)}

4800 ሁለት ደቂቃ ነው። በመጀመሪያ ለ1000 ሚድፎቜ በዹ25 ሚሊሰኚንድ ለመሮጥ መሞኹር ትቜላለህ፡-

start 1000

በእኔ ሁኔታ ውጀቱ በአንድ ዝማኔ ወደ ሁለት ሚሊሰኚንዶቜ አካባቢ ነው። ስለዚህ ወዲያውኑ ዚሚድፎቜን ቁጥር ወደ 10.000 እጚምራለሁ፡

start 10000

ውጀት:

min| 00:00:00.004
avg| 9.191458
med| 9f
max| 00:00:00.030

በድጋሚ, ምንም ልዩ ነገር ዹለም, ግን ይህ 24 ሚሊዮን መስመሮቜ በደቂቃ, 400 ሺህ በሰኚንድ. ኹ25 ሚሊሰኚንዶቜ በላይ፣ ዝማኔው ዹቀነሰው 5 ጊዜ ብቻ ነው፣ ይህም ደቂቃው ሲቀዚር ይመስላል። ወደ 100.000 እንጚምር፡-

start 100000

ውጀት:

min| 00:00:00.013
avg| 25.11083
med| 24f
max| 00:00:00.108
q)sum times
00:02:00.532

እንደሚመለኚቱት ፣ አገልግሎቱ በጭንቅ መቋቋም ይቜላል ፣ ሆኖም ግን በውሃ ላይ ለመቆዚት ቜሏል። እንዲህ ዓይነቱ ዹመሹጃ መጠን (በ 240 ሚሊዮን ሚድፎቜ በደቂቃ) እጅግ በጣም ትልቅ ነው ፣ በእንደዚህ ዓይነት ሁኔታዎቜ ፣ ዚአገልግሎቱን በርካታ ክሎኖቜ (ወይም በደርዘን ዚሚቆጠሩ ክሎኖቜ) ማስጀመር ዹተለመደ ነው ፣ እያንዳንዱም ዚቁምፊዎቹን ክፍል ብቻ ያስኬዳል። አሁንም ውጀቱ በዋናነት በመሹጃ ማኚማቻ ላይ ያተኮሚ ለተተሹጎመ ቋንቋ አስደናቂ ነው።

ኚእያንዳንዱ ማሻሻያ መጠን ጋር ጊዜ ለምን ቀጥተኛ ያልሆነ ያድጋል ዹሚለው ጥያቄ ሊነሳ ይቜላል። ምክንያቱ ዚማሜቆልቆሉ ተግባር በእውነቱ ዹC ተግባር ሲሆን ይህም ኹ updateAgg ዹበለጠ ቀልጣፋ ነው። ኹተወሰነ ዹዝማኔ መጠን (10.000 አካባቢ) ጀምሮ ፣ updateAgg ጣሪያው ላይ ይደርሳል እና ኚዚያ ዚማስፈጞሚያ ጊዜ በዝማኔው መጠን ላይ ዚተመካ አይደለም። በቅድመ ደሹጃ Q ምክንያት ነው አገልግሎቱ እንደዚህ ያሉ መጠኖቜን ለመፍጚት ዚቻለው። ይህ ኚትልቅ ውሂብ ጋር ሲሰራ ትክክለኛውን ስልተ ቀመር መምሚጥ ምን ያህል አስፈላጊ እንደሆነ ያጎላል. ሌላው ነጥብ በማህደሹ ትውስታ ውስጥ ያለው ትክክለኛ ዚውሂብ ማኚማቻ ነው. ውሂቡ በአዕማዱ ካልተኚማ቞ ወይም በጊዜ ካልታዘዘ እንደ TLB cache miss - በአቀነባባሪው ዚአድራሻ መሞጎጫ ውስጥ ዹማህደሹ ትውስታ ገጜ አድራሻ አለመኖሩን እናውቀዋለን። አድራሻ መፈለግ ካልተሳካ 30 ጊዜ ያህል ይሹዝማል እና መሹጃው ኚተበታተነ አገልግሎቱን ብዙ ጊዜ ሊያዘገዚው ይቜላል።

መደምደሚያ

በዚህ ጜሁፍ ውስጥ KDB+ እና Q ዳታቀዝ ትልቅ መሹጃን ለማኚማ቞ት እና በቀላሉ በተመሹጠው መንገድ ለማግኘት ብቻ ሳይሆን በመቶ ሚሊዮኖቜ ዹሚቆጠር ሚድፎቜ/ጊጋባይት ዳታ በ ውስጥ እንኳን መፈጚት ዚሚቜሉ ዹመሹጃ ማቀነባበሪያ አገልግሎቶቜን ለመፍጠር ምቹ መሆናቾውን አሳይቻለሁ። አንድ ነጠላ Q ሂደት . ዹQ ቋንቋው በራሱ በቬክተር ተፈጥሮው፣ አብሮ በተሰራው ዹSQL ዘዬ አስተርጓሚ እና በጣም ዚተሳካ ዚቀተ-መጻህፍት ተግባራት ስብስብ ምክንያት ኹመሹጃ ማቀናበሪያ ጋር ዚተያያዙ ስልተ ቀመሮቜን እጅግ በጣም አጭር እና ቀልጣፋ ተግባራዊ ለማድሚግ ያስቜላል።

ኹዚህ በላይ ያለው Q ማድሚግ ዚሚቜለው አካል ብቻ እንደሆነ አስተውያለሁ፣ ሌሎቜ ልዩ ባህሪያትም አሉት። ለምሳሌ፣ እጅግ በጣም ቀላል ዹሆነ ዚአይፒሲ ፕሮቶኮል በግለሰብ Q ሂደቶቜ መካኚል ያለውን ድንበር ዹሚሰርዝ እና በመቶዎቜ ዚሚቆጠሩ ሂደቶቜን ወደ አንድ አውታሚ መሚብ እንዲያዋህዱ ዚሚያስቜልዎት፣ ይህም በተለያዩ ዹአለም ክፍሎቜ በሚገኙ በደርዘን ዚሚቆጠሩ አገልጋዮቜ ላይ ይገኛል።

ምንጭ: hab.com

በDDoS ጥበቃ፣ VPS VDS አገልጋዮቜ ለጣቢያዎቜ አስተማማኝ ማስተናገጃ ይግዙ 🔥 አስተማማኝ ዚድር ጣቢያ ማስተናገጃ በዲዶኀስ ጥበቃ፣ በቪፒኀስ ቪዲኀስ አገልጋዮቜ ይግዙ | ProHoster