해당 원글은 미디엄 블로그에서 작성한 내용을 해당 블로그에 기록하기 위해 가져옴. 원글은 2021.02.19일 작성.
개요
- 자동 투자 봇을 만들어 보려고 한다.
- 다양한 증권사 중 한국투자증권(이하 한투)으로 결정한 이유는 이미 계좌가 개설되어 있기 때문이다. 매우 단순한 이유지만 사실 모바일 API를 지원하지 않았으면 대표 적인 증권사인 키움이나 대신으로 넘어갔을지도 모른다.
- 한투의 기본 COM방식(?)은 OpenAPI 예제가 없어도 너무 없었다. 여러가지 고민을 했었는데 모바일이라면 쉽게 접근할 수 있을 것 같아서 시작해보려고 한다.
생각대로 안되면 때려 치우고 결국 새롭게 계좌 개설 하러 갈지도 모름..
참고로 한국투자증권 Rest API가 출시됨.. 해당 포스트 보러 오신분은 얼른 이 페이지에서 나가주세요.
- 그럼 처음부터 차근차근 시작해 보자.
- 전략은 간단하다. 한투 모바일 API 앱내에 Netty Framework이용하여 Http 서버를 만들고, 파이썬으로 서버에 접근하여 모바일 API를 간접적으로 호출하는 것이다.
1. 한투 모바일 API를 받아보자.
- 모바일로 써있는 건 모두 받자
2. 세가지 파일 모두 압축을 풀어보자
- 가이드 파일은 API 사용법에 대해 잘 나와있으니 계속 확인을 해야한다.
CommExpert_mobile 이라고 Open API 프로그램이 있는데 딱히 필요는 없다. 중요한 건 샘플 프로그램이다. 이 샘플 프로그램을 Android Studio로 열어보자. 아래 그림과 같은 구조의 프로그램을 확인할 수있다. CommExpert 모듈이 증권사에서 제공하는 Open API 모듈로 가장 핵심적인 부분이라고 할 수있다. OpenApiSample 모듈은 CommExpert를 이용한 간단한 앱 예제이다.
- 이 프로젝트 그대로 앱을 실행하면 매우 심플한 화면을 만날 수 있다.
- 앱이라서 여러가지 화면들로 구성되어있다.
3. 샘플 프로그램 수정
- 샘플 프로그램 그대로 사용해도 상관은 없다.
- 하지만 난 앱 내의 서버만 잘 올라가면 되기 때문에 화면구성은 메인화면을 제외하고 다 삭제해버렸다.
화면 구성 외에 다른 것들은 건드릴 필요가 없어서 그대로 두고 필요없는 것은 모두 삭제한 뒤 다시 테스트를 해본다. 그렇게 완성된 프로젝트는 아래 그림과 같다.
이렇게 완성되기까지 꽤 많은 시행착오를 거쳤다. 안드로이드 프로그래밍 숙련자라면 쉽게 완성할 수 있을 것이다.
- 간단히 만든 예제
- 참고로 그냥 시작하면 공인인증서 파일이 없다는 알럿이 뜬다. 에뮬내에 공인인증서를 넣어주면 해결될 것 같지만 에뮬레이터에선 잘 안되니 테스트용도로만 사용하자. 실제 안드로이드 폰에 설치해서 확인해본 결과 공인인증서만 잘 넣어놓으면 공인인증서 로그인도 잘 된다. 사고 팔고 하려면 필요하니 로그인 할 수 있도록 하자.
몰랐는데 안드로이드 sdcard 디렉토리를 보면 NPKI 디렉토리가 친절하게 잘 구성되어 있더라…
4. Netty 서버 구축
- 앱이 로딩이 되면 서버가 바로 시작되어야하기 때문에 적절한 곳에 서버 시작 프로세스를 추가했다.
1
2
3
4
5
6
7
8
@Override
public void onInitFinished() {
// TODO Auto-generated method stub
Toast.makeText(this, "초기화 성공", Toast.LENGTH_SHORT).show();
StartServer startServer = new StartServer();
startServer.startServer();
- CommExpertMng가 초기화 되고 로그인 시작 전에 서버 시작한다.
- Netty Http 서버는 github 예제에서 그대로 가져와 사용했다.(netty 사랑합니다.)
- Port는 전세계 기본 port 8080
- 서버가 구동되고 adb port forward를 통해 8080 port를 연결한뒤 127.0.0.1:8080에 접속하면 Hello world를 만날 수 있다.
안녕 월드
5. Netty SimpleChannelInboundHandler
- Netty가 중요한게 아니니 간단히 어떻게 활용했는지만 작성해본다.
SimpleChannelInboundHandler를 상속받은 Class를 확인해보자
- HttpRequest가 중요하다.
- HttpRequest Class를 확인해보면 uri를 받아올 수 있는데 이걸 활용하여 apiName과 parameter를 구분할 것이다.
- 예를 들면 127.0.0.1:8080/getAccountNo/1 이런식으로 호출하면 getAccountNo가 apiName이고 1을 parameter로 활용하는것이다.
- apiName으로 필요한 요청을 구분하고 요청에 필요한 parameter를 전달한다. 간단하게 enum으로 작성해 봤다.
일단 무식하게 짠 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
HttpRequest req = (HttpRequest) msg;
Log.d(TAG, "uri : " + req.uri());
ApiCommand apiCommand = null;
String params = "";
String mainUri = StringUtils.substring(req.uri(), 1);
if (StringUtils.isNoneBlank(mainUri)) {
String[] paramList = mainUri.split("/");
if (paramList.length == 1) {
apiCommand = ApiCommandFactory.INSTANCE.getApiCommand(paramList[0]);
} else if (paramList.length == 2) {
apiCommand = ApiCommandFactory.INSTANCE.getApiCommand(paramList[0]);
params = paramList[1];
}
}
String result = "no Result";
if (apiCommand != null) {
if (StringUtils.isNoneBlank(params)) {
result = apiCommand.getResult(params.split(","));
} else {
result = apiCommand.getResult(params);
}
}
Log.d(TAG, "api result : " + result);
ApiCommand Enum
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public enum ApiCommand {
AccountSize("getAccountSize") {
@Override
public String getResult(String... params) {
int nCount = CommExpertMng.getInstance().GetAccountSize();
return String.valueOf(nCount);
}
},
AccountNo("getAccountNo") {
@Override
public String getResult(String... params) {
String index = params[0];
String strAcc = CommExpertMng.getInstance().GetAccountNo(Integer.parseInt(index));
return strAcc;
}
},
AccountCode("getAccountCode") {
@Override
public String getResult(String... params) {
String index = params[0];
String strAccCode = CommExpertMng.getInstance().GetAccountCode(Integer.parseInt(index));
return strAccCode;
}
},
AccountName("getAccountName") {
@Override
public String getResult(String... params) {
String index = params[0];
String strAccName = CommExpertMng.getInstance().GetAccountName(Integer.parseInt(index));
return strAccName;
}
};
}
- api가 추가될 수록 enum 클래스 내용이 길어지겠지만, 딱히 유지보수 할 내용도 없고 해서 간단하게 가려고 한다.
테스트로 호출해보니 잘 돌아간다.
계좌 2개 잘있음
- favicon.ico는 브라우저에서 테스트를 해서 그런 것 같고 앞으로 파이썬에서 테스트 하면 호출 안될 것 같다.
그래서 앞으로의 과제는
- 응답을 text/plain으로 보내고 있는 부분을 application/json으로 바꾸기
- 필요한 api 모두 등록하기
- 파이썬에서 호출 테스트 해보기
마무리
- 이렇게만 완성하면 본격적으로 파이썬을 이용한 자동 투자 봇을 만들 수 있을 것 같다.
- 여기까지 만드는 데 퇴근 후 짬짬히 시간내어 3~4일정도 걸린 것 같은데 앞으로 파이썬 공부하면서 완성하려면 정말 긴 여정이 될 것 같다… 일 때려치우고 여기에 매달릴 수도 없고 ㅠ
- 찬찬히 진행해서 2탄으로 등장할 수 있도록 하자!