주식 매매 체결 순서 설명

주식 체결 순서 원칙에 따르면 다음과 같은 일도 일어 납니다. 보유하고 있던 주식을 10,000원에 매도 주문을 냈는데 10,500원에 매도 되는 일 말입니다.
자주 일어나는 일은 아니지만, 주식 매매 원칙에 따르면 충분히 일어날 수 있는 일입니다.
주식 체결 순서 원칙은 주식 거래가 정규 시장, 동시호가 시간, 시간외 거래 시간 이루어지냐에 따라 조금 차이가 나는데요, 기본이 되는 정규 시장의 원칙부터 알아보겠습니다.

주식 거래는 정규 시장에 주로 이루어 지지만 아래와 같이 정규 거래 시간 외에도 주식을 거래할 수 있는 시간이 있습니다.
    - 정규 시장: 오전 9시 ~ 오후 2시 50분
    - 동시호가 시간: 오전 8시 ~ 오전 9시, 오후 2시 50분 ~ 오후 3시
    - 시간외 매매: 오전 7시 30분 ~ 오전 8시 30분, 오후 3시 ~ 오후 3시 30분, 오후 3시 30분 ~ 오후 6시
정규 시장 전 동시호가 시간과 오전 시간외 매매 시간 일부가 겹치는 것으로 보이지만, 시간외 매매는 정규 시장 거래 창이 아니라 별도의 거래 창에서 이루어 지기 때문에 거래가 겹치는 것은 아닙니다.

정규 시장 주식 체결 순서

가격 우선 → 시간 우선 → 수량 우선 순의 체결 원칙에 따라 매매가 이루어 지는데요, 구체적인 예를 들어 어떻게 이 원칙에 따라 매매가 체결 되는 지는 잠시 후에 알아 보겠습니다.자
정규 시장은 오후 3시까지이지만 마지막 10분 즉 오후 2시 50분에서 3시까지는 동시호가 체결 원칙에 따라 거래가 이루어 집니다. 따라서 가격, 시간, 수량 순의 우선 순위 체결 원직은 오전 9시부터 오후 2시 50분까지의 시간 동안 지켜지는 것이라고 보면 됩니다.

가격 우선 체결 원칙

주식을 사거나 팔 때 시장가로 매매 하기도 하지만, 보통은 매도 호가나 매수 호가를 지정하여 거래를 합니다.
가격 우선 원칙은 매도 호가는 낮은 가격이 높은 가격에 우선하고 매수 호가는 높은 가격이 낮은 가격에 우선한다는 원칙입니다.
이 원칙에 따르게 되면 여러 사람이 매도 호가와 매수 호가를 지정하여 주식을 매매 할 때, 가장 낮은 매도 호가를 부른 사람과 가장 높은 매수 호가를 부를 사람의 거래가 성립되게 됩니다.
이렇게 첫 번째 거래가 성립되고 나면 두 번째로 우선 순위를 갖는 매도자와 매수자와의 거래가 성립되고 또 다음 우선 순위를 갖는 거래가 성립되는 식으로 순차적으로 매매 거래가 체결 됩니다.
말은 이런 식으로 하지만 전산 처리되어 순식간에 체결이 이루어지죠. 물론 매도 우선 순위를 갖는 사람과 매수 우선 순위를 갖는 사람이 있지만 가격 조건이 맞지 않아 거래가 이루어 지지 않는 경우도 있습니다.

아래 예를 통해 구체적으로 살펴 보겠습니다.

어떤 주식에 대해 다음과 같이 매도 호가를 부른 사람 두 명(A와 B), 매수 호가를 부른 사람 두 명(갑과 을)이 있다고 가정해 보겠습니다.

    - A는 100주를 1주당 8,000원에 매도 하려고 하고,
    - B는 50주를 1주당 9,000원에 매도 하고자 함.
    - 갑은 100주를 1주당 10,000원에 매수 하려고 하고,
    - 을은 10주를 1주당 7,000원에 매수 하려고 함.
    - 가격 우선 체결 순서에 따르면 매도자 중에서는 낮은 매도 가격을 낸 A가 우선 순위를 가지고 매수자 중에서는 높은 매수 가격을 제시한 갑이 우선 순위를 가집니다.

A와 갑의 가격 조건을 보니 팔려는 사람(A)보다 사려는 사람(갑)이 비싸게 가격을 제시 했네요. 갑은 1주당 10,000원을 주고 100주는 매입하게 됩니다. A는 1주당 8,000원에 팔려고 했지만 갑 덕분에 1주당 10,000원에 팔 수 있게 되었습니다.
이번에는 다음 우선 순위를 가지는 B와 을의 가격 조건을 검토해 보겠습니다. B는 1주당 9,000원에 팔려고 하지만 을은 7,000원에 매수 하려고 합니다. 두 사람이 직접 만난다면 가격 흥정을 해 볼 수 있겠지만, 정규 주식 시장에서의 거래는 둘이 직접 만나 가격 흥정을 하는 식으로 거래가 성립 되지는 않지요.
그래서 B와 을 사이에는 가격이 맞지 않아 거래가 성립되지 않습니다. 결국 위의 예에서는 A와 갑사이에서만 거래가 성립됩니다.
실제 주식 시장에서는 위의 예 보다 훨씬 더 많은 매도자와 매수자가 있습니다. 따라서 실제 주식 체결 순서는 위 예보다는 좀 더 복잡하지만, 기본 원칙은 위에서 설명한 예와 같습니다.
가격을 기준으로 우선 순위를 가지는 매도자와 매수자를 걸러 내고 둘 사이에 가격이 맞다면 주식 매매가 체결 되고, 그 다음 우선 순위를 가지는 매도자와 매수자 간의 가격 조건을 검토하여 거래 성립 여부를 본 후, 또 그 다음 우선 순위를 가지는 매도자와 매수자의 거래 성립을 판단 하는 식으로 주식 거래가 이루어 집니다.

