NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 팁 앤 테크
  • 매뉴얼

    팁과 테크니컬 노하우를 확인하세요.

    팁 앤 테크

    팁과 테크니컬 노하우를 확인하세요.

    본 사이트의 컨텐츠는 저작권법의 보호를 받으므로 무단 복사, 게재, 배포 등을 금합니다.

    커스텀 주식, 선물, 비트 코인 시세 분석 커스텀 매크로 만들기. (특정 시간 동안 최대값, 최소값, 평균등등... 통계적 접근 및 …

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 오늘은 사용자가 설정한 시간동안~ 주식, 선물 또는 코인과 같은 시세(호가)를 수집해서 최대값과 최소값을 어떻게 수집하는지 알아보도록 하겠습니다. 웹 API를 사용해도 되지만, 이번에는 OCR 기능을 이용해서 만들었습니다. 또한, 엔지엠 매크로에 있는 [ OCR 체크(문자 판독기) ] 액션을 이용해서 처리해도 됩니다. 커스텀 모듈로 만든 이유는 간단합니다. 최대한의 퍼포먼스를 뽑아내기 위함인데요. 시시각각 변화하는 시세를 놓치면 안되기 때문입니다. 아래는 1분간 수집한 데이타입니다.

    DtdlwUi.gif

     

     

    ①1분동안 총 702회 문자를 판독했습니다. ②중복을 제거하고 7번 변동이 있었습니다. 변동 값 중에 최대값은 ③74,153,000원이고 최소값은 ④74,065,000원입니다.

    cwOWm8u.png

     

     

    현재는 최대값과 최소값만 뽑아봤지만 소스상에서 여러가지 통계를 적용해서 사용하시면 됩니다. 커스텀 모듈을 만들기 위해 Visual Studio를 실행하고, 라이브러리 프로젝트를 추가하세요. 그리고, 엔지엠 커스텀 모듈 개발 라이브러리를 참조에 추가하세요. 자세한 내용은 [ 커스텀 모듈 만들기 ] 예제를 처음부터 읽어보시면 됩니다. 익숙해지면 그렇게 어렵지는 않을거예요^^; 아래와 같이 using을 추가 해줍니다.

    using NGM.Interface;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Linq;

     

    아래 그림을 참고해서 모듈 참조도 추가 해주세요. (실제 참조 관련 내용은 커스텀 모듈 만들기 예제 참고)

    aN3pHax.png

     

     

    대부분의 예제가 도구 상자에 추가할 수 있는 커스텀 모듈이었습니다. 하지만, 이번에는 여러가지 엔지엠의 공통 기능을 사용해야 하기 때문에 함수 상자 커스텀으로 만들어야 합니다. 아래와 같이 NGM.Models.Interface.BaseCustomFunctionModel을 상속 받고, 구현하세요.

    namespace CustomMinMaxNumber
    {
        [Serializable]
        public class MinMaxValueModel : NGM.Models.Interface.BaseCustomFunctionModel
        {

     

    BaseCustomFunctionModel의 추상 프로퍼티와 메소드를 추가하세요.

            /// <summary>
            /// 도구 상자에 표시될 카테고리 이름을 가져옵니다.
            /// </summary>
            public override string DisplayCategory => "NGMsoftware";
    
            /// <summary>
            /// 도구 상자에 표시될 액션 이름을 가져옵니다.
            /// </summary>
            public override string DisplayName => "최대값 최소값 추출";
    
            public override void Execute(IMainView mainView, IPlayer player)
            {
            }

     

    여러가지 옵션을 사용자에게 제공해야 하기 때문에 필요한 프로퍼티들을 추가했습니다. 설명들이 적혀있으니 이해하는데 어려움은 없을겁니다^^;

    /// <summary>
            /// 최대값 최소값을 계산하기 위해 데이터를 수집하는 시간입니다.
            /// </summary>
            [Category("Action")]
            [DisplayName("수집 시간")]
            [Description("최대값 최소값을 계산하기 위해 데이터를 수집하는 시간입니다. (단위: 초)")]
            [Browsable(true)]
            [DefaultValue(60)]
            public int CollectionTime { get; set; } = 60;
    
            [Category("Action")]
            [DisplayName("모델 선택")]
            [Description("문자 판독에 사용되는 모델을 선택합니다.")]
            [Browsable(true)]
            [DefaultValue(typeof(NGM.Definition.OcrModel), "Normal")]
            public NGM.Definition.OcrModel ModelOption { get; set; } = NGM.Definition.OcrModel.Normal;
    
            [Category("Action")]
            [DisplayName("OCR 영역")]
            [Description("OCR 문자 판독 영역을 설정하세요.")]
            [Browsable(true)]
            [DefaultValue(typeof(System.Drawing.Rectangle), "0,0,0,0")]
            [Editor(typeof(NGM.Models.TypeEditor.AreaCaptureEditor), typeof(System.Drawing.Design.UITypeEditor))]
            public Rectangle SearchArea { get; set; }
    
            [Category("Data")]
            [DisplayName("최대값")]
            [Description("판독한 숫자에서 가장 큰 값을 표시합니다.")]
            [Browsable(true)]
            [DefaultValue(0)]
            [ReadOnly(true)]
            public double Max { get; set; }
    
            [Category("Data")]
            [DisplayName("최소값")]
            [Description("판독한 숫자에서 가장 작은 값을 표시합니다.")]
            [Browsable(true)]
            [DefaultValue(0)]
            [ReadOnly(true)]
            public double Min { get; set; }
    
            [Category("Data")]
            [DisplayName("인식 횟수")]
            [Description("문자 판독 인식 횟수입니다.")]
            [Browsable(true)]
            [DefaultValue(0)]
            [ReadOnly(true)]
            public int Count { get; set; }
    
            [Category("Data")]
            [DisplayName("인식 숫자 목록")]
            [Description("OCR 문자 판독으로 읽은 숫자의 목록입니다. (중복 제거)")]
            [Browsable(true)]
            [DefaultValue(null)]
            public List<double> Numbers { get; set; } = new List<double>();

     

    가장 중요한 핵심 코드는 아래와 같습니다.

            public override void Execute(IMainView mainView, IPlayer player)
            {
                if (SearchArea.IsEmpty)
                {
                    mainView.WriteOutput("필수 입력값이 누락되었습니다. OCR 영역을 선택하세요.");
                    return;
                }
    
                Image Target = null;
    
                if (Numbers == null)
                    Numbers = new List<double>();
                else
                    Numbers.Clear();
    
                Count = 0;
    
                var checkTime = DateTime.Now.AddSeconds(CollectionTime);
    
                while (checkTime > DateTime.Now)
                {
                    Count++;
    
                    if (player.MainHandle == IntPtr.Zero)
                        Target = NGM.Utility.ScreenCaptureManager.ScreenShot.GetActiveImage(SearchArea, player);
                    else
                        Target = NGM.Utility.ScreenCaptureManager.ScreenShot.GetInactiveImage(player, ControlWindowRectangle, SearchArea, true);
    
                    if (Target == null)
                        continue;
    
                    string number = NGM.Utility.OCRManager.Converter.ImageToText(
                        (Image)Target.Clone(), 
                        NGM.Definition.Language.English, 
                        ModelOption,
                        NGM.Definition.TesseractEngine.Default,
                        NGM.Definition.PageSegMode.SingleBlock, 
                        false, 
                        null,
                        null);
    
                    Target?.Dispose();
                    Target = null;
    
                    if (!string.IsNullOrEmpty(number) && double.TryParse(System.Text.RegularExpressions.Regex.Replace(number, @"[^0-9.]", ""), out double n))
                    {
                        if (!Numbers.Contains(n))
                            Numbers.Add(n);
                    }
                }
    
                if (Numbers.Count > 0)
                {
                    Max = Numbers.Max();
                    Min = Numbers.Min();
                }
            }

     

    기본적인 사용 방법은 OCR 체크와 비슷합니다. 숫자를 인식할 범위를 선택하고, 해당 범위의 이미지를 문자로 변환해줍니다. 엔지엠 에디터 또는 플레이어, 커스텀등등 성능 테스트 자료를 참고하시면 왜 커스텀을 사용해야 하는지 이해할 수 있을겁니다. 속도가 중요한 작업의 경우 하나씩 액션으로 처리하기에는 무리가 많습니다. 각각의 액션이 실행 전과 실행 후 처리해야 할 내용들이 많기 때문입니다. 커스텀은 이런 부분들을 제거하고, 필요한 부분만 최적화해서 사용할 수 있습니다. 많은 장점이 존재하지만~ 러닝 커브가 커서 아무나 쉽게 할수는 없죠^^;

     

    [ 커스텀 모듈 다운로드 ]

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.