하아찡

[C#/WPF] Upbit프로젝트 BidAskList 본문

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

[C#/WPF] Upbit프로젝트 BidAskList

하아찡 2023. 11. 29. 14:53

선택된 코인 호가창을 보여줌. 최대 10개까지로 설정했음.

 

 

BidAskList.xaml

<UserControl x:Class="Upbit.Views.BidAskList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"      
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:conv="clr-namespace:Upbit.Converter"
             prism:ViewModelLocator.AutoWireViewModel="True">
    <UserControl.Resources>
        <conv:DivByThreeConverter x:Key="DivByThreeConverter"/>
        <Style x:Key="ListviewItemStyle" TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Border x:Name="border" Background="Red">
                            <ContentPresenter Content="{TemplateBinding Content}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid x:Name="g1">
        <Grid.RowDefinitions>
            <RowDefinition Height="20" />
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" x:Name="c1" />
            <ColumnDefinition Width="1*" x:Name="c2"/>
            <ColumnDefinition Width="1*" x:Name="c3" />
        </Grid.ColumnDefinitions>

        <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding CoinName}"/>
                <TextBlock Margin="10,0,0,0" Text="{Binding Rate}"/>
            </StackPanel>
        </Grid>
        <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" >
            <ListView x:Name="LvAsk" ItemsSource="{Binding AskUnits}" 
              ScrollViewer.VerticalScrollBarVisibility="Disabled"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled"
              BorderThickness="0"
              Background="{Binding MyColors.ColorAskBack}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDoubleClick">
                        <i:InvokeCommandAction Command="{Binding CommandListViewDoubleClick}" CommandParameter="{Binding ElementName=LvAsk,Path=SelectedItem}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        
                        <VirtualizingStackPanel VerticalAlignment="Bottom"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                <ListView.Resources>
                    <!--상단 헤더 안보이게-->
                    <Style TargetType="GridViewColumnHeader">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Style>

                    <Style TargetType="ListViewItem">
                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                    </Style>
                </ListView.Resources>
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Volume" DisplayMemberBinding="{Binding units}" Width="{Binding ActualWidth, ElementName=g1,Converter={StaticResource DivByThreeConverter}}"/>
                        <GridViewColumn Header="Price" DisplayMemberBinding="{Binding unitp}" Width="{Binding ActualWidth, ElementName=g1,Converter={StaticResource DivByThreeConverter}}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>

        <Grid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2">
            <ListView x:Name="LvBid" ItemsSource="{Binding BidUnits}"
              
              ScrollViewer.VerticalScrollBarVisibility="Disabled"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled"
              BorderThickness="0"
              Background="{Binding MyColors.ColorBidBack}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseDoubleClick">
                        <i:InvokeCommandAction Command="{Binding CommandListViewDoubleClick}" CommandParameter="{Binding ElementName=LvBid,Path=SelectedItem}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>

                <ListView.Resources>
                    <!--상단 헤더 안보이게-->
                    <Style TargetType="GridViewColumnHeader">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Style>

                    <Style TargetType="ListViewItem">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="Transparent"/>
                                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                                <!--Setter Property="BorderBrush" Value="{Binding MyColors.ColorBid}"/-->
                            </Trigger>
                            <Trigger Property="IsSelected" Value="True">
                                <!--Setter Property="BorderBrush" Value="{Binding MyColors.ColorBid}"/-->
                                
                                <Setter Property="Background" Value="Transparent"/>
                            </Trigger>
                        </Style.Triggers>
                        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                    </Style>
                    
                    
                </ListView.Resources>
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Volume" DisplayMemberBinding="{Binding unitp}" Width="{Binding ActualWidth, ElementName=g1,Converter={StaticResource DivByThreeConverter}}" />
                        <GridViewColumn Header="Price" DisplayMemberBinding="{Binding units}" Width="{Binding ActualWidth, ElementName=g1,Converter={StaticResource DivByThreeConverter}}"/>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Grid>
</UserControl>

 

 

DivByThreeConverter.cs

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows;

namespace Upbit.Converter
{
    public class DivByThreeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double width)
            {
                return width / 3.0;
            }

            return DependencyProperty.UnsetValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

}

 

 

 

BidAskListViewModel.cs

using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using PublicColor;
using System;
using System.Collections.Generic;
using System.Linq;
using Upbit.Event;
using Upbit.Functions;
using Upbit.Functions.Interface;
using Upbit.UpbitFunctions;
using static Upbit.Structs;

namespace Upbit.ViewModels
{
    public class BidAskListViewModel : BindableBase,IWebSocketTicker, IColors
    {

        PublicFunctions upbit = new PublicFunctions();
        #region Models
        /// <summary>
        /// 매수 호가 목록
        /// </summary>
        private List<Structs.BidAskUnit> bidunits;
        public List<Structs.BidAskUnit> BidUnits
        {
            get { return bidunits; }
            set { SetProperty(ref bidunits, value); }
        }
        

        /// <summary>
        /// 매도 호가창
        /// </summary>
        private List<Structs.BidAskUnit> askunits;
        public List<Structs.BidAskUnit> AskUnits
        {
            get { return askunits; }
            set { SetProperty(ref askunits, value); }
        }


        /// <summary>
        /// 현재 코인명
        /// </summary>
        private string coinname;
        public string CoinName
        {
            get { return coinname; }
            set { SetProperty(ref coinname, value); }
        }

        /// <summary>
        /// 등락율
        /// </summary>
        private string rate;
        public string Rate
        {
            get { return rate; }
            set { SetProperty(ref rate, value); }
        }