시간 우선 체결 원칙

앞의 예에서는 A와 B, 갑과 을이 서로 다른 가격을 제시한 것으로 가정했는데요, 만약 매도자들이 서로 같은 가격 또 매수자들이 서로 같은 가격을 제시한다면 어떻게 될까요?
바로 다음과 같은 상황인데요,

    - A: 한주당 8,000원 100주 매도 주문,
    - B: 한주당 8,000원 50주 매도 주문,
    - 갑: 한주당 10,000원 100주 매수 주문
    - 을: 한주당 10,000원 10주 매수 주문

가격이 같기 때문에 가격 우선 원칙을 적용하여 우선 순위를 가지는 사람을 판별할 수 없습니다.
그래서 등장하는 것이 시간 우선 원칙입니다. 즉, A가 B보다 먼저 매도 주문을 냈다면 매도자 중에서는 A가 우선 순위를 가지고 을이 갑보다 먼저 매수 주문을 냈다면 매수자 중에서는 을이 우선 순위를 가지게 되죠.
따라서 먼저 A와 을 사이에 거래가 성립 됩니다. 가격은 을의 매수 주문 가격인 한주당 10,000원이 됩니다. 그런데 을은 10주만 매수 하려 하기 때문에 A의 주식은 일단 10주만 매도 됩니다.
매도자 중에서 A는 아직도 90주(100주-10주)만큼 우선 순위를 가지고 있습니다. 매수자 중에서는 이제 갑만 남았습니다. 갑은 한주당 10,000원으로 A로부터 90주를 매수할 수 있게 됩니다.
갑은 100주를 구입하려 했으니 아직 10주를 구입 못한 상태입니다. 매도자 중에서 A는 팔려는 주식을 모두 팔았으니 이제 B만 남았습니다. 갑은 B로부터 한주당 10,000원으로 10주를 매수 하게 됩니다.

수량 우선 체결 원칙

앞에서 가격 우선 원칙을 살펴 보았고, 가격이 같다면 시간 우선 주식 체결 순서에 따라 거래가 성립 되는 것을 알아 보았습니다.
그런데, 가격도 같고 주문을 낸 시간도 같다면 어떻게 될까요?
이때는 수량 우선 원칙이 적용되게 되는데요, 주문 수량이 많은 사람이 우선한다는 원칙입니다.
다음과 같은 상황을 가정해 보겠습니다. A,B,C 모두 같은 시각에 매도 주문을 내었고, 갑과 을도 같은 시간에 매수 주문을 내었습니다.

    - A: 한주당 8,000원 100주 매도 주문,
    - B: 한주당 8,000원 50주 매도 주문,
    - C: 한주당 8,000원 70주 매도 주문,
    - 갑: 한주당 10,000원 100주 매수 주문,
    - 을: 한주당 10,000원 10주 매수 주문

매도자들이 서로 같은 가격으로 주문을 했고 매수자들도 같은 매수 가격을 제시했으니, 가격 우선 체결 원칙은 적용될 수 없고, 또 같은 시각에 주문을 내었으니 시간 우선 원칙도 적용될 수 없습니다.
이 경우에는 수량 우선 주식 체결 원칙에 따라 거래가 이루어 집니다. 주문 수량이 많은 순으로 우선 순위가 정해 지므로 매도자는 A → C → B, 매수자는 갑 → 을 순으로 우선 순위를 갖게 됩니다.
따라서 갑은 A에게서 100주를 주당 10,000원으로 매수하게 되고, 을은 C로부터 주당 10,000원으로 10주를 매수하게 됩니다.
B는 한 주도 팔지 못하고 C는 70주 중에서 10주만 매도에 성공하게 됩니다.
이상 정규 시장에서의 주식 체결 순서였습니다. 이제 동시호가 시간의 주식 체결은 어떻게 이루어 지는 지 알아 보겠습니다.

동시호가 시간엔 모두 거래가 동시에 이루어 졌다고 가정하여 주식 체결

