모든 프로그램들은 Call Flow가 존재하며, 사용자 지향적인 프로그램일수록 사용자가 어떻게 프로그램을 사용해 나갈지, 예를 들면, 로그인부터 해서 특정 기능을 사용하기 위해 어떤 것들을 설정해야 하며, 얻어낸 결과를 어떻게 저장하고 프로그램을 종료하는지까지의 시나리오가 존재한다.
프로그램 제작 전에 완성된 내용이지만, 나중에 사용자 매뉴얼 작성 시에 도움이 될 수 있도록 지금 기록을 해놓는 게 좋을 것 같다. 물론 Flow Chart 기반의 시나리오 정리이며, 필요할 경우 지속적으로 업데이트될 것이다.
L-ATS 사용자 시나리오
실은 어떤 프로그램이든 사용자 관점에서 정의하는 시나리오는 복잡하지 않다.
사용자는 프로그램의 기능이 직관적이며 단순해야(단순하다는 어감이 조금 좋지 않은데 Simple하다가 의도하는 바와 가까운 단어다.) 잘 사용하게 된다.
개발자라면 잘 알겠지만 단순해 보이는 하나하나의 과정마다 수가지의 예외처리와 백그라운드 프로세스 작업이 존재한다는 것을 알 것이다.
사용자의 시선에서는 당연히 신경 쓸 필요 없다. 모든 기능이 오류 없이 정상적으로 처리되어야 하니 말이다.
즉, 위의 시나리오는 프로그램의 모든 기능이 정상적일 때의 시나리오이다.
설계된 L-ATS 2.0의 기능은 크게 4가지로 구분된다.
이베스트 증권 계좌 선택
스탑로스 조건 설정
자동 매매 시작
종목별 처리할 스탑로스 종류 선택
실제론 대부분의 자동매매 프로그램들이 1.~3.번 기능이 전부이다. 2.번 기능이 프로그램마다의 특징을 갖는 기능이며, 자동으로 매수하는 기능이 있는 프로그램도 있다. (L-ATS 1.0에도 존재했던 기능이나 2.0에서는 스탑로스만...)
기능 자체는 간단해 보이지만, 돈이 왔다갔다하는 프로그램이기에 얕은 지식으로 간단하게 만들 수 있는 프로그램의 종류는 아니다.
기능 구현보다 Exception 처리에 더 많은 공을 들여야 한다.
사용자는...더구나 GUI 환경에서의 사용자는 개발자가 예측하지 못한 돌발 행동을 많이 한다.
새로운 클래스 파일(.cs)의 객체에 저장한 후에 그 값을 읽어와서 출력하는 방법으로 진행해 보자.
오른쪽 솔루션 탐색기에서 프로젝트 명의 오른쪽 클릭 후 [ 추가(D) ] - [ 새 항목(W) ]을 선택한다.
클래스를 선택 후에 입력할 사용자 정보를 관리할 'User_Info.cs' 파일을 추가한다.
User_Info Class는 ID와 Password, 두 개의 변수를 갖고, 각각의 값을 Set/Get하는 함수를 갖게 될 것이다.
ID와 비밀번호는 사용하는 Class에서 직접 접근할 수 없도록 'private' 접근 제한자를 사용하고, 각각의 값을 Handling 할 수 있는 'public' 함수를 만들어 사용할 수 있도록 한다. (이게 객체지향 방법이라는데...나는 익숙치 않아서....Anyway)
[ User_Info.cs ]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace delegate_test
{
class User_Info
{
private string Id; // 사용자 ID
private string Password; // 사용자 비밀번호
// 생성자
public User_Info()
{
Id = string.Empty;
Password = string.Empty;
}
public void SetId(string Id)
{
this.Id = Id;
}
public string GetId()
{
return this.Id;
}
public void SetPassword(string Password)
{
this.Password = Password;
}
public string GetPassword()
{
return this.Password;
}
}
}
참고로 나는 변수의 초기화를 굉~~장히 중요하게 생각하는 개발자다. (생성자에서 변수 초기화는 무조건 필수!!)
이제 User_Info Class를 어떻게 사용하는가...
두 가지의 방법이 있는데, 하나는 User_Info Class 내에 static 객체를 하나 생성해두고 다른 곳에서 호출해서 쓰는 방식이고 다른 하나는 User_Info Class를 사용할 곳에서 객체를 직접 생성해서 사용하는 방식이 있다.
< 방법 1> - Static 객체
[User_Info.cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace delegate_test
{
class User_Info
{
// static 객체
public static User_Info gUser_Info = new User_Info();
private string Id; // 사용자 ID
private string Password; // 사용자 비밀번호
// 생성자
public User_Info()
{
Id = string.Empty;
Password = string.Empty;
}
public void SetId(string Id)
{
this.Id = Id;
}
public string GetId()
{
return this.Id;
}
public void SetPassword(string Password)
{
this.Password = Password;
}
public string GetPassword()
{
return this.Password;
}
}
}
어디서든 접근 가능하도록 public으로 만든 static 객체를 만들어 둔다.
사용하는 방법은 간단하다.
User_Info 객체를 사용하고 싶은 곳에서 [클래스명].[객체명].[함수/변수]와 같은 형태로 사용하면 된다.
[Form1.cs]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace delegate_test
{
public delegate void LoginGetEventHandler(string id, string password); // 자식 Form EventHandler
public partial class Form1 : Form
{
static string static_id = "brandon";
Form2 Child = new Form2(static_id);
public Form1()
{
InitializeComponent();
Form2.LoginGetEvent += new LoginGetEventHandler(this.Login_Process); // EventHandler 등록
}
private void 로그인ToolStripMenuItem_Click(object sender, EventArgs e)
{
Child.Owner = this;
Child.ShowDialog();
}
private void Login_Process(string id, string password) // Event 발생 시, 처리할 함수 선언
{
// User_Info 객체에 입력 받은 정보 저장
User_Info.gUser_Info.SetId(id);
User_Info.gUser_Info.SetPassword(password);
// User_Info 객체에서 값 가져오기
string test_result = string.Empty;
//test_result = String.Format("ID : {0}, PW : {1}", id, password);
test_result = String.Format("ID : {0}, PW : {1}", User_Info.gUser_Info.GetId(), User_Info.gUser_Info.GetPassword())
textBox1.Text = test_result; // 자식 Form에서 수신한 값 표시
}
}
}
전과 동일하게 아이디랑 비밀번호가 출력되면 정상적으로 User_Info Class를 사용하는 셈.
사용자 정보의 경우, 프로그램내에서 단 하나만(!) 존재하는 것이기에 위의 예제처럼 static 객체로 선언해서 쓰는것이 좋을 것 같다. 상황에 따라 여러개의 객체가 필요한 경우는 아래처럼 사용하면 된다.
[Form1.cs]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace delegate_test
{
public delegate void LoginGetEventHandler(string id, string password); // 자식 Form EventHandler
public partial class Form1 : Form
{
// User_Info 객체 생성
User_Info gUser_Info = new User_Info();
static string static_id = "brandon";
Form2 Child = new Form2(static_id);
public Form1()
{
InitializeComponent();
Form2.LoginGetEvent += new LoginGetEventHandler(this.Login_Process); // EventHandler 등록
}
private void 로그인ToolStripMenuItem_Click(object sender, EventArgs e)
{
Child.Owner = this;
Child.ShowDialog();
}
private void Login_Process(string id, string password) // Event 발생 시, 처리할 함수 선언
{
// User_Info 객체에 입력 받은 정보 저장
gUser_Info.SetId(id);
gUser_Info.SetPassword(password);
// User_Info 객체에서 값 가져오기
string test_result = string.Empty;
//test_result = String.Format("ID : {0}, PW : {1}", id, password);
test_result = String.Format("ID : {0}, PW : {1}", gUser_Info.GetId(), gUser_Info.GetPassword());
textBox1.Text = test_result; // 자식 Form에서 수신한 값 표시
}
}
}
앞서 말한바와 같이 이베스트의 XingAPI는 서버 연결과 HTS 연결이 별로도 동작한다.
때문에 L-ATS 프로그램을 사용하기 위해서는 아래 두 가지 로그인 절차를 거치게 설계했다.
Step 1. L-ATS 프로그램 로그인
Step 2. 이베스트 HTS 로그인
번거로울 수 있을 것이라 생각할 수도 있겠지만, 이베스트 XingAPI의 로그인 구조와
내가 추구하는 (아무나 내프로그램을 사용할 수 없는...?) 방향과 딱 맞아 떨어졌다 생각할 수 있겠다.
지난 '두번째 프로그램' 초기화면 설계와 조금 달라진 모습을 볼 수 있다.
우선, 프로그램 실행과 동시에 'L-ATS 로그인' 화면을 제공하여 프로그램 사용자 로그인과 동시에
이베스트 HTS 서버 연결을 선택하도록 했다. (덕분에 프로그램 사용자 정보도 관리해야할 것 같다.)
먼저 구현된 각 화면의 표시 정보를 보자. (기능이 구현되는 순으로 계속 설명을 써야겠다.)
사용자 정보 : L-ATS 등록 사용자 정보
HTS : 실시간 이베스트 HTS 연동 상태 표시. 빨 : Disconnect, 녹 : Connected.
시작 버튼 : HTS 로그인 후 계좌를 선택해야 하므로, ATS의 모든 기능은 이 버튼이 눌린 시점부터 시작된다.
알림 : 프로그램에서 Event 발생 시, 텍스트로 표시해 준다. (예] 로그인, 매수, 매도 등)
하단 Status Bar : 이베스트 HTS 사용자 정보 표시
우선 로그인을 해보자.
내 계정은 이미 등록이 되어 있는 상태이며, 추후 사용자 관리관련 포스팅 예정이다.
그리고 로그인 버튼을 누르면 다음과 같은 L-ATS 시작 화면이 된다.
L-ATS 프로그램 사용자의 정보가 왼쪽 상단에 표시되고, 실시간 이베스트 HTS 접속 상태가 'HTS' 부분에 빨간색->초록색으로 표시가 된다. '모의투자'를 선택했을 경우 '모투', '실투자'를 선택했을 경우 '실투'라고 표시된다.
그리고 '알림' 부분에 현재 발생한 로그인 이벤트에 대한 내용이 표시된다.
여기까지는 아직 이베트스 HTS에 로그인 하긴 전 상태라 계좌정보, 자산현황 등을 알 수 없다. (다음 게시물 예정.)
자동 매매 프로그램에 있어서 HTS 연결은 매우 중요하다.
정전, 네트워크 장애 등등. 어떠한 이유에 있어 프로그램이 돌아가고 있는 상태에서 HTS 연결만 끊기는 경우가 발생할 수 있으므로, HTS 연결 상태를 지속적으로 확인(Heart-Beat)하고 재연결(Reconnect)를 할 수 있도록 개발해야하는 것이 기본이다. 이건 Database 서버와의 연결도 마찬가지이다.
L-ATS v1.0 때보다 많은 기능이 설계에 들어가고 있어...매우 정신이 없다...
그래도 재밌는걸 어떡하나 싶다...
만들다보니 회원가입 절차가 필요해져서 '비밀번호'는 당연히 입력 즉시(나도 알 수 없도록) 암호화하여 DB에 저장하도록 해야겠다 생각했지만, 이베스트 XingAPI 특징상 HTS 로그인시에 아이디/비번/공인인증서비번을 입력 받도록 되어있다.
보안에 굉장히 취약할 수도 있는 부분이라 이 부분을 어떻게 해야 사용자들이 안심하고 사용할 수 있을지 고민이다.