사용자 매뉴얼 / 4. 스크립트 작성을 위한 C#

4. 스크립트 작성을 위한 C# 

와이즈 트레이딩 룸 스크립트 작성을 위한 C# 기본 강좌입니다. 프로그래밍 경험이 전혀 없는 사람이 스크립트를 작성하기 위해 필요한 만큼의 수준과 내용으로 설명합니다.


4.1 C#의 이해 

C#

  • C#은 마이크로소프트가 만든 프로그래밍 언어입니다. 주로 MS 윈도우에서 실행되는 프로그램을 개발할 때 사용하는 언어로 C나 C++ 보다 느리지만 파이썬이나 Java 등의 언어보다 빠른 프로그램을 개발할 수 있습니다.
  • 코드가 실행될 때마다 컴파일(인터프리팅)하는 파이썬 대비 C#은 한번의 컴파일로 실행 코드가 생성되는 언어적 특성성 대량 종목의 탐색과 초단타 매매에 강점이 있습니다.
  • C#은 객체지향 언어입니다.

객체

  • C#을 이용한 객체지향 프로그래밍에서 객체는 데이터(속성 및 필드)와 함수(메소드)를 모두 가지고 있습니다. 와이즈 트레이딩 룸이 제공하는 데이터(탐색종목, 시장, 일봉_0봉전, N분봉_1봉전 등)들도 객체형입니다.

if문

  • 모든 언어는 기본적으로 조건에 따른 실행이라는 로직을 구현하기 위해 if문과 같은 선택문이 있습니다. 와이즈 트레이딩 룸의 스크립트 또한 매매 조건에 따른 주문을 실행하는 로직 형태이기 때문에 if문을 사용하여 스크립트를 작성합니다.
  • if문은 다음과 같은 형태로 작성합니다.
    // if 문
    if (조건)
    {
      // 조건이 참(true)일 경우 실행되는 코드 작성
    }
    // if else 문
    if (조건)
    {
      // 조건이 참(true)일 경우 실행되는 코드 작성
    }
    else
    {
     // 조건이 거짓(false)일 경우 실행되는 코드 작성
    }
    // if else if 문
    if (조건1)
    {
      // 조건1이 참(true)일 경우 실행되는 코드 작성
    }
    else if (조건2)
    {
     // 조건1이 거짓(false)이고, 조건2가 참(true)일 경우 실행되는 코드 작성
    }
    else
    {
     // 조건1과 조건2가 모두 거짓(false)일 경우 실행되는 코드 작성
    }

상수와 변수

  • 로직을 작성하기 위해서는 다양한 데이터 값을 참조하고 계산해야 하기 때문에 고정된 값을 갖는 상수와 계산된 값을 저장할 수 있는 변수가 필요합니다.
  • 변수를 사용하기 위해서는 먼저 변수를 선언해야 합니다. 먼저 선언하는 이유는 컴파일러가 어떤 데이터값을 코드에서 사용할지 미리 알아서 저장공간을 확보하거나 코드가 정확히 데이터를 사용하는지 검증하기 위해서입니다.
  • C#에서 변수를 선언하려면 int, double, string 등 데이터 타입으로 명시적 선언하는 방법과 var를 이용하여 암묵적으로 선언하는 방법이 있습니다.
  • var를 이용해서 변수를 선언하려면 변수에 초기값을 대입해서 데이터 타입을 컴파일러가 알 수 있게 해야 합니다.
  • 변수명은 한글도 가능하지만 특수문자나 숫자로 시작할 수 없는 제약들도 있습니다.

세미콜론(;)

  • C#에서 모든 문장의 끝에는 세미콜론(;)을 사용해야 합니다.

주석

  • 긴 로직을 작성하려면 코드에 대한 설명이 필요할 수 있습니다. 이런 경우 C#에서는 한줄 주석(// 주석내용)과 여러줄에 대한 주석(/* 주석내용 */)을 사용할 수 있습니다.

4.2 간단한 C# 프로그램 작성 

이번 장에서는 간단한 C#을 작성해 보고 실행해 보겠습니다. C#에 대한 교육보다는 스크립트 작성에 목적이 있기 때문에 이와 관련하여 설명합니다.

Hello World

  • 프로그램의 시작 지점 Main()은 전체 코드상에 단 하나만 존재해야 합니다.
  • Main()은 임의의 public 클래스안에 static으로 선언되어야 합니다.
using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
    }
}