동시호가 시간은 오전 8시에서 오전 9시까지(장전 동시호가) 한 시간 또 오후 2시 50분에서 오후 3시까지(장 마감 동시호가) 10분간 이루어 집니다.
이 시간에 이루어 지는 매도·매수 주문은 모두 동시에 이루어 진 것으로 간주합니다. 동시(同時)호가라는 이름은 그래서 생긴 것이죠.
어쨌든 이 원칙에 따르면 오전 8시에 낸 주문도 오전 8시 50분에 낸 주문도 같은 시간에 이루어 진 것으로 간주하게 됩니다.
따라서 동시호가 시간의 주식 매매에는 시간 우선 원칙을 적용할 수 없습니다. 가격 우선 원칙을 먼저 적용하고 그 다음에 수량 우선 원칙을 적용하게 되죠.
그런데 일정 시간 동안에 있었던 주식 매매 주문을 같은 시간에 이루어 진 것으로 간주할 경우 , 일정 시점을 끊어서 거래를 체결해 주어야 합니다. 그렇지 않으면 거래가 이루어지지 않겠지요.
그래서 장전 동시호가 시간에 있었던 주문들은 오전 9시에 동시에 이루어 진 것으로 보아 일괄적으로 체결하고 장 마감 동시호가 시간에 있었던 주문들은 오후 3시에 일괄적으로 체결 됩니다.

시초가와 종가

잠시 후에 동시호가 시간의 주식 체결 방식을 구체적으로 알아 볼텐데요, 동시호가 주식 체결 방식에 따라 결정된 주식 가격은 특별한 의미를 가집니다.
즉, 장전 동시호가에서 결정된 주식 가격은 시초가가 되고 장마감 동시호가에서 결정된 주식 가격은 그날의 종가가 됩니다.
어떻게 시초가와 종가가 결정 되는 지는 아래에서 예를 들어 알아 보겠습니다.

동시호가 주식 체결 방식

동시호가 시간에 있었던 주문은 모두 같은 시간에 한 것으로 간주하고 가격 우선 → 수량 우선 체결 원칙이 적용 된다고 했는데요, 정규 시장과 다른 점이 한 가지 더 있습니다.
동시호가 시간의 주문은 가격 우선과 수량 우선 순서로 적용하되 모든 주문을 한꺼번에 체결 하기 때문에 마지막으로 성립되는 거래에서 매수자가 제시한 가격으로 일괄 체결된다는 점이 다릅니다.
아마 말로는 쉽게 이해되지 않을 것 같은데요, 아래의 예를 보면 금방 이해할 수 있습니다.
동시호가 시간 동안 어떤 주식에 대해 매도자와 매수자가 다음과 같이 주문을 했다고 가정해 보겠습니다.

    매도자
    - A: 주당 10,000원에 100주
    - B: 주당 10,100원에 10주
    - C: 주당 10,200원에 30주
    매수자
    - 갑: 주당 10,300에 70주
    - 을: 주당 10,150에 30주
    - 병: 주당 10,150에 50주

가격 → 수량 우선 순서에 따라 매도자는 A → B → C 순으로 우선 순위를 가지고, 매수자는 갑 → 병 → 을 순으로 우선 순위를 가지게 됩니다.
일단 갑과 A 사이에 70주 거래가 가능합니다.

그 다음 우선 순위인 병은 A로부터 30주를 살 수 있고 B로부터 10주를 살 수 있습니다. 여기까지의 상황은 A와 B가 주문을 낸 만큼 모두 팔 수 있고, 갑은 원하는 수만큼 모두 구매 할 수 있으며 병은 원하는 수량 50주 중 40주를 매수할 수 있는 상황입니다.
병이 나머지 10주를 매수하기 위해서는 C로부터 매수해야 하는데 C는 10,200원에 팔기를 원하고 병은 10,150에 매수하기를 원하므로 거래가 성립되지 않습니다.
따라서 마지막으로 성립된 거래는 병과 B사이의 거래고 이 때의 매수 가격은 10,150원입니다. 위 예가 장전 동시호가라면 10,150원이 시초가가 될 것이고 장 마감 동시호가라면 10,150원이 종가가 됩니다.
정규시장이었다면, 갑과 A 사이는 10,300원으로 거래가 되겠지만, 동시호가 시간의 거래 원칙에 따라 갑과 A 사이도 최종 거래 가격인 10,150원으로 거래가 됩니다. 이제 ‘동시호가 시간의 거래는 마지막으로 성립되는 거래에서 매수자가 제시한 가격으로 일괄 체결 된다.’는 말을 이해할 수 있을 것입니다.

장전 동시호가시간 거래할 때 주의할 점

회사 출근 때문에 HTS나 MTS를 이용할 수 없는 직장인이나 비슷한 이유로 장중에 주식 매매를 할 수 없는 경우 오전 8시 ~ 오전 9시 사이에 미리 주문을 내어 놓는 경우가 있습니다.
동시호가 주식 체결 방식에 따라 거래가 성립된다면 9시에 일괄적으로 체결되지만, 자신이 낸 주문이 체결 되지 않았다면 어떻게 될 까요?
장 마감 동시호가 시간에 낸 주문이 체결되지 않는 경우에는 오후 3시에 자동으로 취소가 됩니다만, 장전 동시호가 시간에 낸 주문이 체결 되지 않는 경우는 자동으로 취소가 되지 않습니다.
따라서 체결 되지 않은 (장전 동시호가 시간에 낸) 주문은 오전 9시에 취소 주문을 하는 것이 좋습니다.
물론 주문 내용 그대로 장 중에 매매가 되기를 희망한다면 굳이 취소 주문을 한 후 새로 주문을 낼 필요가 없지만,
주식이라는 것이 장전 분위기와 장 시작한 후의 분위기가 다른 때가 많은 법이니 장전 동시호가 시간에 내었던 주문은 꼭 체결 되었는지 여부를 확인하고 체결되지 않았다면 필요한 조치(그대로 두거나, 취소 주문을 내거나, 아니면 취소 주문후 새로운 조건으로 주문을 내 는 조치)를 취해야 한다는 점을 잊지 마시기 바랍니다.

