[C#/WPF 키움 API 자동 매매] 프로젝트 구성 (1)
조건 검색 기반으로 자동 매수 매도 프로그램을 만드는 과정을 진행 하겠습니다.
1) 이전에 진행 했던 키움 증권 API 프로젝트 와 키워드 검색에서 생성 한 프로젝트를 첨부 하였습니다.
해당 프로젝트를 가지고 진행 하겠습니다.
2) WPF 앱(.NET Framework) 으로 프로젝트 생성 EEH.WPF.UI.KIWOOM 후 EEH/EEH.WINFORM.CONTROL.KIWOOM 프로젝트를 다운받아 참조 합니다.
3) NuGet에서 ModernUI.WPF를 설치 합니다.
4) App.xaml 에 리소스 추가 합니다.
<Application x:Class="EEH.WPF.UI.KIWOOM.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EEH.WPF.UI.KIWOOM"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
<ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.Light.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
5) WindowsBase,WindowsFormsIntegration 참조 추가합니다.
EEH.WINFORM.CONTROL.KIWOOM 프로젝트는 윈폼으로 생성 되었는데 해당 프로젝트의 KHCtrl 컨트롤을 UI에 바인딩 하기 위해서 첨부 하였습니다.
6) Views 폴더 생성후 Dashboard.xaml ,AutoTrading.xaml UserControl,DashboardViewModel.cs,AutoTradingViewModel.cs 클래스 생성 합니다.
7) Model 폴더 생성후 KHStaticModel.cs 클래스 생성합니다.
키움 API 컨트롤을 Static으로 구성하여 전역에서 사용 하기 위한 클래스
using EEH.WINFORM.CONTROL.KIWOOM;
using EEH.WINFORM.CONTROL.KIWOOM.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EEH.WPF.UI.KIWOOM.APIs
{
public class KHStaticModel : BaseViewModel
{
/// <summary>
/// Static 으로 해당 인스턴스를 생성하여 전역에서 사용 할수 있게..
/// </summary>
public static KHStaticModel Instance { get; set; }
KHCtrl ocxCtrl;
/// <summary>
/// 인스턴스 생성시 키움 API를 전달 받습니다.
/// </summary>
/// <param name="ctrl"></param>
public KHStaticModel(KHCtrl ctrl)
{
ocxCtrl = ctrl;
//연결 정보 변경시 이벤트 발생 합니다.
ocxCtrl.OnChangeConnected += (isConnected) =>
{
IsConnected = isConnected;
};
//조건 검색식 불러오면 발생 합니다.
ocxCtrl.OnConditionListHandler += (conditions) =>
{
Conditions = conditions;
};
//종목이 실시간 시세를 감시 할경우 발생 합니다.
ocxCtrl.OnRealTimeStock += (stock) =>
{
if (RealTimeStockList.Count(x => x.Code == stock.Code) == 0)
RealTimeStockList.Add(stock);
};
//모든 실시간 감시가 멈출 경우 발생 합니다.
ocxCtrl.OnStopRealStock += () =>
{
RealTimeStockList.Clear();
};
}
bool isConnected;
/// <summary>
/// 키움 API 연결 여부
/// </summary>
public bool IsConnected
{
get
{
return isConnected;
}
set
{
isConnected = value; OnPropertyCanged("IsConnected");
}
}
KHAccount account;
/// <summary>
/// 계좌정보
/// </summary>
public KHAccount Account
{
get
{
return account;
}
set
{
account = value; OnPropertyCanged("Account");
}
}
ObservableCollection<KHCondition> conditions;
/// <summary>
/// 조건검색식 리스트
/// </summary>
public ObservableCollection<KHCondition> Conditions { get { return conditions; } set { conditions = value; OnPropertyCanged("Conditions"); } }
KHAccountBalance currentAccountBalance;
/// <summary>
/// 계좌 잔고 정보
/// </summary>
public KHAccountBalance CurrentAccountBalance { get { return currentAccountBalance; } set { currentAccountBalance = value; OnPropertyCanged("CurrentAccountBalance"); } }
ObservableCollection<KHStock> stockList = null;
/// <summary>
/// 종목 리스트
/// </summary>
public ObservableCollection<KHStock> StockList { get { return stockList; } set { stockList = value; OnPropertyCanged("StockList"); } }
ObservableCollection<KHStock> realTimeStockList;
/// <summary>
/// 실시간 감시중인 종목 리스트
/// </summary>
public ObservableCollection<KHStock> RealTimeStockList
{
get
{
if (realTimeStockList.ExIsNull()) realTimeStockList = new ObservableCollection<KHStock>();
return realTimeStockList;
}
set { realTimeStockList = value; OnPropertyCanged("RealTimeStockList"); }
}
ObservableCollection<KHCondition> runConditions;
/// <summary>
/// 작동중인 조건 검색식
/// </summary>
public ObservableCollection<KHCondition> RunConditions
{
get
{
if (runConditions.ExIsNull()) runConditions = new ObservableCollection<KHCondition>();
return runConditions;
}
set
{
runConditions = value; OnPropertyCanged("RunConditions");
}
}
/// <summary>
/// 로그인
/// </summary>
public void Login()
{
ocxCtrl.Login((r) =>
{
if (r)
{
LoadStockList();
LoadAccount();
}
});
}
/// <summary>
/// 자동 로그인 및 계좌 비밀번호 셋팅창을 보여줍니다.
/// </summary>
public void ShowLoginSetting()
{
ocxCtrl.ShowAutoLogin();
}
/// <summary>
/// 조건 검색식을 작동 시킵니다.
/// </summary>
/// <param name="condition"></param>
public void RunRealCondition(KHCondition condition)
{
if (ocxCtrl.RunRealCondition(condition))
{
if (RunConditions.Count(x => x == condition) == 0)
{
RunConditions.Add(condition);
}
}
}
/// <summary>
/// 조건 검색시을 멈춥니다.
/// </summary>
/// <param name="condition"></param>
public void StopRealCondition(KHCondition condition)
{
ocxCtrl.StopRealCondition(condition);
if (RunConditions.Count(x => x == condition) > 0)
{
RunConditions.Remove(condition);
}
}
/// <summary>
/// 계좌 정보를 로드합니다.
/// </summary>
public void LoadAccount()
{
Account = ocxCtrl.GetAccountInfo();
if (Account.ExNotNull() && Account.AccountBalanceList.ExNotNull() && Account.AccountBalanceList.Count > 0)
{
string accNum = Account.AccountBalanceList[0].AccountNumber;
ocxCtrl.GetAccountBalance(accNum, (accountBalance) =>
{
CurrentAccountBalance = accountBalance;
});
}
}
/// <summary>
/// 계좌리스트를 로드합니다.
/// </summary>
public void LoadStockList()
{
StockList = new ObservableCollection<KHStock>(ocxCtrl.GetStockList());
}
/// <summary>
/// 계좌의 상세 정보를 로드합니다.
/// </summary>
/// <param name="code"></param>
/// <param name="isRunRealStock"></param>
/// <param name="completedHandler"></param>
/// <returns></returns>
public bool LoadStockInfo(string code,bool isRunRealStock = true, Action<KHStock> completedHandler = null)
{
int r = ocxCtrl.GetStockInfo(code, isRunRealStock , completedHandler);
return r == 0;
}
/// <summary>
/// 실시간 시세를 작동 합니다.
/// </summary>
/// <param name="codes"></param>
public void RunRealTimeStock(List<string> codes)
{
ocxCtrl.RunRealStock(codes);
}
/// <summary>
/// 실시간 시세를 작동 합니다.
/// </summary>
/// <param name="code"></param>
public void RunRealTimeStock(string code)
{
ocxCtrl.RunRealStock(new List<string> { code });
}
/// <summary>
/// 모든 실시간 종목을 멈춥니다.
/// </summary>
public void StopAllRealTimeStock()
{
ocxCtrl.StopAllRealStock();
}
/// <summary>
/// 종목을 매수 매도 합니다.
/// </summary>
/// <param name="code"></param>
/// <param name="orderType"></param>
/// <param name="hoga"></param>
/// <param name="cnt"></param>
/// <param name="price"></param>
/// <param name="orderID"></param>
/// <param name="OnCompleted"></param>
/// <returns></returns>
public bool Order(string code, KHOrderType orderType, KHHogaGb hoga, int cnt, int price,string orderID, Action<KHOrderInfo> OnCompleted = null)
{
int r = ocxCtrl.Order(code, CurrentAccountBalance.AccountNumber, cnt, orderType, hoga, orderID, price, OnCompleted);
return r == 0;
}
}
}
8) MainWindos.xaml
<mui:ModernWindow x:Class="EEH.WPF.UI.KIWOOM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
xmlns:local="clr-namespace:EEH.WPF.UI.KIWOOM"
ContentSource="/Views/Dashboard.xaml"
xmlns:khctrl ="clr-namespace:EEH.WINFORM.CONTROL.KIWOOM;assembly=EEH.WINFORM.CONTROL.KIWOOM"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<mui:ModernWindow.MenuLinkGroups>
<mui:LinkGroup DisplayName="KIWOOM">
<mui:LinkGroup.Links>
<mui:Link DisplayName="DASHBOARD" Source="/Views/Dashboard.xaml"></mui:Link>
<mui:Link DisplayName="TRADING" Source="/Views/AutoTrading.xaml"></mui:Link>
</mui:LinkGroup.Links>
</mui:LinkGroup>
</mui:ModernWindow.MenuLinkGroups>
<WindowsFormsHost Visibility="Collapsed">
<khctrl:KHCtrl x:Name="KhCtrlApi"></khctrl:KHCtrl>
</WindowsFormsHost>
</mui:ModernWindow>
using EEH.WPF.UI.KIWOOM.APIs;
using FirstFloor.ModernUI.Windows.Controls;
namespace EEH.WPF.UI.KIWOOM
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : ModernWindow
{
public MainWindow()
{
InitializeComponent();
KHStaticModel.Instance = new KHStaticModel(KhCtrlApi);
}
}
}
이상으로 프로젝트 생성은 완료 하였습니다.
다음 시간은 대시보드(계좌정보,로그인,실시간시세,조건검색)를 만들어 보겠습니다.