위의 코드에 사용자는 주석을 이용하여 아래와 같이 설명을 작성할 수 있습니다.

/* 
첫번째 프로그램:
화면에 Hello World를 출력하는 프로그램
*/

// System 네임스페이스에는 코드에서 사용하고 있는 Console 클래스와 같은 기본적인 클래스들이 정의되어 있습니다. 
// 코드에서 전체 네임스페이스를 지정하면 번거롭기 때문에 using을 사용하여 네임스페이스를 선언합니다.
// 모든 문장의 끝은 세미콜론(;)입니다.

using System;

// Main이 들어 있는 Program 클래스는 외부에서 보여지도록 public 클래스로 선언해야 합니다.        
public class Program
{

  // Main()도 public으로 선언해서 외부에 보여지도록 해야 합니다.
  // static은 정적 선언자로 Main()이 초기화시 한번 생성되어 동일 메모리를 사용하도록 합니다.
  // void는 Main()이 리런값이 없다는 의미입니다.
    public static void Main()
    {
    // Console 클래스안에 화면에 문자열을 줄단위로 출력하는 WriteLine 메소드가 있습니다.
        Console.WriteLine("Hello World");
    }
}

온라인 컴파일러 서비스를 이용하면 C# 코드를 테스트해 볼 수 있습니다. - 피들러 온라인 컴파일러 서비스

와이즈 트레이딩 룸의 스크립트는 독립적으로 실행되는 프로그램이 아니고 호출되는 코드이기 때문에 Main()이나 메소드(함수)명이 필요없습니다.


4.3 변수와 if문 사용하기 

기본 C# 프로그램에서 변수와 if문을 사용해 보는 예제입니다.

using System;

public class Program
{
    public static void Main()
    {
    bool a;
    int b;
    int c;

    b = 100;
    c = 50;

    if ( b > c)
    {
      a = true;
    }
    else
    {
      a = false;
    }

    if (a)
      Console.WriteLine("b가 c보다 크다");
    else
      Console.WriteLine("b가 c보다 크지 않다");
    }
}

아래는 var를 이용한 변수 선언 예제입니다. var로 선언할 때에는 초기값도 같이 정해줘야하고, 이 초기값에 따라서 컴파일러가 데이터 타입을 정하게 됩니다.

using System;

public class Program
{
    public static void Main()
    {
    var a = false;
    var b = 100;
    var c = 50;

    if ( b > c)
    {
      a = true;
    }

    if (a)
      Console.WriteLine("b가 c보다 크다");
    else
      Console.WriteLine("b가 c보다 크지 않다");
    }
}

4.4 리스트 사용하기 

일봉이나 분봉 등의 주가 데이터는 시가, 고가, 저가, 종가 등의 데이터를 시간에 따라 저장한 형태입니다. 이런 시계열 데이터를 저장하는데 적합한 자료구조가 리스트형입니다. 와이즈 트레이딩 룸의 차트 데이터를 직접 가공하여 사용하려면 리스트 자료형에 대한 이해가 필요합니다.

아래는 리스트 객체를 만들어서 테스트 데이터를 생성해 보는 예제입니다. 참고로, 예제 실행하기를 눌러서 직접 코드를 작성해 보고 수정할 수 있습니다.

using System;
using System.Collections.Generic;


public class Program
{
    public static void Main()
    {
        List<주가> stockList = new List<주가>();        

        stockList.Add(new 주가(){일자="20200101",시가=1000,고가=1500,저가=800,종가=900,거래량=10000});
        stockList.Add(new 주가(){일자="20200102",시가=900,고가=1500,저가=800,종가=1100,거래량=15000});
        stockList.Add(new 주가(){일자="20200103",시가=1000,고가=1200,저가=500,종가=800,거래량=12000});

        foreach (var item in stockList)
            Console.WriteLine("일자:{0}, 시가:{1}, 고가:{2}, 저가:{3}, 종가:{4}, 거래량:{5}", item.일자, item.시가, item.고가, item.저가, item.종가, item.거래량);    
    }
}

public class 주가
{
    public string 일자 {get; set;}    
    public int 시가 {get; set;}
    public int 고가 {get; set;}
    public int 저가 {get; set;}
    public int 종가 {get; set;}
    public int 거래량 {get; set;}  
}

예제 실행해 보기


4.5 LINQ와 람다식을 이용한 리스트 처리