시간외 거래

시간외 거래는 시간외 종가 매매와 시간외 단일가 매매로 나뉘어 지는데요, 시간외 종가 매매는 전일 종가로만 거래되는 장전 시간외 거래 시간(오전 7시 30분 ~ 오후 8시 30분)와 당일 종가로만 거래되는 장후 시간외 거래 시간(오후 3시 ~ 오후 3시 30분)으로 나누어 집니다.
장후 시간외 거래의 경우는 오후 3시부터 주문을 할 수는 있지만 체결은 오후 3시 10분부터 이루어 집니다.
시간외 단일가 매매는 오후 3시 30분~ 오후 6시 사이에 이루어 지는데요, 당일 종가 기준 ±5% 범위에서 매수 매도 주문을 낼 수 있습니다.
단, 상한가와 하한가를 초과할 수는 없기 때문에 상한가로 마감된 경우에는 상한가~상한가-5%, 하한가로 마감된 경우에는 하한가 ~ 하한가+5% 범위에서 주문을 낼 수 있습니다.
시간외 단일가 매매 체결은 오후 4시 ~ 오후 6시 사이에 10분 단위로 동시호가 방식으로 이루어 집니다.
시간외 거래 주문은 동시호가나 정규장 시간에 이용하는 창이 아니라 별도의 창(증권사에 따라서는 주문 종류 선택으로 하는 곳도 있음)에서 해야 합니다.

주식 체결 순서에 대한 결론

지금까지 정규 주식 시장, 동시호가 시간, 시간외 거래 시간에 주식이 체결 되는 방식에 대해 알아 보았는데요,
주식 체결 순서 원칙은 정규 시장에서 이루어 지는 가격 → 시각 → 수량 우선 원칙입니다. 동시호가 시간과 시간외 거래는 이 원칙의 변용으로 이해하면 됩니다.
체결 순서 기본 원칙에 따라 매도자 입장에서 빨리 매도에 성공하려면 가능한 한 낮은 가격으로 빨리 또 가능한 많은 수량의 주문을 내야 하고 매수자 입장이라면 가능한 한 높은 가격으로 최대한 빨리 많은 수량의 주문을 내야 한다는 것을 알 수 있습니다.
그런데 매도자 입장에서는 최대한 높은 가격으로 팔고 매수자 입장에서는 될 수 있는 한 낮은 가격으로 주식 거래를 체결해야 이익입니다. 가격 우선 체결 원칙은 이와는 반대로 가죠.
시간 우선 체결 원칙 상황도 비슷합니다. 빨리 거래를 성공시키기 위해서는 빨리 주문을 내야 하지만, 주식 투자라는 것이 간을 보아야 할 때가 많습니다.
수량 우선 상황도 비슷하죠. 많은 수량으로 주문을 내야 빨리 거래를 성공 시킬 수 있지만, 보유 주식을 한꺼번에 매도 하는 것보다는 분할 매도 하는 것이 또 분할 매수 하는 것이 일반적인 주식 투자 원칙입니다.
이처럼 주식 체결 순서 원칙은 주식 투자를 통해 수익를 얻으려는 목적과 반대되는 경향이 있다는 점을 염두에 두시기 바랍니다.
물론 주식 투자를 하다 보면 최대한 빨리 팔거나 사야 할 때가 있고 이 때는 주식 체결 순서를 고려하여 주문을 내야 하지만, 그렇지 않은 상황에서는 사실 주식 체결 순서를 그리 민감하게 고민할 필요는 없다는 말씀입니다.
주식 체결 순서 원칙보다는 자신만의 투자 원칙에 집중하는 것이 더 좋다는 생각입니다.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>

#include "tagwire.h"
#include "fssdefine.h"

#define HEADERINDEX 13

