하아찡
[C#/WPF/수정] Upbit프로젝트 Balance 본문
디자인은 변경될 가능성이 매우매우매우매우 높음...
Balance.xaml
<UserControl x:Class="Upbit.Views.Balance"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:conv="clr-namespace:Upbit.Converter"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:custom="clr-namespace:TextBoxPlaceHolder;assembly=TextBoxPlaceHolder"
Width="180"
prism:ViewModelLocator.AutoWireViewModel="True">
<UserControl.Resources>
<conv:IsVisibilityConverter x:Key="isVisiblityConverter"/>
<conv:TwoMultipleConverter x:Key="TwoMultipleConverter"/>
<conv:FloorNumber x:Key="FloorNumber"/>
<conv:SubConverter x:Key="SubConverter"/>
<conv:PlusConverter x:Key="PlusConverter"/>
<Style x:Key="ListviewHeader" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Foreground" Value="{Binding MyColors.ColorText}"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Background" Value="{Binding MyColors.ColorBack}"/>
</Style>
</UserControl.Resources>
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<StackPanel Orientation="Vertical">
<TextBlock Text="내 보유자산" FontWeight="Bold" FontSize="14"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="5"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="5"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="0,0,5,0">
<TextBlock Text="보유KRW"/>
<TextBlock Text="{Binding MyAccount.Balance, Converter={StaticResource FloorNumber}}" FontSize="16" FontWeight="Bold" Margin="0,0,0,5"/>
<Grid Grid.Row="0">
<TextBlock Text="총매수" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding MyAccount.AvgBuyPrice, Converter={StaticResource FloorNumber}}" HorizontalAlignment="Right" />
</Grid>
<Grid Grid.Row="1">
<TextBlock Text="총평가" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding MyAccount.NowPrice, Converter={StaticResource FloorNumber}}" HorizontalAlignment="Right" />
</Grid>
</StackPanel>
<StackPanel Grid.Row="1" Margin="2" Background="Gray"/>
<StackPanel Grid.Row="3" Margin="2" Background="Gray"/>
<StackPanel Grid.Row="2" Orientation="Vertical" Margin="0,0,5,0">
<TextBlock Text="총 보유자산"/>
<TextBlock FontSize="16" FontWeight="Bold" Margin="0,0,0,5">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource PlusConverter}">
<Binding Path="MyAccount.NowPrice" />
<Binding Path="MyAccount.Balance" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<Grid Grid.Row="0">
<TextBlock Text="평가손익" HorizontalAlignment="Left"/>
<TextBlock HorizontalAlignment="Right" Foreground="{Binding MyAccount.Color}" >
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SubConverter}">
<Binding Path="MyAccount.NowPrice" />
<Binding Path="MyAccount.AvgBuyPrice" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
<Grid Grid.Row="1">
<TextBlock Text="수익률" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding MyAccount.Rate, StringFormat={}{0:0.##}%}" Foreground="{Binding MyAccount.Color}" HorizontalAlignment="Right" />
</Grid>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
<Grid Grid.Row="1" >
<!-- 인증 안됐을때 텍스트로 출력 -->
<TextBlock Panel.ZIndex="1" Foreground="{Binding MyColors.ColorText}" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Lang.LNotAccess}" Visibility="{Binding NoneAccessView}" />
<ListView ItemsSource="{Binding Accounts}" Foreground="{Binding MyColors.ColorText}"
ScrollViewer.VerticalScrollBarVisibility="Disabled" BorderThickness="0"
x:Name="MyListView">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding CommandSendCoin}" CommandParameter="{Binding ElementName=MyListView, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="0,10,0,0">
<StackPanel Orientation="Vertical">
<Grid >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CoinName}" FontWeight="Bold" FontSize="14" />
<TextBlock Text="{Binding Currency,StringFormat={}({0})}" FontWeight="Bold" FontSize="14" />
</StackPanel>
</Grid>
<Grid>
<TextBlock Text="수익률" />
<TextBlock Foreground="{Binding Color}" Text="{Binding Rate,StringFormat={}{0:0.##}%}" HorizontalAlignment="Right"/>
</Grid>
<Grid>
<TextBlock Text="평가손익" />
<TextBlock Foreground="{Binding Color}" HorizontalAlignment="Right">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource SubConverter}">
<Binding Path="TotalPrice" />
<Binding Path="Cost" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
<Grid>
<TextBlock Text="평단가" />
<TextBlock Text="{Binding AvgBuyPrice, Converter={StaticResource FloorNumber}}" HorizontalAlignment="Right"/>
</Grid>
<Grid>
<TextBlock Text="보유수량" />
<TextBlock Text="{Binding TotalBalance}" HorizontalAlignment="Right"/>
</Grid>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</UserControl>
BalanceViewModel.cs
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Threading;
using Upbit.UpbitFunctions;
using System.Windows;
using Upbit.UpbitFunctions.Interface;
using Language;
using System.Windows.Media;
using PublicColor;
using Prism.Events;
using Upbit.Event;
using Upbit.Functions.Interface;
using Upbit.Functions;
using System.Windows.Controls.Primitives;
using System.Linq;
using Language.Lang;
using static Upbit.Structs;
using System.Diagnostics;
namespace Upbit.ViewModels
{
public class BalanceViewModel : BindableBase,IAccess, ILanguage, IColors, IWebSocketTicker, IMyTrade
{
#region Lang
private Language.Lang.Balance lang;
public Language.Lang.Balance Lang
{
get { if (lang is null) lang = new Language.Lang.Balance(); return lang; }
set { SetProperty(ref lang, value); }
}
public virtual void SetLanguage()
{
Lang.UpdateLang();
SetCoinName();
}
#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;
}
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 Prism
private IEventAggregator _ea;
#endregion Prism
#region Models
private Structs.Accounts myaccount;
public Structs.Accounts MyAccount
{
get { return myaccount; }
set { SetProperty(ref myaccount, value); }
}
private Visibility noneaccessview;
public Visibility NoneAccessView
{
get { return noneaccessview; }
set { SetProperty(ref noneaccessview, value); }
}
public bool IsBalance { get; private set; }
private UpbitFunctions.Accounts FAccount = new UpbitFunctions.Accounts();
private List<Structs.Accounts> accounts;
public List<Structs.Accounts> Accounts
{
get { return accounts; }
set {
SetProperty(ref accounts, value);
}
}
private List<Structs.MarketCodes> Markets;
private PublicFunctions pf = new PublicFunctions();
#endregion Models
/// <summary>
/// 코인 선택 이벤트
/// </summary>
private DelegateCommand<object> _sendcoin;
public DelegateCommand<object> CommandSendCoin =>
_sendcoin ?? (_sendcoin = new DelegateCommand<object>(ExecuteCommandSendCoin));
void ExecuteCommandSendCoin(object obj)
{
if (obj is null) return;
Structs.Accounts marketCodes = (Structs.Accounts)obj;
_ea.GetEvent<MessagaeAccountEvent>().Publish(marketCodes);
}
public void TradeEvent(Structs.Trade tr)
{
throw new NotImplementedException();
}
public void OrderEvent(Structs.Orderbook ob)
{
throw new NotImplementedException();
}
public void TickerEvent(Structs.Ticker tick)
{
if(Accounts is not null)
{
if(Accounts.Count > 0)
{
for(int i = 0; i < Accounts.Count; i++)
{
if(tick.cd == Accounts[i].Market)
{
Accounts[i].NowPrice = tick.tp;
Accounts[i].TotalPrice = tick.tp;
Accounts[i].Rate = tick.tp;
Accounts[i].Color = SetTextColor(Accounts[i].NowPrice , Convert.ToDouble(Accounts[i].AvgBuyPrice));
if(MyAccount is not null)
{
//내 지갑
SetMyAccount();
}
break;
}
}
}
}
}
private Brush SetTextColor(double now, double avg)
{
Brush val = Brushes.Transparent;
if (now >= avg)
val = MyColors.ColorBid;
else
val = MyColors.ColorAsk;
return val;
}
/// <summary>
/// key값을 전달받았을때 이벤트
/// </summary>
/// <param name="b"></param>
public void D_AccessEvent(bool b)
{
IsBalance = Access.UpbitInstance.GetAccess();
if (IsBalance)
{
NoneAccessView = Visibility.Collapsed;
Accounts = Task.Run(() => FAccount.AccountsAsync()).Result;
PullOutMyAccount(ref accounts);
SetCoinName();
}
else
{
Accounts = new List<Structs.Accounts>();
NoneAccessView = Visibility.Visible;
}
}
private void SetCoinName()
{
if (Accounts is null)
return;
for(int i = 0; i < Accounts.Count; i++)
{
foreach(var v in Markets)
{
if(v.Market == Accounts[i].Market)
{
string str = "";
if (Language.Language.Lang.LangType == "kr")
str = v.Korean_name;
else
str = v.English_name;
Accounts[i].CoinName = str;
break;
}
}
}
}
private double GetMyTotalPrice()
{
double value = 0;
foreach(var v in Accounts)
{
value += v.TotalPrice;
}
return value;
}
private double GetMyTotalCost()
{
double value = 0;
foreach (var v in Accounts)
{
value += v.Cost;
}
return value;
}
private void PullOutMyAccount(ref List<Structs.Accounts> list)
{
if (Accounts is null)
return;
try
{
int index = -1;
for (int i = 0; i < list.Count; i++)
{
if ("KRW" == list[i].Currency)
{
MyAccount = list[i];
index = i;
}
else
{
if (list[i].NowPrice == 0)
{
Structs.Orderbook now = pf.OrderBook(list[i].Market);
list[i].NowPrice = now.obu[0].bp;
list[i].TotalPrice = now.obu[0].bp;
list[i].Rate = now.obu[0].bp;
list[i].Color = SetTextColor(list[i].NowPrice, Convert.ToDouble(list[i].AvgBuyPrice));
}
}
}
if (index != -1)
list.RemoveAt(index);
}
catch(Exception e)
{
Debug.WriteLine("PullOut");
}
SetMyAccount();
}
/// <summary>
/// 내 KRW잔고 갱신
/// </summary>
private void SetMyAccount()
{
MyAccount.NowPrice = GetMyTotalPrice();
MyAccount.AvgBuyPrice = GetMyTotalCost().ToString();
MyAccount.Cost = GetMyTotalCost();
MyAccount.Rate = MyAccount.NowPrice;
MyAccount.Color = SetTextColor(MyAccount.NowPrice, Convert.ToDouble(MyAccount.AvgBuyPrice));
}
#region Account Timer Functions
/// <summary>
/// 잔고 갱신
/// </summary>
public void RefreshAccount()
{
List<Structs.Accounts> list = Task.Run(() => FAccount.AccountsAsync()).Result;
PullOutMyAccount(ref list);
for (int j = 0; j < list.Count; j++)
{
for (int i = 0; i < Accounts.Count; i++)
{
if (Accounts[i].Market == list[j].Market)
{
list[j].CoinName = Accounts[i].CoinName;
list[j].NowPrice = Accounts[i].NowPrice;
list[j].TotalPrice = Accounts[i].NowPrice;
list[j].Color = SetTextColor(Accounts[i].NowPrice, Convert.ToDouble(Accounts[i].AvgBuyPrice));
break;
}
}
}
Accounts = list;
SetCoinName();
}
/// <summary>
/// 코인 주문 성공했을때 현재 잔고 갱긴을위해사용
/// </summary>
/// <param name="b"></param>
public void RefreshAccount(bool b)
{
if (b)
{
RefreshAccount();
}
}
public virtual void MyTradeEvent(Structs.MyTrade mytrade)
{
//원화는 그냥 불러와서 계산하는게 정확할거같아서 불러다씀
RefreshAccount();
}
#endregion Account Timer Functions
public BalanceViewModel(IEventAggregator ea)
{
_ea = ea;
EventUpdateColor();
SetLanguage();
Accounts = new List<Structs.Accounts>();
_ea.GetEvent<MessageBoolEvent>().Subscribe(RefreshAccount);
//Key값 이벤트 등록
Access.CheckedAccess += (D_AccessEvent);
PublicFunctions Upbitpf = new PublicFunctions();
Markets = Task.Run(() => Upbitpf.MarketsAsync()).Result;
//색변경 이벤트 등록
PublicColor.Colors.ColorUpdate += (EventUpdateColor);
//언어 변경시 이벤트 등록
Language.Language.LangChangeEvent += (SetLanguage);
//실시간 틱데이터를 받아오기위해 이벤트등록
WebSocketTicker.TickerEvent += new WebSocketTicker.TickEventHandler(TickerEvent);
MyTradeClientWebSocket.MyTradeEvent += new MyTradeClientWebSocket.MyTradeEventHandler(MyTradeEvent);
IsBalance = Access.UpbitInstance.GetAccess();
if (IsBalance)
{
NoneAccessView = Visibility.Collapsed;
Accounts = Task.Run(() => FAccount.AccountsAsync()).Result;
PullOutMyAccount(ref accounts);
SetCoinName();
}
else
{
Accounts = new List<Structs.Accounts>();
NoneAccessView = Visibility.Visible;
}
}
}
}
전체 코드중 이전과 다르게 추가된점은
PullOutMyAccount 함수쪽인데 이전엔 현재가를 받아오지 못한상태에서 웹소켓에서 데이터가 들어올때가지 표시가 안되는 버그가 있었는데 그 문제를 OrderBook함수를 호출해서 현재 호가를 불러와 일부 계산을 시켜서 버그 해결.
PullOutMyAccount함수
/// <summary>
/// 내 잔고를 뺌과 동시에 내 지갑에있는 코인 현재가가없을경우 현재가를 출력해줌
/// 23.12.04 -완
/// </summary>
/// <param name="list"></param>
private void PullOutMyAccount(ref List<Structs.Accounts> list)
{
if (Accounts is null)
return;
try
{
int index = -1;
for (int i = 0; i < list.Count; i++)
{
if ("KRW" == list[i].Currency)
{
MyAccount = list[i];
index = i;
}
else
{
if (list[i].NowPrice == 0)
{
Structs.Orderbook now = pf.OrderBook(list[i].Market);
list[i].NowPrice = now.obu[0].bp;
list[i].TotalPrice = now.obu[0].bp;
list[i].Rate = now.obu[0].bp;
list[i].Color = SetTextColor(list[i].NowPrice, Convert.ToDouble(list[i].AvgBuyPrice));
}
}
}
if (index != -1)
list.RemoveAt(index);
}
catch(Exception e)
{
Debug.WriteLine("PullOut");
}
SetMyAccount();
}
반응형
'C# > 코인프로그램 - 코드' 카테고리의 다른 글
[C#/WPF/수정] Upbit프로젝트 Balance 타이머 추가 (1) | 2023.12.08 |
---|---|
[C#/WPF/수정] PublicColor프로젝트 색변경 추가 (1) | 2023.12.06 |
[C#/WPF] Upbit 프로젝트 JWT (2) | 2023.12.03 |
[C#/WPF] Upbit 프로젝트 Chart - 7(Converter) (0) | 2023.12.03 |
[C#/WPF] Upbit 프로젝트 Chart - 6(틱 타입변경) (2) | 2023.12.03 |