하아찡

[C#/WPF] Upbit 프로젝트 Chart - 5(라이브 캔들) 본문

C#/코인프로그램 - 코드

[C#/WPF] Upbit 프로젝트 Chart - 5(라이브 캔들)

하아찡 2023. 12. 2. 01:16

라이브 캔들은 실시간으로 거래가 되고있는 데이터를 TickData에 넣음과 동시에 PrintTick에도 업데이트를 하게 시킵니다.

하지만 내가 이전 데이터를 보고있는데 PrintTick을 업데이트를 시키면 오류가 나기때문에 현재 보고있는 화면에 라이브 캔들이 들어가는 경우에만 변경하게 했습니다.

 

실시간 거래를 처리하는 방식은 WebSocket을 설명할때 사용했던 코드를 그대로 사용합니다. 설명이 필요하신분은 아래 링크를 참고해주세요.

https://thesh.tistory.com/42

 

C# Upbit프로젝트 WebSocketTicker

코인데이터를 실시간으로 받아오기위해선 Upbit Websocket을 사용하라해서 WebSocket을 사용해서 실시간 데이터를 받아옴. 아래는 Upbit API Reference주소 입니다. https://docs.upbit.com/reference/websocket-ticker Open

thesh.tistory.com

 

 

TickerEvent

/// <summary>
/// 실시간 데이터를 웹소켓에서 받아와서 차트에 갱신시켜줌.
/// 23.11.14
/// </summary>
/// <param name="tick"></param>
public void TickerEvent(Ticker tick)
{
    if (Market == tick.cd)
    {
        if (TickData is not null && TickData.Count > 0)
        {
            int cnt = TickData.Count - 1;
            DateTime StartTime = Convert.ToDateTime(TickData[cnt].kst);
            StartTime = StartTime.AddSeconds(StartTime.Second * -1);
            DateTime EndTime = StartTime.AddMinutes(MinTickTime).AddSeconds(-1);
            DateTime dtTradeTime = FncDateTime.LongToDateTime(tick.ttms);         //한국시간
            UInt32 TradeTime = FncDateTime.DateTimeToInt(dtTradeTime);
            try
            {
                //실시간 데이터 갱신
                if (FncDateTime.DateTimeToInt(StartTime) <= TradeTime && TradeTime <= FncDateTime.DateTimeToInt(EndTime))
                {
                    Candle candle = TickData[cnt];
                    candle.timestamp = tick.ttms;
                    candle.tp = tick.tp;
                    candle.candle_acc_trade_price = tick.atp;
                    candle.candle_acc_trade_volume += tick.tv;
                    //candle.kst = FncDateTime.LongToDateTime(tick.ttms).ToString();

                    //고가 갱신
                    if (candle.tp > candle.hp)
                        candle.hp = candle.tp;

                    //저가 갱신
                    if (candle.lp > candle.tp)
                        candle.lp = candle.tp;

                    //현재 갱신중인 틱을 보여줌.
                    if ((TickData.Count - PrintCursor) < PrintCandle)
                    {
                        Tick _tick = PrintTick[PrintTick.Count - 1];
                        _tick.TP = tick.tp;

                        //해당 기준 시간을 변경시 틱데이터를 불러올때 데이터가 불러와지지 않는 버그 발생 Timestamp를 변경해야할듯
                        //_tick.KST = candle.kst;
                        _tick.Timestamp = tick.ttms;

                        _tick.Colors = SetCandleColor(_tick.OP, _tick.TP);

                        if (_tick.TP < _tick.LP)
                            _tick.LP = _tick.TP;
                        if (_tick.TP > _tick.HP)
                            _tick.HP = _tick.TP;

                        _tick.Tail = 0;
                        _tick.Candle = 0;
                        _tick.CandleStartPoint = 0;
                        _tick.Volume += tick.tv;

                        if (MinPrice > _tick.LP)
                            MinPrice = _tick.LP;
                        if (MaxPrice < _tick.HP)
                            MaxPrice = _tick.HP;
                        if (MaxVolume < _tick.Volume)
                            MaxVolume = _tick.Volume;
                        VolumeTickHeight = GridVolumeHeight / MaxVolume;
                        ChartTickHeight = GridHeight / (MaxPrice - MinPrice);

                        PrintChartYAxis[0].CursorValue = MaxPrice.ToString(FLen);
                        PrintChartYAxis[1].CursorValue = MinPrice.ToString(FLen);

                        //현재가 표시해줌
                        PrintChartYAxis[3].CursorValue = _tick.TP.ToString();
                        PrintChartYAxis[3].Y = (GridHeight * ((MaxPrice - _tick.TP) / (MaxPrice - MinPrice))) + GapYAxis;

                    }

                    TickData[cnt] = candle;
                }
                else
                {
                    EndTime = StartTime.AddMinutes(MinTickTime);
                    Candle precandel = TickData[cnt];
                    Candle candle = new Candle();
                    candle.timestamp = tick.ttms;
                    candle.tp = tick.tp;
                    candle.op = precandel.tp;
                    candle.hp = tick.tp;
                    candle.lp = tick.tp;
                    candle.kst = EndTime.ToString();
                    candle.candle_acc_trade_volume = tick.tv;
                    TickData.Add(candle);


                    //실시간 데이터 생성
                    if ((TickData.Count - PrintCursor) < PrintCandle)
                    {
                        Tick _tick = new Tick();
                        _tick.TP = tick.tp;
                        _tick.OP = precandel.tp;
                        _tick.HP = tick.tp;
                        _tick.LP = tick.tp;
                        _tick.KST = EndTime.ToString();
                        _tick.Volume = tick.tv;
                        if (MinPrice > _tick.LP)
                            MinPrice = _tick.LP;
                        if (MaxPrice < _tick.HP)
                            MaxPrice = _tick.HP;
                        if (MaxVolume < _tick.Volume)
                            MaxVolume = _tick.Volume;
                        VolumeTickHeight = GridVolumeHeight / MaxVolume;
                        ChartTickHeight = GridHeight / (MaxPrice - MinPrice);

                        _tick.Tail = 0;
                        _tick.Candle = 0;
                        _tick.CandleStartPoint = 0;
                        _tick.X = PrintTick[PrintTick.Count - 1].X + 1;


                        _tick.Colors = SetCandleColor(_tick.OP, _tick.TP);

                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            PrintTick.Add(_tick);
                            GetCandleTime();
                        });


                    }


                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show("aaaaaa");
            }
        }
    }
}

 

 

DateTime StartTime = Convert.ToDateTime(TickData[cnt].kst);
StartTime = StartTime.AddSeconds(StartTime.Second * -1);
DateTime EndTime = StartTime.AddMinutes(MinTickTime).AddSeconds(-1);
DateTime dtTradeTime = FncDateTime.LongToDateTime(tick.ttms);         //한국시간
UInt32 TradeTime = FncDateTime.DateTimeToInt(dtTradeTime);

위 코드로 인해 현재 마지막 틱이 갱신이 되야하는지 다음 틱을 새로 생성하는지를 정해줍니다.

 

if (FncDateTime.DateTimeToInt(StartTime) <= TradeTime && TradeTime <= FncDateTime.DateTimeToInt(EndTime))

 

해당 코드를 말로 설명하면 "틱 시작시간 <= 현재시간 < 틱 마지막시간" 이런식인데 이 시간 안에 있을 경우엔 마지막 데이터를 계속 갱신하는 방향으로 처리하고 해당 경우가 틀렸을 경우엔 다음 틱을 생성해줘야합니다.

 

 

틱 생성 초기데이터

EndTime = StartTime.AddMinutes(MinTickTime);
Candle precandle = TickData[cnt];
Candle candle = new Candle();
candle.timestamp = tick.ttms;
candle.tp = tick.tp;
candle.op = precandle.tp;
candle.hp = tick.tp;
candle.lp = tick.tp;
candle.kst = EndTime.ToString();
candle.candle_acc_trade_volume = tick.tv;
TickData.Add(candle);

precandle은 마지막 틱 종가를 받아와 새로 생성하는 틱 시가를 정보를 전달해주기위해 사용.

EndTime은 틱 데이터 기준시간을 지정해주기위해 사용함. 정확하게 맞아야 데이터가 밀리지않음.

 

반응형