스크립트를 이용하여 매매 전략을 구현하다 보면, 사용자가 직접 차트나 체결 데이터 등을 처리해야할 경우가 있습니다. 이럴 경우 C#의 LINQ와 람다식 조합을 이용하면 간단히 구현할 수 있습니다.

LINQ는 리스트의 연산을 쉽게하기 위해 추가로 제공되는 집계함수로 이해하시면 됩니다.

람다식은 람다 연산자(=>)로 이름 없는 메소드를 간결히 표현한 식(expression)입니다. 아래와 같은 형태로 작성됩니다.

(input-parameters) => expression

아래 예제에 보면, 리스트 자료형의 메소드, Count, Sum, Average 등의 입력값으로 람다식을 사용한 것을 볼 수 있습니다. 참고로 예제의 람다식 파라메터는'w'를 사용했는데 어떤 문자로도 상관 없습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using MoreLinq;

public class Program
{
    public static void Main()
    {
        // 일봉 테스트 데이터 생성
        List<주가> _일봉차트 = new List<주가>();        

        _일봉차트.Add(new 주가(){일자="20200101",시가=1000,고가=1500,저가=800,종가=900,거래량=10000});
        _일봉차트.Add(new 주가(){일자="20200102",시가=900,고가=1500,저가=800,종가=1100,거래량=15000});
        _일봉차트.Add(new 주가(){일자="20200103",시가=1000,고가=1200,저가=500,종가=800,거래량=12000});
        _일봉차트.Add(new 주가(){일자="20200104",시가=800,고가=1500,저가=800,종가=900,거래량=20000});
        _일봉차트.Add(new 주가(){일자="20200105",시가=1200,고가=1200,저가=500,종가=800,거래량=22000});

        // 생성된 일봉 데이터 확인
        Console.WriteLine("일봉 데이터");
        Console.WriteLine("------------------------------------------------------------------------------------");
        foreach (var item in _일봉차트)
            Console.WriteLine("일자:{0}, 시가:{1}, 고가:{2}, 저가:{3}, 종가:{4}, 거래량:{5}", item.일자, item.시가, item.고가, item.저가, item.종가, item.거래량);

        Console.WriteLine("------------------------------------------------------------------------------------");
        Console.WriteLine();

        // 일봉 데이터 개수 구하기
        var _개수 = _일봉차트.Count();
        Console.WriteLine("개수:{0}", _개수);   

        // 시가 1000이상 개수 구하기
        var _개수_시가1000이상 = _일봉차트.Count(w => w.시가 >= 1000);
        Console.WriteLine("시가 1000이상 개수:{0}", _개수_시가1000이상);                

        // 거래량 합계 구하기
        var _합계_거래량 = _일봉차트.Sum(w => w.거래량);
        Console.WriteLine("거래량 합게:{0}", _합계_거래량);               

        // 거래량 평균 구하기
        var _평균_거래량 = _일봉차트.Average(w => w.거래량);
        Console.WriteLine("거래량 평균:{0}", _평균_거래량);               

        // 최근 2일 거래량 합계 구하기
        var _합계_거래량_최근2일 = _일봉차트.Skip(_일봉차트.Count - 2).Sum(w => w.거래량);
        Console.WriteLine("최근 2일 거래량 합게:{0}", _합계_거래량_최근2일);                

        // 최근 3일 거래량 평균 구하기
        var _평균_거래량_최근3일 = _일봉차트.Skip(_일봉차트.Count - 3).Average(w => w.거래량);
        Console.WriteLine("최근 3일 거래량 평균:{0}", _평균_거래량_최근3일);                

        // 최근 3일 최고 종가 구하기
        var _최고종가_최근3일 = _일봉차트.Skip(_일봉차트.Count - 3).Max(w => w.종가);
        Console.WriteLine("최근 3일 최고종가:{0}", _최고종가_최근3일);                

        // 전체 기간 중 최고 종가를 가진 일자의 거래량 구하기
        var _일봉_최고종가 = _일봉차트.MaxBy(w => w.종가);
        Console.WriteLine("최고종가 일자의 거래량:{0}", _일봉_최고종가.FirstOrDefault().거래량);       
    }
}

public class 주가
{
    public string 일자 {get; set;}    
    public int 시가 {get; set;}
    public int 고가 {get; set;}
    public int 저가 {get; set;}
    public int 종가 {get; set;}
    public int 거래량 {get; set;}  
}

예제 실행해 보기

위에 예시된 Count, Average, Sum, Max 외에 Min, GroupBy 등 다양한 집계 메소드를 사용할 수 있습니다.





댓글