KDB+ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ฌด์์ธ์ง, Q ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๊ฐ ๋ฌด์์ธ์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ค์ ๊ฐ์ ๊ณผ ์ฝ์ ์ด ๋ฌด์์ธ์ง์ ๋ํด์๋ ์ด์ ๊ธฐ์ฌ์์ ์ฝ์ ์ ์์ต๋๋ค. ์๋ก ์์ ๊ฐ๋ตํ๊ฒ ์ค๋ช ํ๊ฒ ์ต๋๋ค. ์ด ๊ธ์์๋ Q์์ ์์ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๊ณ ๋ค์ํ ์ง๊ณ ํจ์๋ฅผ "์ค์๊ฐ" ๋ชจ๋๋ก ๋งค๋ถ ๊ณ์ฐํ๋ ์๋น์ค๋ฅผ ๊ตฌํํฉ๋๋ค(์ฆ, ๋ค์ ๋ฐ์ดํฐ ๋ถ๋ถ์ ๊ณ์ฐํ๊ธฐ ์ ์ ๋ชจ๋ ๊ฒ์ ๊ณ์ฐํ ์๊ฐ์ ํ๋ณดํฉ๋๋ค). Q์ ์ฃผ์ ํน์ง์ ๋จ์ผ ๊ฐ์ฒด๊ฐ ์๋ ๋ฐฐ์ด, ๋ฐฐ์ด์ ๋ฐฐ์ด, ๊ธฐํ ๋ณต์กํ ๊ฐ์ฒด๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๋ฒกํฐ ์ธ์ด๋ผ๋ ๊ฒ์ ๋๋ค. Q์ ๊ด๋ จ ์ธ์ด์ธ K, J, APL์ ๊ฐ๊ฒฐํจ์ผ๋ก ์ ๋ช ํฉ๋๋ค. Java์ ๊ฐ์ ์ต์ํ ์ธ์ด๋ก ์ฌ๋ฌ ํ๋ฉด ๋ถ๋์ ์ฝ๋๋ฅผ ์ฐจ์งํ๋ ํ๋ก๊ทธ๋จ๋ ๋ช ์ค๋ก ์์ฑํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ด ๊ธ์์ ๋ฐ๋ก ์ด๋ฌํ ์ ์ ๋ณด์ฌ๋๋ฆฌ๊ณ ์ ํฉ๋๋ค.