int main(int argc, char *argv[])
{
FILE *fp=NULL;
char rbuf[4096 * 2L];

if(argc != 2) return -1;

if((fp=fopen(argv[1], "rt"))==NULL) return -1;

while(1)
{
memset(rbuf, 0x00, sizeof(rbuf));
if(fgets(rbuf, sizeof(rbuf), fp)==NULL) break;
rbuf[strlen(rbuf)-1]=0x00;

        if(memcmp(rbuf+HEADERINDEX,"296=",4)==0)
{
struct TradableInstrument *ie=NULL;

ie = TradableInstrument(rbuf + HEADERINDEX);

if(ie != NULL)
{
//printf("%s", rbuf);
printf("SEQ[%07ld],", kk+1);
printf("MessageID[%.4s],", rbuf+HEADERINDEX);
printf("shortName:[%s],", ie->shortName);
printf("orderBookId:[%ld],", ie->orderBookId);
printf("closingPrice:[%ld],", ie->closingPrice);
printf("isDeleted:[%c],", ie->isDeleted);
printf("upperPriceLimit:[%ld],", ie->upperPriceLimit);
printf("lowerPriceLimit:[%ld],", ie->lowerPriceLimit);
printf("closingDate:[%s]", ie->closingDate);

printf("\n");
}
}
else if(memcmp(rbuf+HEADERINDEX,"496=",4)==0)
{
struct IndexEvent *ie=NULL;

ie = IndexEvent(rbuf + HEADERINDEX);

if(ie != NULL)
{
//printf("%s", rbuf);
printf("SEQ[%07ld],", kk+1);
printf("MessageID[%.4s],", rbuf+HEADERINDEX);
printf("sequenceNumber[%ld],", ie->sequenceNumber);
printf("timeOfEvent[%s]", ie->timeOfEvent);

printf("\n");
}
}
else if(memcmp(rbuf + HEADERINDEX,"140=",3)==0)
{
struct MarketByLevelEvent *ie=NULL;

ie = MarketByLevelEvent(rbuf + HEADERINDEX);

if(ie != NULL)
{
//printf("%s", rbuf);
printf("SEQ[%07ld],", kk+1);
printf("MessageID[%.3s],", rbuf+HEADERINDEX);
printf("timeOfEvent[%s],",ie->timeOfEvent);
printf("orderBook[%ld],",ie->orderBook);
printf("isBid[%c],",ie->isBid);
printf("price[%ld],",ie->price);
printf("volume[%ld],",ie->volume);
printf("correspondingPrice[%ld]",ie->correspondingPrice);

printf("\n");
}
}
else if(memcmp(rbuf + HEADERINDEX,"51=",3)==0)
{
struct OrderBookStateChangeEvent *ie=NULL;

ie = OrderBookStateChangeEvent(rbuf + HEADERINDEX);

if(ie != NULL)
{
//printf("%s", rbuf);
printf("SEQ[%07ld],", kk+1);
printf("MessageID[%.3s],", rbuf+HEADERINDEX);
printf("timeOfEvent:[%s],", ie->timeOfEvent);
printf("orderBookRuleGroup:[%s]", ie->orderBookRuleGroup);

printf("\n");
}
}
else if(memcmp(rbuf + HEADERINDEX,"49=",3)==0)
{
struct TradeEvent *ie=NULL;

ie = TradeEvent(rbuf + HEADERINDEX);

if(ie != NULL)
{
//printf("%s", rbuf);
printf("SEQ[%07ld],", kk+1);
printf("MessageID[%.3s],", rbuf+HEADERINDEX);
printf("timeOfTrade[%s],", ie->timeOfTrade);
printf("orderQty[%ld],", ie->orderQty);
printf("price[%ld],", ie->price);
printf("highPrice[%ld],", ie->highPrice);
printf("lowPrice[%ld],", ie->lowPrice);
printf("totalTurnover[%ld],", ie->totalTurnover);
printf("correspondingPrice[%ld],", ie->correspondingPrice);
printf("tradeId[%s],", ie->tradeId);
printf("dealId[%s]", ie->dealId);

printf("\n");
}
}
else if(memcmp(rbuf + HEADERINDEX,"62=",3)==0)
{
struct AuctionEvent *ie=NULL;

ie = AuctionEvent(rbuf + HEADERINDEX);

if(ie != NULL)
{
//printf("%s", rbuf);
printf("SEQ[%07ld],", kk+1);
printf("MessageID[%.3s],", rbuf+HEADERINDEX);
printf("timeOfEvent[%s],",ie->timeOfEvent);
printf("orderBook[%ld],",ie->orderBook);
printf("calculatedAuctionPrice[%ld],",ie->calculatedAuctionPrice);
printf("matchedQuantity[%ld]",ie->matchedQuantity);

printf("\n");
}
}
}
if(fp != NULL) fclose(fp);
return(0);
}

※ 요약
윈도우 환경에 OpenSSL 개발 환경을 구축하는 방법이다. 
OpenSSL은 보안 및 암호화와 관련된 라이브러리인 만큼 최신 버전으로 개발 환경을 구축하기 바란다.

 

※ 다운로드 주소
http://slproweb.com/products/Win32OpenSSL.html
FILE:Win32 OpenSSL v1.1.0f​

/*

 *  AES 128 bits Algorithm AES/ECB/PKCS7Padding and hex encoding

 *  AES 128 bits Algorithm AES/ECB/PKCS7Padding and hex decoding

 *

 *  (암호화 방법) TEXT를 암호화 한다. > 암호화되어진코드는 READ DISABLE하다. > HEXA ENCODING을 한다.

 *  (복호화 방법) HEXA DECODING을 한다. > 복호화되어진 코드는 READ DISABLE하다. > 복호화를 진행한다.

 */

 

/* FILE PATH REGISTERED CASE

 * gcc AES.c -lcrypto -o AES

 * gcc AES.c -lcurl -o AES

 * gcc AES.c -ljason-c -o AES​

 */

/* NEEDED FILE

 1. 2017-08-29  오전 08:40             3,433 aes.h
 2. 2017-08-29  오전 08:46             6,610 AES_TEST.c
 3. 2017-05-25  오후 09:20           928,710 libcrypto.lib
 4. 2017-05-25  오후 09:20             4,155 opensslconf.h

 *

 * gcc -c AES_TEST.c

 * gcc -o AES_TEST AES_TEST.o libcrypto.lib

 */


