본문 바로가기
대충 만들면서 배우자/자동 매매 (키움 API)

[C#/WPF 키움 API 자동 매매] 프로젝트 구성 (1)

by 프갭 2023. 4. 12.

조건 검색 기반으로 자동 매수 매도 프로그램을 만드는 과정을 진행 하겠습니다.

 

1) 이전에 진행 했던 키움 증권 API 프로젝트 와 키워드 검색에서 생성 한 프로젝트를 첨부 하였습니다.

해당 프로젝트를 가지고 진행 하겠습니다.

EEH.zip
0.09MB
EEH.WINFORM.CONTROL.KIWOOM.zip
0.41MB

 

 

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);
        }
    }
}

 

이상으로 프로젝트 생성은 완료 하였습니다.

다음 시간은 대시보드(계좌정보,로그인,실시간시세,조건검색)를 만들어 보겠습니다.

반응형

댓글