        private double acwidth;
        public double AcWidth
        {
            get { return acwidth; }
            set { SetProperty(ref acwidth, value); }
        }

        private bool BidAskType = true;
        #endregion

        #region Colors
        /// <summary>
        /// 색상 업데이트 이벤트
        /// </summary>
        public void EventUpdateColor()
        {
            MyColors.ColorText = PublicColor.Colors.Colorinstance.ColorText;
            MyColors.ColorBack = PublicColor.Colors.Colorinstance.ColorBack;
            MyColors.ColorBid = PublicColor.Colors.Colorinstance.ColorBid;
            MyColors.ColorAsk = PublicColor.Colors.Colorinstance.ColorAsk;
            MyColors.ColorBidBack = PublicColor.Colors.Colorinstance.ColorBidBack;
            MyColors.ColorAskBack = PublicColor.Colors.Colorinstance.ColorAskBack;
        }

        private PublicColor.Colors mycolors;
        public PublicColor.Colors MyColors
        {
            get
            {
                if (mycolors is null) mycolors = new PublicColor.Colors();
                return mycolors;
            }
            set { SetProperty(ref mycolors, value); }
        }
        #endregion Colors

        #region PrismEvent
        private IEventAggregator _ea;


        #endregion PrismEvent


        #region Event

        /// <summary>
        /// 선택된 금액으로 매수 매도가 변경
        /// </summary>
        private DelegateCommand<object> listviewdoubleclick;
        public DelegateCommand<object> CommandListViewDoubleClick =>
            listviewdoubleclick ?? (listviewdoubleclick = new DelegateCommand<object>(ExecuteCommandListViewDoubleClick));

        void ExecuteCommandListViewDoubleClick(object obj)
        {
            if (obj is null)
                return;
            Structs.BidAskUnit unit = (BidAskUnit)obj;

            Structs.MessageCoinPirce mp = new MessageCoinPirce();
            mp.Check = unit.Check;
            mp.Price = unit.unitp;
             
            _ea.GetEvent<MessageCoinPriceEvent>().Publish(mp);
        }

        #endregion

        #region InterfaceFunctions
        public void TradeEvent(Trade tr)
        {
            throw new NotImplementedException();
        }

        public void OrderEvent(Orderbook ob)
        {
            if (CoinName == ob.cd)
            {
                SetOrderBook(ob);
            }
        }

        public void TickerEvent(Ticker tick)
        {

            if (CoinName == tick.cd)
            {
                string Change = tick.c;
                string str = "";

                if (Change == "RISE")
                    str = "+";
                else if (Change == "FALL")
                    str = "-";

                Rate = $"{str}{Math.Round(tick.cr * 100, 2)}%";
            }
        }

        #endregion InterfaceFunctions

        #region Functions

        /// <summary>
        /// 호가창 셋팅
        /// </summary>
        /// <param name="ob"></param>
        private void SetOrderBook(Structs.Orderbook ob)
        {
            BidUnits.Clear();
            AskUnits.Clear();
            
            try
            {
                foreach (var item in ob.obu)
                {

                    Structs.BidAskUnit ask = new Structs.BidAskUnit();
                    Structs.BidAskUnit bid = new Structs.BidAskUnit();
                    ask.unitp = item.ap;
                    ask.units = item._as;

                    bid.unitp = item.bp;
                    bid.units = item.bs;
                    AskUnits.Add(ask);
                    BidUnits.Add(bid);

                }

                AskUnits = Enumerable.Reverse(AskUnits).ToList();
                BidUnits = BidUnits.ToList();

            }
            catch(Exception e)
            {

            }
            
        }

        private void GetCoinName(Structs.MarketCodes coinname)
        {
            CoinName = coinname.Market;
            Rate = coinname.Rate.ToString();
            SetOrderBook(upbit.OrderBook(CoinName));

            Structs.MessageCoinPirce mcp = new Structs.MessageCoinPirce();
            //mcp.
            if(BidAskType == true)
            {
                //매수 타입
                
                mcp.Price = AskUnits[AskUnits.Count - 1].unitp;
            }
            else
            {
                //매도타입
                mcp.Price = BidUnits[0].unitp;
            }
            mcp.Check = BidAskType;
            _ea.GetEvent<MessageCoinPriceEvent>().Publish(mcp);
            
        }
        private void GetBidAskType(bool b)
        {
            BidAskType = b;
        }
        #endregion Functions

        public BidAskListViewModel(IEventAggregator ea)
        {
            _ea = ea;

            _ea.GetEvent<MessageCoinNameEvent>().Subscribe(GetCoinName);
            _ea.GetEvent<MessageBidAskCheckEvent>().Subscribe(GetBidAskType);

            BidUnits = new List<Structs.BidAskUnit>();
            AskUnits = new List<Structs.BidAskUnit>();

            //웹소켓에서 받아온 OrderBook이벤트 발생
            WebSocketTicker.OrderEvent += new WebSocketTicker.OrderEventHandler(OrderEvent);
            WebSocketTicker.TickerEvent += new WebSocketTicker.TickEventHandler(TickerEvent);

            //색변경 이벤트 등록
            PublicColor.Colors.ColorUpdate += (EventUpdateColor);
        }

    }
}

 

해당 코드는 최대 호가15개로 받고 보여주는 호가를 변경 할 수 있게 수정할예정.

물론 UI쪽 디자인도 조금 다듬어야할듯.

반응형