#include <stdio.h>
#include <string.h>
#include <time.h>

#include "aes.h"​ 

 

#define MAX_AES_BUFF_SIZE 2048

 

const unsigned char fw_aes_key[16+1] = {0X33, 0X67, 0X33, 0X33, 0XAB, 0X69, 0X6C, 0XC0, 0X73, 0X30, 0X6C, 0X75, 0X74, 0X69, 0X6F, 0X6E, 0x00};

 

static void e_hex_convert(const void* pv, size_t len, char *outBuff) {
    const unsigned char * p = (const unsigned char*)pv;
  
    if (NULL == pv) {
        return;
    }
    else

    {
        size_t i = 0;
        int hexLen = 0;
        char editb[8];


        memset (editb, 0x00, sizeof(editb));
        for (; i<len;++i) {
            sprintf(editb, "%02X", *p++);
            memcpy(outBuff+hexLen, editb, 2);
            hexLen += 2; 
        }
    }
    return;
}

static void d_hex_convert(unsigned char *pv, size_t len, char *outBuff) {
    const unsigned char * p = (const unsigned char*)pv;
 
    int ii, kk, jj;
 
    kk=0;
    ii=0;
    while(1)
    {
        if(ii >= len) break;
  
        jj=0;
        if(pv[ii] == 'F') pv[ii] = 15;
        else if(pv[ii] == 'E') pv[ii] = 14;
        else if(pv[ii] == 'D') pv[ii] = 13;
        else if(pv[ii] == 'C') pv[ii] = 12;
        else if(pv[ii] == 'B') pv[ii] = 11;
        else if(pv[ii] == 'A') pv[ii] = 10;
        else if(pv[ii] == '9') pv[ii] = 9;
        else if(pv[ii] == '8') pv[ii] = 8;
        else if(pv[ii] == '7') pv[ii] = 7;
        else if(pv[ii] == '6') pv[ii] = 6;
        else if(pv[ii] == '5') pv[ii] = 5;
        else if(pv[ii] == '4') pv[ii] = 4;
        else if(pv[ii] == '3') pv[ii] = 3;
        else if(pv[ii] == '2') pv[ii] = 2;
        else if(pv[ii] == '1') pv[ii] = 1;
        else if(pv[ii] == '0') pv[ii] = 0;
  
        if((pv[ii] & 0x08) > 0) jj = jj + 128;
        if((pv[ii] & 0x04) > 0) jj = jj + 64;
        if((pv[ii] & 0x02) > 0) jj = jj + 32;
        if((pv[ii] & 0x01) > 0) jj = jj + 16;
  
        if(pv[ii+1] == 'F') pv[ii+1] = 15;
        else if(pv[ii+1] == 'E') pv[ii+1] = 14;
        else if(pv[ii+1] == 'D') pv[ii+1] = 13;
        else if(pv[ii+1] == 'C') pv[ii+1] = 12;
        else if(pv[ii+1] == 'B') pv[ii+1] = 11;
        else if(pv[ii+1] == 'A') pv[ii+1] = 10;
        else if(pv[ii+1] == '9') pv[ii+1] = 9;
        else if(pv[ii+1] == '8') pv[ii+1] = 8;
        else if(pv[ii+1] == '7') pv[ii+1] = 7;
        else if(pv[ii+1] == '6') pv[ii+1] = 6;
        else if(pv[ii+1] == '5') pv[ii+1] = 5;
        else if(pv[ii+1] == '4') pv[ii+1] = 4;
        else if(pv[ii+1] == '3') pv[ii+1] = 3;
        else if(pv[ii+1] == '2') pv[ii+1] = 2;
        else if(pv[ii+1] == '1') pv[ii+1] = 1;
        else if(pv[ii+1] == '0') pv[ii+1] = 0;
  
        if((pv[ii+1] & 0x08) > 0) jj = jj + 8;
        if((pv[ii+1] & 0x04) > 0) jj = jj + 4;
        if((pv[ii+1] & 0x02) > 0) jj = jj + 2;
        if((pv[ii+1] & 0x01) > 0) jj = jj + 1;
  
        outBuff[kk] = jj;
  
        kk = kk + 1;
        ii = ii + 2;
    }
    return;
}

 

//AES 128 bits Algorithm AES/ECB/PKCS7Padding and hex encoding