์๊ฐ
KDB+๋ ํน์ ๋ฐฉ์(์ฃผ๋ก ์๊ฐ ๊ธฐ์ค)์ผ๋ก ์ ๋ ฌ๋ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ํด ์ค๊ณ๋ ์ปฌ๋ผํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๋ค. ์ฃผ๋ก ์ํ, ํฌ์ ํ๋, ๋ณดํ ํ์ฌ ๋ฑ ๊ธ์ต ๊ธฐ๊ด์์ ์ฌ์ฉ๋ฉ๋๋ค. Q ์ธ์ด๋ KDB+์ ๋ด๋ถ ์ธ์ด๋ก, ์ด ๋ฐ์ดํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๋ค๋ฃฐ ์ ์๋๋ก ํด์ค๋๋ค. Q ์ธ์ด์ ํต์ฌ์ ๊ฐ๊ฒฐ์ฑ๊ณผ ํจ์จ์ฑ์ ์ค์ํ๋ ๋ฐ๋ฉด, ๋ช ํ์ฑ์ ํฌ์๋ฉ๋๋ค. ๋ฒกํฐ ์ธ์ด๋ ์ด๋ค ๊ฒฝ์ฐ์๋ ์ธ์งํ๊ธฐ ์ด๋ ต๋ค๋ ์ฌ์ค๊ณผ, ๋ ์ฝ๋์ ๊ฐ๊ฒฐ์ฑ๊ณผ ํ๋ถํจ ๋๋ถ์ ํ๋ก๊ทธ๋จ์ ํจ์ฌ ๋ ๋ง์ ๋ถ๋ถ์ ํ ํ๋ฉด์์ ๋ณผ ์ ์์ด ๊ถ๊ทน์ ์ผ๋ก ์ดํดํ๊ธฐ๊ฐ ๋ ์ฝ๋ค๋ ์ฌ์ค์์ ๊ทธ ์ด์ ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
์ด ๊ธ์์๋ Q๋ก ์์ ํ ํ๋ก๊ทธ๋จ์ ๊ตฌํํด ๋ณด๊ฒ ์ต๋๋ค. ์ง์ ์ฒดํํด ๋ณด์๋ ๊ฒ๋ ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๋ฅผ ์ํด์๋ Q ์์ฒด๊ฐ ํ์ํฉ๋๋ค. kx ํ์ฌ ์น์ฌ์ดํธ์์ ๋ฌด๋ฃ 32๋นํธ ๋ฒ์ ์ ๋ค์ด๋ก๋ํ ์ ์์ต๋๋ค. . ๊ด์ฌ์ด ์์ผ์๋ค๋ฉด Q๋ผ๋ ์ฑ ์ ๋ํ ์ฐธ๊ณ ์ ๋ณด๋ ์ฐพ์ผ์ค ์ ์์ต๋๋ค. ์ด ์ฃผ์ ์ ๋ํ ๋ค์ํ ๊ธฐ์ฌ๊ฐ ์์ต๋๋ค.
๋ฌธ์ ์ฑ๋ช
25๋ฐ๋ฆฌ์ด๋ง๋ค ๋ฐ์ดํฐ ํ ์ด๋ธ์ ์ ์กํ๋ ์์ค๊ฐ ์์ต๋๋ค. KDB+๋ ์ฃผ๋ก ๊ธ์ต ๋ถ์ผ์์ ์ฌ์ฉ๋๋ฏ๋ก, ์ด ํ ์ด๋ธ์ ๊ฑฐ๋ ํ ์ด๋ธ์ด๋ผ๊ณ ๊ฐ์ ํ๊ฒ ์ต๋๋ค. ์ด ํ ์ด๋ธ์ ์ด์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. time(๋ฐ๋ฆฌ์ด ๋จ์ ์๊ฐ), sym(์ฆ๊ถ ๊ฑฐ๋์์ ํ์ฌ ์ข ๋ชฉ) IBM, AAPL,โฆ), ๊ฐ๊ฒฉ(์ฃผ์ ๋งค์ ๊ฐ๊ฒฉ), ํฌ๊ธฐ(๊ฑฐ๋ ๊ท๋ชจ). 25๋ฐ๋ฆฌ์ด ๊ฐ๊ฒฉ์ ์์๋ก ์ ํ๋์์ผ๋ฉฐ, ๋๋ฌด ์์ง๋ ํฌ์ง๋ ์์ต๋๋ค. ์ด ๊ฐ๊ฒฉ์ ๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ ๋ฒํผ๋ง๋ ์ํ๋ก ์๋น์ค์ ๋์ฐฉํจ์ ์๋ฏธํฉ๋๋ค. ํ์ฌ ๋ถํ์ ๋ฐ๋ผ ๋์ ๋ฒํผ๋ง์ ํฌํจํ์ฌ ์๋น์ค ์ธก์์ ๋ฒํผ๋ง์ ๊ตฌํํ๋ ๊ฒ์ ์ฝ์ง๋ง, ๋จ์ํ๋ฅผ ์ํด ๊ณ ์ ๋ ๊ฐ๊ฒฉ์ผ๋ก ์ค๋จํ๊ฒ ์ต๋๋ค.
์๋น์ค๋ sym ์ด์์ ๋ค์ด์ค๋ ๊ฐ ์ฌ๋ณผ์ ๋ํด ๋ถ๋น ์ง๊ณ ํจ์ ์งํฉ(์ต๋ ๊ฐ๊ฒฉ, ํ๊ท ๊ฐ๊ฒฉ, ํฉ๊ณ ํฌ๊ธฐ ๋ฑ)์ ๊ณ์ฐํด์ผ ํฉ๋๋ค. ์ด๋ ์ ์ฉํ ์ ๋ณด์ ๋๋ค. ๋จ์ํ๋ฅผ ์ํด ๋ชจ๋ ํจ์๋ ์ฆ๋ถ์์ผ๋ก ๊ณ์ฐ๋ ์ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ์ฆ, ์ ๊ฐ์ ์ป์ผ๋ ค๋ฉด ์ด์ ๊ฐ๊ณผ ๋ค์ด์ค๋ ๊ฐ, ๋ ๊ฐ์ ์ซ์๋ง ์๋ฉด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ต๋๊ฐ, ํ๊ท ๊ฐ, ํฉ๊ณ ํจ์๋ ์ด๋ฌํ ์์ฑ์ ๊ฐ์ง๋ง, ์ค๊ฐ๊ฐ ํจ์๋ ์ด๋ฌํ ์์ฑ์ ๊ฐ์ง ์์ต๋๋ค.
๋ํ ์์ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ด ์๊ฐ์์ผ๋ก ์ ๋ ฌ๋์ด ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ง์ง๋ง ๋ถ๋ง ์ฒ๋ฆฌํ๋ฉด ๋ฉ๋๋ค. ์ค์ ๋ก๋ ์ผ๋ถ ์ ๋ฐ์ดํธ๊ฐ ์ง์ฐ๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ํ์ฌ ๋ถ๊ณผ ์ด์ ๋ถ๋ง ์ฒ๋ฆฌํ๋ฉด ๋ฉ๋๋ค. ํธ์์ ์ด ๊ฒฝ์ฐ๋ ๊ณ ๋ คํ์ง ์๊ฒ ์ต๋๋ค.
์ง๊ณ ํจ์
ํ์ํ ์ง๊ณ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ์๋น์ค ๋ถํ๋ฅผ ๋๋ฆฌ๊ธฐ ์ํด ๊ฐ๋ฅํ ํ ๋ง์ ํจ์๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
- ๋์ โ ์ต๋ ๊ฐ๊ฒฉ โ ๋ถ๋น ์ต๋ ๊ฐ๊ฒฉ.
- ๋ฎ์ โ ์ต์ ๊ฐ๊ฒฉ โ ๋ถ๋น ์ต์ ๊ฐ๊ฒฉ.
- firstPrice โ ์ฒซ ๋ฒ์งธ ๊ฐ๊ฒฉ โ ๋ถ๋น ์ฒซ ๋ฒ์งธ ๊ฐ๊ฒฉ.
- lastPrice โ ๋ง์ง๋ง ๊ฐ๊ฒฉ โ ๋ถ๋น ๋ง์ง๋ง ๊ฐ๊ฒฉ.
- firstSize โ ์ฒซ ๋ฒ์งธ ํฌ๊ธฐ โ ๋ถ๋น ์ฒซ ๋ฒ์งธ ๊ฑฐ๋ ํฌ๊ธฐ.
- lastSize โ ๋ง์ง๋ง ํฌ๊ธฐ โ ๋ถ๋น ๋ง์ง๋ง ๊ฑฐ๋ ํฌ๊ธฐ์ ๋๋ค.
- numTrades โ count i โ ๋ถ๋น ๊ฑฐ๋ ์.
- ๊ฑฐ๋๋ โ ์ด ๊ฑฐ๋ ๊ท๋ชจ โ ๋ถ๋น ๊ฑฐ๋ ๊ท๋ชจ์ ํฉ๊ณ.
- pvolume โ sum price โ ๋ถ๋น ๊ฐ๊ฒฉ์ ํฉ๊ณ, avgPrice์ ํ์ํจ.
- ๊ฑฐ๋์ก โ ๊ฐ๊ฒฉ ํฉ๊ณ * ๊ท๋ชจ โ ๋ถ๋น ์ด ๊ฑฐ๋๋.
- avgPrice โ pvolume%numTrades โ ๋ถ๋น ํ๊ท ๊ฐ๊ฒฉ.
- avgSize โ volume%numTrades โ ๋ถ๋น ํ๊ท ๊ฑฐ๋ ๊ท๋ชจ.
- vwap โ ๊ฑฐ๋๋%๋งค์ถ โ ๊ฑฐ๋ ๊ท๋ชจ์ ๋ฐ๋ผ ๊ฐ์ค์น๋ฅผ ๋ ๋ถ๋น ํ๊ท ๊ฐ๊ฒฉ.
- cumVolume โ ์ด ๊ฑฐ๋๋ โ ๋ชจ๋ ๊ธฐ๊ฐ ๋์ ๋์ ๋ ๊ฑฐ๋๋์ ๋๋ค.
๋ฐ๋ก ๋ช ํํ์ง ์์ ์ ํ๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋ฐ๋ก ์ด๋ฌํ ์ด์ ์ฒ์๊ณผ ์ดํ ๋งค ๋ถ๋ง๋ค ์ด๊ธฐํํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. firstPrice ์ ํ์ ์ผ๋ถ ์ด์ ๋งค๋ฒ null ๊ฐ์ผ๋ก ์ด๊ธฐํํด์ผ ํ๋ฉฐ, ๊ทธ ๊ฐ์ ์ ์๋์ง ์์ต๋๋ค. volume ์ ํ์ ๋ค๋ฅธ ์ด์ ํญ์ 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 ะพะฑัััะฝะตะฝ ะฝะธะถะต
ํธ์๋ฅผ ์ํด ์ฌ์ ์ sym๊ณผ time์ ์ถ๊ฐํ์ต๋๋ค. ์ด์ initWith๋ ์ต์ข ์ง๊ณ ํ ์ด๋ธ์์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ง ์ค์ด๋ฉฐ, ์ฌ๋ฐ๋ฅธ sym๊ณผ time์ ์ค์ ํ๋ ์ญํ ์ ํฉ๋๋ค. ์ด๋ฅผ ์ฌ์ฉํ์ฌ ํ ์ด๋ธ์ ์ ํ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์ง๊ณ ํจ์๋ฅผ ์์ฑํ ๋ aggCols๊ฐ ํ์ํฉ๋๋ค. Q์ ํํ์ ๊ณ์ฐ ์์(์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ)์ ํน์ฑ์ผ๋ก ์ธํด ๋ฆฌ์คํธ๋ฅผ ๋ฐ์ ํด์ผ ํฉ๋๋ค. ์ผ๋ถ ์ด์ด ์ด์ ์ด์ ์ข ์๋๋ฏ๋ก, ๊ณ์ฐ์ด high์์ cumVolume์ผ๋ก ์งํ๋๋๋ก ํ๋ ๊ฒ์ด ๋ชฉํ์ ๋๋ค.
์ด์ ๋ถ์์ ์ ๋ถ์ผ๋ก ๋ณต์ฌํด์ผ ํ๋ ์ด์ ํธ์์ sym ์ด์ด ์ถ๊ฐ๋์์ต๋๋ค.
rollColumns:`sym`cumVolume;
์ด์ ์ ๋ฐ์ดํธ ๋ฐฉ์์ ๋ฐ๋ผ ์ด์ ๊ทธ๋ฃน์ผ๋ก ๋๋ ๋ณด๊ฒ ์ต๋๋ค. ์ธ ๊ฐ์ง ์ ํ์ด ์์ต๋๋ค.
- ๋์ ๊ธฐ(๊ฑฐ๋๋, ๋งค์ถ ๋ฑ) โ ์ ์ ๊ฐ์น๋ฅผ ์ด์ ๊ฐ์น์ ๋ํด์ผ ํฉ๋๋ค.
- ํน์ ์ง์ (๋์, ๋ฎ์, ..)์ ์ฌ์ฉํ๋ฉด ๋ถ์ ์ฒซ ๋ฒ์งธ ๊ฐ์ ๋ค์ด์ค๋ ๋ฐ์ดํฐ์์ ๊ฐ์ ธ์ค๊ณ ๋๋จธ์ง๋ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ์ฐํฉ๋๋ค.
- ๋๋จธ์ง๋ ํญ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ์ฐ๋ฉ๋๋ค.
๋ค์ ํด๋์ค์ ๋ํ ๋ณ์๋ฅผ ์ ์ํด ๋ณด๊ฒ ์ต๋๋ค.
accumulatorCols:`numTrades`volume`pvolume`turnover;
specialCols:`high`low`firstPrice`firstSize;
๊ณ์ฐ ์์
์ง๊ณ ํ ์ด๋ธ์ ๋ ๋จ๊ณ์ ๊ฑธ์ณ ์ ๋ฐ์ดํธํฉ๋๋ค. ํจ์จ์ฑ์ ์ํด ๋จผ์ ์ ๋ ฅ ํ ์ด๋ธ์ ์์ถํ์ฌ ๊ฐ ๊ธฐํธ์ ๋ถ์ ๋ํด ํ๋์ ํ์ด ์๋๋ก ํฉ๋๋ค. ๋ชจ๋ ํจ์๊ฐ ์ฆ๋ถํ์ด๊ณ ์ฐ๊ด ํจ์์ด๋ฏ๋ก ์ด ์ถ๊ฐ ๋จ๊ณ์์ ๊ฒฐ๊ณผ๊ฐ ๋ณ๊ฒฝ๋์ง ์์ต๋๋ค. select๋ฅผ ์ฌ์ฉํ์ฌ ํ ์ด๋ธ์ ์์ถํ ์ ์์ต๋๋ค.
select high:max price, low:min price โฆ by sym,time.minute from table
์ด ๋ฐฉ๋ฒ์๋ ๋จ์ ์ด ์์ต๋๋ค. ๊ณ์ฐ๋ ์ด ์งํฉ์ด ๋ฏธ๋ฆฌ ์ ์๋์ด ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋คํํ Q์์๋ select๊ฐ ๋์ ์ผ๋ก ์์ฑ๋ ์ธ์๋ฅผ ๋์ฒดํ ์ ์๋ ํจ์๋ก๋ ๊ตฌํ๋์ด ์์ต๋๋ค.
?[table;whereClause;byClause;selectClause]
์ธ์์ ํ์์ ๋ํด์๋ ์์ธํ ์ค๋ช ํ์ง ์๊ฒ ์ต๋๋ค. ์ด ๊ฒฝ์ฐ์๋ by์ select ํํ์๋ง ์ค์ํ์ง ์์ผ๋ฉฐ, ์ด ํํ์๋ค์ '์ด!ํํ์' ํํ์ ์ฌ์ ์ด์ด์ผ ํฉ๋๋ค. ๋ฐ๋ผ์ ์์ถ ํจ์๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํ ์ ์์ต๋๋ค.
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];
๋ช ํ์ฑ์ ์ํด, parse ํจ์๋ฅผ ์ฌ์ฉํ์ต๋๋ค. ์ด ํจ์๋ Q ํํ์์ด ํฌํจ๋ ๋ฌธ์์ด์ eval ํจ์์ ์ ๋ฌ๋ ์ ์๋ ๊ฐ์ผ๋ก ๋ณํํ์ฌ select ํจ์์ ํ์ํ ๊ฐ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. ๋ํ, preprocess ํจ์๋ select ํจ์์ ํ๋ก์ ์ (์ฆ, ์ธ์๊ฐ ๋ถ๋ถ์ ์ผ๋ก ์ง์ ๋ ํจ์)์ผ๋ก ์ ์๋์ด ์์ผ๋ฉฐ, ์ธ์ ํ๋(ํ ์ด๋ธ)๊ฐ ๋๋ฝ๋์์ต๋๋ค. ํ ์ด๋ธ์ preprocess ํจ์๋ฅผ ์ ์ฉํ๋ฉด ์์ถ๋ ํ ์ด๋ธ์ด ์์ฑ๋ฉ๋๋ค.
๋ ๋ฒ์งธ ๋จ๊ณ๋ ์ง๊ณ ํ ์ด๋ธ์ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ๋๋ค. ๋จผ์ ์๊ณ ๋ฆฌ์ฆ์ ์์ฌ์ฝ๋๋ก ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
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์์๋ ์ฌ์ดํด ๋์ ๋งต/๋ฆฌ๋์ค ํจ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค. ํ์ง๋ง 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;โฆ)];
์ํ๊น๊ฒ๋ ํ์ ํ ๋นํ๋ ค๋ฉด ์ด์ด ์๋ ํ ๋ชฉ๋ก์ด ํ์ํ๊ณ , flip ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ ฌ์ ์ ์น(์ด ๋ชฉ๋ก์ ํ ๋ชฉ๋ก์ผ๋ก)ํด์ผ ํฉ๋๋ค. ์ด ์์ ์ ํฐ ํ์์๋ ๋น์ฉ์ด ๋ง์ด ๋ค๊ธฐ ๋๋ฌธ์, ๋์ map ํจ์(์ํฌ์คํธ๋กํผ์ฒ๋ผ ๋ณด์ด๋)๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ด์ ๊ฐ๋ณ์ ์ผ๋ก ์ผ๋ฐ ํ ๋น์ ์ ์ฉํฉ๋๋ค.
.[aggTable;;:;]'[(idx;)each aggCols; (row[`high] | inputTable`high;row[`volume] + inputTable`volume;โฆ)];
ํจ์ ํฌ์์ ๋ค์ ์ฌ์ฉํฉ๋๋ค. ๋ํ Q์์ ๋ฆฌ์คํธ๋ฅผ ์์ฑํ๋ ๊ฒ๋ ํจ์์ด๋ฉฐ, each(map)์ ์ฌ์ฉํ์ฌ ๋ฆฌ์คํธ์ ๋ฆฌ์คํธ๋ฅผ ์ป์ ์ ์๋ค๋ ์ ์ ์ ์ํ์ธ์.
๊ณ์ฐ๋ ์ด์ ๊ณ ์ ๋ ์งํฉ์ ํผํ๊ธฐ ์ํด ์ ํํ์์ ๋์ ์ผ๋ก ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค. ๋จผ์ , row ๋ฐ inp ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ์ง๊ณ ๋ฐ ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ ๊ฐ ์ด์ ๊ณ์ฐํ๋ ํจ์๋ฅผ ์ ์ํฉ๋๋ค.
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");
์ผ๋ถ ์ด์ ํน์ํ์ฌ ํจ์์์ ์ฒซ ๋ฒ์งธ ๊ฐ์ ๊ณ์ฐํด์๋ ์ ๋ฉ๋๋ค. ์ด row[`numTrades]๋ฅผ ํตํด ์ฒซ ๋ฒ์งธ ์ด์์ ํ์ธํ ์ ์์ต๋๋ค. ์ด ๊ฐ์ด 0์ด๋ฉด ์ฒซ ๋ฒ์งธ ๊ฐ์ ๋๋ค. Q์๋ ์ฒซ ๋ฒ์งธ ์ธ์์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ชฉ๋ก 1 ๋๋ ๋ชฉ๋ก 2์์ ๊ฐ์ ์ ํํ๋ select ํจ์(?[Boolean list;list1;list2])๊ฐ ์์ต๋๋ค.
// high -> ?[isFirst;inp`high;row[`high]|inp`high]
// @ - ัะพะถะต ะพะฑะพะฑัะตะฝะฝะพะต ะฟัะธัะฒะฐะธะฒะฐะฝะธะต ะดะปั ัะปััะฐั ะบะพะณะดะฐ ะธะฝะดะตะบั ะฝะตะณะปัะฑะพะบะธะน
@[`aggExpression;specialCols;{[x;y]"?[isFirst;inp`",y,";",x,"]"};string specialCols];
์ฌ๊ธฐ์๋ ์ ํจ์(์ค๊ดํธ ์์ ํํ์)๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ค๋ฆญ ํ ๋น์ ํธ์ถํ์ต๋๋ค. ํ์ฌ ๊ฐ(์ฒซ ๋ฒ์งธ ์ธ์)๊ณผ ๋ค ๋ฒ์งธ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌํ ์ถ๊ฐ ์ธ์๊ฐ ์ ๋ฌ๋ฉ๋๋ค.
๋ฐฐํฐ๋ฆฌ ์คํผ์ปค๋ ๊ธฐ๋ฅ์ด ๋์ผํ๋ฏ๋ก ๋ณ๋๋ก ์ถ๊ฐํด ๋ณด๊ฒ ์ต๋๋ค.
// volume -> row[`volume]+inp`volume
aggExpression[accumulatorCols]:{"row[`",x,"]+inp`",x } each string accumulatorCols;
์ด๋ Q ๊ธฐ์ค์ผ๋ก๋ ์ผ๋ฐ์ ์ธ ํ ๋น์ ๋๋ค. ๋ค๋ง ๊ฐ ๋ชฉ๋ก์ ํ ๋ฒ์ ํ ๋นํ๋ ๊ฒ๋ฟ์ ๋๋ค. ๋ง์ง๋ง์ผ๋ก main ํจ์๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
// ":",/: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์์๋ ํ๊ฐ ์์๊ฐ ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ๋ฐ๋๋ฏ๋ก ์ด์ ํ๊ฐ ์์๋ ๋ฐ๋์ ๋๋ค.
์ด์ ์ปดํจํ ์ ํ์ํ ๋ ๊ฐ์ง ์ฃผ์ ๊ธฐ๋ฅ์ด ๊ฐ์ถฐ์ก๊ณ , ์ธํ๋ผ๋ฅผ ์ถ๊ฐํ๊ธฐ๋ง ํ๋ฉด ์๋น์ค๊ฐ ์ค๋น๋ฉ๋๋ค.
์ต์ข ๋จ๊ณ
๋ชจ๋ ์์ ์ ์ฒ๋ฆฌํ๋ preprocess ํจ์์ updateAgg ํจ์๊ฐ ์์ต๋๋ค. ํ์ง๋ง ๋ถ ๋จ์์ ์ ํํ ์ ํ์ ๋ณด์ฅํ๊ณ ์ง๊ณ๋ฅผ ์ํ ์ธ๋ฑ์ค๋ฅผ ๊ณ์ฐํด์ผ ํฉ๋๋ค. ๋จผ์ init ํจ์๋ฅผ ์ ์ํด ๋ณด๊ฒ ์ต๋๋ค.
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)];
}
๋ง์ง๋ง์ผ๋ก, ํด๋ผ์ด์ธํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด ํธ์ถํ๋ upd ํจ์(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];
};
ํ ์คํธ
์๋น์ค์ ์ฑ๋ฅ์ ํ์ธํด ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ์ํด ๋ณ๋์ ํ๋ก์ธ์ค์์ ์คํํ๊ณ (service.q ํ์ผ์ ์ฝ๋๋ฅผ ์ถ๊ฐํ๊ณ ) init ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
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๋ฐ๋ฆฌ์ด๊น์ง ๋ณํฉ๋๋ค.
์ด์ ์๋น์ค๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ณผ ์ ์์ต๋๋ค(์ฒ์ 10์๊ฐ์ ์ถ๊ฐํด ๋ณด๊ฒ ์ต๋๋ค).
{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๋ฐ๋ฆฌ์ด๋ง๋ค XNUMX์ค์ฉ ์คํํด ๋ณด์ธ์.
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์ต XNUMX์ฒ๋ง ์ค)์ ๋งค์ฐ ๋ฐฉ๋ํ๊ธฐ ๋๋ฌธ์, ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ์๋น์ค์ ๋ณต์ ๋ณธ์ ์ฌ๋ฌ ๊ฐ(์ฌ์ง์ด ์์ญ ๊ฐ) ์คํํ์ฌ ๊ฐ๊ฐ ๋ฌธ์์ ์ผ๋ถ๋ง ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ , ๋ฐ์ดํฐ ์ ์ฅ์ ์ฃผ๋ก ์ด์ ์ ๋ง์ถ ํด์ ์ธ์ด๋ก์๋ ์ธ์์ ์ธ ๊ฒฐ๊ณผ์ ๋๋ค.
๊ฐ ์ ๋ฐ์ดํธ ํฌ๊ธฐ์ ๋ฐ๋ผ ์๊ฐ์ด ๋น์ ํ์ ์ผ๋ก ์ฆ๊ฐํ๋ ์ด์ ๊ฐ ๊ถ๊ธํ ์ ์์ต๋๋ค. ๊ทธ ์ด์ ๋ ์ถ์ ํจ์๊ฐ ์ค์ ๋ก updateAgg๋ณด๋ค ํจ์ฌ ํจ์จ์ ์ผ๋ก ์๋ํ๋ C ํจ์์ด๊ธฐ ๋๋ฌธ์ ๋๋ค. ํน์ ์ ๋ฐ์ดํธ ํฌ๊ธฐ(์ฝ 10.000)์์ ์์ํ์ฌ updateAgg๋ ์ํ์ ๋๋ฌํ๊ณ ๊ทธ ํ ์คํ ์๊ฐ์ ์ ๋ฐ์ดํธ ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง์ง ์์ต๋๋ค. ์๋น์ค๊ฐ ์ด๋ฌํ ๋ณผ๋ฅจ์ ๋ฐ์ดํฐ๋ฅผ ์ํํ ์ ์๋ ๊ฒ์ ์๋น Q ๋จ๊ณ ๋๋ฌธ์ ๋๋ค. ์ด๋ ๋น ๋ฐ์ดํฐ๋ก ์์ ํ ๋ ์ฌ๋ฐ๋ฅธ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ๋ ๊ฒ์ด ์ผ๋ง๋ ์ค์ํ์ง ๊ฐ์กฐํฉ๋๋ค. ๋ ๋ค๋ฅธ ์์ ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฅํ๋ ๊ฒ์ ๋๋ค. ๋ฐ์ดํฐ๊ฐ ์ด ํ์์ผ๋ก ์ ์ฅ๋์ง ์์๊ฑฐ๋ ์๊ฐ์์ผ๋ก ์ ๋ ฌ๋์ง ์์๋ค๋ฉด TLB ์บ์ ๋ฏธ์ค(ํ๋ก์ธ์ ์ฃผ์ ์บ์์ ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง ์ฃผ์๊ฐ ์๋ ์ํ)์ ๊ฐ์ ๋ฌธ์ ์ ์ง๋ฉดํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ์คํจ ์ ์ฃผ์ ๊ฒ์์ ์ฝ 30๋ฐฐ ๋ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๊ฐ ๋ถ์ฐ๋ ๊ฒฝ์ฐ ์๋น์ค ์๋๊ฐ ์ฌ๋ฌ ๋ฐฐ ๋๋ ค์ง ์ ์์ต๋๋ค.
๊ฒฐ๋ก
์ด ๊ธ์์๋ KDB+์ Q ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ select๋ฅผ ํตํด ์ฝ๊ฒ ์ ๊ทผํ ์ ์์ ๋ฟ๋ง ์๋๋ผ, ๋จ์ผ Q ํ๋ก์ธ์ค์์๋ ์์ต ๊ฐ์ ํ/๊ธฐ๊ฐ๋ฐ์ดํธ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์๋น์ค๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ์๋ ์ ํฉํ๋ค๋ ๊ฒ์ ๋ณด์ฌ์ฃผ์์ต๋๋ค. Q ์ธ์ด ์์ฒด๋ ๋ฒกํฐ ๊ธฐ๋ฐ ํน์ฑ, ๋ด์ฅ SQL ์ธ์ด ์ธํฐํ๋ฆฌํฐ, ๊ทธ๋ฆฌ๊ณ ๋งค์ฐ ์ ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํจ์ ์ธํธ๋ฅผ ํตํด ๋งค์ฐ ๊ฐ๋จํ๊ณ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
์์ ๋ด์ฉ์ Q์ ๊ธฐ๋ฅ ์ค ์ผ๋ถ์ ๋ถ๊ณผํ๋ฉฐ, Q๋ ๋ค๋ฅธ ๊ณ ์ ํ ๊ธฐ๋ฅ๋ค์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๊ฐ๋ณ Q ํ๋ก์ธ์ค ๊ฐ์ ๊ฒฝ๊ณ๋ฅผ ์์ ๊ณ ์๋ฐฑ ๊ฐ์ ํ๋ก์ธ์ค๋ฅผ ๋จ์ผ ๋คํธ์ํฌ๋ก ํตํฉํ ์ ์๋๋ก ํ๋ ๋งค์ฐ ๊ฐ๋จํ IPC ํ๋กํ ์ฝ์ด ์์ต๋๋ค. ์ด ๋คํธ์ํฌ๋ ์ ์ธ๊ณ ์์ญ ๊ฐ์ ์๋ฒ์ ๋ถ์ฐ ๋ฐฐ์น๋ ์ ์์ต๋๋ค.
์ถ์ฒ : habr.com