static int e_makeAesPacket(char *EncryptText, int EncryptTextLen, char *DecryptText) {
 
    AES_KEY enc_key;
    long idx=0;
    unsigned char padBuff[MAX_AES_BUFF_SIZE];
    unsigned char encBuff[MAX_AES_BUFF_SIZE];
    int ii;

    const size_t encPadLen = ((EncryptTextLen + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;

 

    memset(padBuff, 0x00, MAX_AES_BUFF_SIZE);
    memset(encBuff, 0x00, MAX_AES_BUFF_SIZE);
 
    AES_set_encrypt_key(fw_aes_key, 128, &enc_key);

    memcpy(padBuff, EncryptText, EncryptTextLen);
    for (ii = EncryptTextLen; ii < encPadLen; ii++) {
        padBuff[ii] = (encPadLen - EncryptTextLen);
    }

    while(idx < encPadLen) {
        AES_ecb_encrypt(padBuff+idx, encBuff+idx, &enc_key, AES_ENCRYPT);
        idx += AES_BLOCK_SIZE;
    }

    e_hex_convert(encBuff, encPadLen, DecryptText);

    return(strlen(DecryptText));
}

//AES 128 bits Algorithm AES/ECB/PKCS7Padding and hex decoding

//AES 128 bits Algorithm AES/ECB/PKCS7Padding and hex decoding 

static int d_makeAesPacket(char *DecryptText, int DecryptTextLen, char *PlainText) {
 
    AES_KEY dec_key;
    long idx=0;
    unsigned char padBuff[MAX_AES_BUFF_SIZE];
    unsigned char encBuff[MAX_AES_BUFF_SIZE];
    unsigned char outBuff[MAX_AES_BUFF_SIZE];
    int ii, kk, jj;

    memset(padBuff, 0x00, MAX_AES_BUFF_SIZE);
    memset(outBuff, 0x00, MAX_AES_BUFF_SIZE);
 
    AES_set_decrypt_key(fw_aes_key, 128, &dec_key);
 
    size_t encPadLen = strlen(DecryptText) / 2;
    d_hex_convert(DecryptText, DecryptTextLen, outBuff);

    while(idx < encPadLen) {
        AES_ecb_encrypt(outBuff+idx, PlainText+idx, &dec_key, AES_DECRYPT);
        idx += AES_BLOCK_SIZE;
    }

    jj=PlainText[encPadLen-1];

    if(jj<=32) PlainText[encPadLen-1] = 0x00;

    if(jj<=32)
    for(kk=encPadLen-2; kk>0; kk--)
    {
        if(PlainText[kk] == jj) PlainText[kk]=0x00;

        else break;
    }
    return(strlen(PlainText));
}

 

 

char TEXT[1204L * 128L];

int main(int argc, char *argv[])
{
     char ENCRYPTEXT[MAX_AES_BUFF_SIZE];
     char DECRYPTEXT[MAX_AES_BUFF_SIZE];
 
     int ii, kk, jj;
     int rlen;
 

     memset(TEXT, 0x00, sizeof(TEXT));

     strcpy(TEXT, "!@#$%^&*()(*&^%$#@!Input/Output Format from CIMS v9.00");​ 


     printf("[PLAIN   TEXT]%s\n", TEXT);
     printf("---------------------------------------------------------------------------------\n");
 
     memset(ENCRYPTEXT,0x00,sizeof(ENCRYPTEXT));
     memset(DECRYPTEXT,0x00,sizeof(DECRYPTEXT));
 
     rlen = e_makeAesPacket(TEXT, strlen(TEXT), ENCRYPTEXT);
     if (rlen < 0)

     {
        printf("AES_ENCRYPT FAILURE(%s)", TEXT);
        return (-1);
     }
     printf("[ENCRYPT TEXT]%s\n", ENCRYPTEXT);
     printf("---------------------------------------------------------------------------------\n");
 
     rlen = d_makeAesPacket(ENCRYPTEXT,strlen(ENCRYPTEXT),DECRYPTEXT);
     if (rlen < 0)

     {
        printf("AES_DECRYPT FAILURE(%s)", TEXT);
        return (-1);
     }
     printf("[DECRYPT TEXT]%s\n", DECRYPTEXT);
     printf("---------------------------------------------------------------------------------\n");
 
     return(0);
}
 
 
  

{
    "MSGCODE":"RCP",
    "RESULT":"0",
    "REASON":"complete",
    "ACCNO":"",
    "TAMOUNT":"0.00",
    "TMKTVALUE":"0.00",
    "PAGE":"1",
    "NEXTPAGE":"2",
    "COUNT":"2",

"STOCKLISTS":
[
    {
        "STOCKSYMBOL":"",
        "GRADE":"",
        "SECURITYTYPE":"",
        "MARGINRATE":"0",
        "ACTUALVOLUME":"0",
        "AVGCOST":"0.000000",
        "AMOUNT":"0.00",
        "LASTPRICE":"0.00",
        "MKTVALUE":"0.00",
        "MR":"0.00"
    },
    {
        "STOCKSYMBOL":"",
        "GRADE":"",
        "SECURITYTYPE":"",
        "MARGINRATE":"0",
        "ACTUALVOLUME":"0",
        "AVGCOST":"0.000000",
        "AMOUNT":"0.00",
        "LASTPRICE":"0.00",
        "MKTVALUE":"0.00",
        "MR":"0.00"
    }
]
}



/**
* sample.c
*
* Created on: Jun 2, 2017
* Description : https://json-c.github.io/json-c/json-c-0.10/doc/html/json__object_8h.html
*/

#include <json/json.h>
#include 
#include 



char buf[1204L * 128L];



int main(int argc, char *argv[])
{
    FILE *fp = fopen(argv[1], "r");

    if(NULL == fp)
    {
        fprintf(stderr, "fopen() failed");
        return -1;
    }

    int n = fread(buf, 1, sizeof(buf), fp);
    buf[n] = 0;

    struct json_object *jobj;

    jobj = json_tokener_parse(buf);
    if(NULL == jobj) {
        return -1;
    }

    char KEY[100], SUBKEY[100];

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "MSGCODE");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "RESULT");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "REASON");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "ACCNO");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "TAMOUNT");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "TMKTVALUE");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "PAGE");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "NEXTPAGE");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    memset(KEY, 0x00, sizeof(KEY));
    strcpy(KEY, "COUNT");
    printf("[%s][%s]\n", KEY, json_object_get_string(json_object_object_get(jobj, KEY)) );

    struct json_object *pdata = NULL;
    if(json_object_object_get_ex(jobj, "STOCKLISTS", &pdata)) 
    {
        int i;
        for (i = 0; i < json_object_array_length(pdata); i++) 
        {
            struct json_object *tmp = json_object_array_get_idx(pdata, i);
            printf("-----------------------------------\n");
            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "STOCKSYMBOL");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "GRADE");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "SECURITYTYPE");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "MARGINRATE");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "ACTUALVOLUME");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "AVGCOST");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "AMOUNT");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "LASTPRICE");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "MKTVALUE");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );

            memset(KEY, 0x00, sizeof(KEY));
            strcpy(KEY, "MR");
            printf("[%.3d][%s][%s]\n", i + 1, KEY, json_object_get_string(json_object_object_get(tmp, KEY)) );
        }
    }
    return 0;
​}




struct PriceLevel
{
 char timeOfEvent[STRING_MAX+1];   // ID :3
 int  price;                       // ID :7
 int  volume;                      // ID :8
 int  levels;                      // ID :10
 int  numberOfOrders;              // ID :11
}; 
struct MarketByLevel5Event
{
 int  subscriptionGroup;           // ID :1
 long sequenceNumber;              // ID :2
 char timeOfEvent[STRING_MAX+1];   // ID :3
 char sequenceIndicator;           // ID :4
 long orderBook;                   // ID :5
 int  askCount;
 struct PriceLevel askPriceLevels[5]; // ID :21
 int  bidCount;
 struct PriceLevel bidPriceLevels[5]; // ID :22
};

 

//위의 구조체에 아래의 데이타를 파싱및 매핑해서, 출력해본다.


3001=[1=258|2=1125000|3=2017-04-26T14:29:33.350|5=2170|21=[[3=2017-04-26T14:29:33.350|7=168000000|8=400000000|10=0]]]
>>>MarketByLevel5Event---------------------------------------------------
subscriptionGroup(1) = 258
sequenceNumber   (2) = 1125000
timeOfEvent      (3) = 2017-04-26T14:29:33.350
sequenceIndicator(4) = 
orderBook        (5) = 2170
    :ASK:::timeOfEvent(3)     = [1][0]2017-04-26T14:29:33.350
    :ASK:::price      (7)     = [1][0]16800
    :ASK:::volume     (8)     = [1][0]400
    :ASK:::levels     (10)    = [1][0]0
    :ASK:::numberOfOrders(11) = [1][0]0
>>>------------------------------------------------------------

3001=[1=258|2=1172210|3=2017-04-26T14:55:16.034|5=2170|21=[[3=2017-04-26T14:29:33.350|7=168000000|8=400000000|10=0]]|22=[[3=2017-04-26T14:55:16.034|7=121000000|8=100000000|10=0]]]
>>>MarketByLevel5Event---------------------------------------------------
subscriptionGroup(1) = 258
sequenceNumber   (2) = 1172210
timeOfEvent      (3) = 2017-04-26T14:55:16.034
sequenceIndicator(4) = 
orderBook        (5) = 2170
    :ASK:::timeOfEvent(3)     = [1][0]2017-04-26T14:29:33.350
    :ASK:::price      (7)     = [1][0]16800
    :ASK:::volume     (8)     = [1][0]400
    :ASK:::levels     (10)    = [1][0]0
    :ASK:::numberOfOrders(11) = [1][0]0
    :BID:::timeOfEvent(3)     = [1][0]2017-04-26T14:55:16.034
    :BID:::price      (7)     = [1][0]12100
    :BID:::volume     (8)     = [1][0]100
    :BID:::levels     (10)    = [1][0]0
    :BID:::numberOfOrders(11) = [1][0]0
>>>------------------------------------------------------------

3001=[1=258|2=1043350|3=2017-04-26T14:29:28.340|5=2202|21=[[3=2017-04-26T14:29:28.340|7=50000000|8=500000000|10=0]]]
>>>MarketByLevel5Event---------------------------------------------------
subscriptionGroup(1) = 258
sequenceNumber   (2) = 1043350
timeOfEvent      (3) = 2017-04-26T14:29:28.340
sequenceIndicator(4) = 
orderBook        (5) = 2202
    :ASK:::timeOfEvent(3)     = [1][0]2017-04-26T14:29:28.340
    :ASK:::price      (7)     = [1][0]5000
    :ASK:::volume     (8)     = [1][0]500
    :ASK:::levels     (10)    = [1][0]0
    :ASK:::numberOfOrders(11) = [1][0]0
>>>------------------------------------------------------------
 

























 

+ Recent posts