private void Timer_Tick(object sender, EventArgs e) { var KRWAccount = ApiData.getAsset().Where(x => "KRW".Equals(x.Value <string>("currency"))).First(); Thread.Sleep(100); var krwBalance = KRWAccount.Value <double>("balance"); // 보유 현금 var candles = ApiData.getCandle <List <Candle> >(CoinName, CandleType, CandleCount); Thread.Sleep(100); var prevCandle = candles[1]; var currCandle = candles[0]; var currPrice = currCandle.Close; var prevPrice = prevCandle.Close; var orderChance = ApiData.getOrdersChance(CoinName); Thread.Sleep(100); var ask = orderChance["ask_account"]; var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = (coinVol * currPrice < 5000) ? currPrice : ask.Value <double>("avg_buy_price"); // 매수 평단가 var coinPrice = avgPrice * coinVol; // 보유 코인 금액 var upRatio = (currPrice - avgPrice) / currPrice * 100; // 평단 대비 상승폭 (%) var downRatio = (currPrice - prevPrice) / currPrice * 100; // 현재가 대비 하락폭 (%) var result = null as JObject; // 거래 결과 Debug.WriteLine("upRatio : {0}, downRatio {1}", upRatio, downRatio); WriteLog("upRatio : {0}, downRatio {1}", upRatio, downRatio); try { if (upRatio >= TriggerRatio && coinPrice > 5000) { // 올랐을때 코인 금액 절반 팔기 var vol = (coinPrice / 2) > 5000 ? coinVol / 2 : coinVol; Debug.WriteLine("#### {2} SELL : 금액 {0}, 수량 {1}", vol * currPrice, vol, CoinName); WriteLog("#### {2} SELL : 금액 {0}, 수량 {1}", vol * currPrice, vol, CoinName); result = React.executeDeal(false, false, CoinName, vol, 0, 0); } else if (downRatio <= -(TriggerRatio) && krwBalance > 5000) { // 내렸을때 보유 현금 절반으로 코인 사기 var total = (krwBalance / 2) > 5000 ? krwBalance / 2 : krwBalance; total = Math.Truncate(total * 1000) / 1000; Debug.WriteLine("#### {2} BUY : 금액 {0}, 수량 {1}", total, total / currPrice, CoinName); WriteLog("#### {2} BUY : 금액 {0}, 수량 {1}", total, total / currPrice, CoinName); result = React.executeDeal(true, false, CoinName, 0, 0, total); } } catch (Exception ex) { Debug.WriteLine(ex); } if (result != null) { Debug.WriteLine("#### RESULT : {0}", result.ToString()); WriteLog("#### RESULT : {0}", result.ToString()); } }
private OrderChance GetOrderChance(string coinName) { var result = new OrderChance(); var orderChance = ApiData.getOrdersChance(CoinName); var ask = orderChance["ask_account"]; var bid = orderChance["bid_account"]; result.KRWBalance = bid.Value <double>("balance"); // 보유 현금 result.CoinVol = ask.Value <double>("balance"); // 보유 코인 수량
private void MinuteCandleByTicks() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = TradeRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) var currPrice = candles.First().Close; // 현재가 // 보유현금 및 주문 정보 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = ask.Value <double>("avg_buy_price"); // 매수 평단가 var bidLock = bid.Value <double>("locked"); // 매수 대기 금액 var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 var coinBalance = currPrice * coinVol; // 코인 평가금 var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 // 분봉 N개를 기준으로 직전 시가 에서 현재 금액 등낙률을 가져온다. //var prevCandle = candles[1]; // 직전 캔들 //var lastCandle = candles.Last(); // 마지막 캔들 var prevPrice = candles[1].Close; // 직전종가 var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 var downPrice = highPrice * (triggerRate + (feeRate * 2)) / 100; // 하락가 var triggerDownPrice = highPrice - downPrice; // 매수 하락 촉발가 var downRate = Math.Min(0D, (currPrice - highPrice) * 100 / highPrice); // 하락율 var upPrice = prevPrice * ((triggerRate / candleCount) + (feeRate * 2)) / 100; // 반등가 var triggerUpPrice = prevPrice + upPrice; // 매수 반등 촉발가 var upRate = Math.Max(0D, (currPrice - prevPrice) * 100 / prevPrice); // 반등 상승율 var downUpRate = upRate == 0 ? 0D : (-downRate / upRate); // 반등율 var targetRate = ((triggerRate / (candleCount - 1)) + (feeRate * 2)) / 100; // 목표 수익율 var targetSellPrice = avgPrice + (avgPrice * targetRate); // 매도 목표가 var buyTs = DateTime.Now - LastBuyDate; var sellTs = DateTime.Now - LastSellDate; var result = null as JObject; var args = new object[] { coinName, currPrice, prevPrice, highPrice, downRate, upRate, avgPrice, targetSellPrice, DateTime.Now; };
private OrderChance GetOrderChance(string coinName) { var orderChance = ApiData.getOrdersChance(CoinName); var ask = orderChance["ask_account"]; var bid = orderChance["bid_account"]; var result = new OrderChance() { KRWBalance = bid.Value <double>("balance"), // 보유 현금 CoinVol = ask.Value <double>("balance"), // 보유 코인 수량 AvgBuyPrice = ask.Value <double>("avg_buy_price"), // 매수 평단가 }; return(result); }
private OrderChance GetOrderChance(ApiData apiData, string coinName, double currentPrice, bool setText = true) { var orderChance = apiData.getOrdersChance(coinName); var ask = orderChance["ask_account"]; var bid = orderChance["bid_account"]; var result = new OrderChance(currentPrice) { KRWBalance = bid.Value <double>("balance"), // 보유 현금 CoinVol = ask.Value <double>("balance"), // 보유 코인 수량 AvgBuyPrice = ask.Value <double>("avg_buy_price"), // 매수 평단가 }; txtKRW.Text = result.KRWBalance.ToString("N0"); txtCoinBalance.Text = result.CoinBalance.ToString("N0"); return(result); }
private void MinuteCandleByTicks() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = TradeRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) var currPrice = candles.First().Close; // 현재가 // 보유현금 및 주문 정보 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = ask.Value <double>("avg_buy_price"); // 매수 평단가 var bidLock = bid.Value <double>("locked"); // 매수 대기 금액 var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 var coinBalance = currPrice * coinVol; // 코인 평가금 var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 // 분봉 N개를 기준으로 직전 시가 에서 현재 금액 등낙률을 가져온다. //var prevCandle = candles[1]; // 직전 캔들 //var lastCandle = candles.Last(); // 마지막 캔들 var prevPrice = candles[1].Close; // 직전종가 var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 var downPrice = highPrice * (triggerRate + (feeRate * 2)) / 100; // 하락가 var triggerDownPrice = highPrice - downPrice; // 매수 하락 촉발가 var downRate = Math.Min(0D, (currPrice - highPrice) * 100 / highPrice); // 하락율 var upPrice = prevPrice * ((triggerRate / candleCount) + (feeRate * 2)) / 100; // 반등가 var triggerUpPrice = prevPrice + upPrice; // 매수 반등 촉발가 var upRate = Math.Max(0D, (currPrice - prevPrice) * 100 / prevPrice); // 반등 상승율 var downUpRate = upRate == 0 ? 0D : (-downRate / upRate); // 반등율 var targetRate = ((triggerRate / (candleCount - 1)) + (feeRate * 2)) / 100; // 목표 수익율 var targetSellPrice = avgPrice + (avgPrice * targetRate); // 매도 목표가 var buyTs = DateTime.Now - LastBuyDate; var sellTs = DateTime.Now - LastSellDate; var result = null as JObject; var args = new object[] { DateTime.Now, coinName, currPrice, prevPrice, highPrice, downRate, upRate, avgPrice, targetSellPrice, triggerDownPrice, triggerUpPrice, targetSellPrice, }; string format = "[{0:T}] {1} : 현재가 {2:N0}, 직전가 {3:N0}, 최고가 {4:N0}, 하락율 {5:F6}, 반등율 {6:F6}, 평단가 {7:N0}"; format += "\r\n[{0:T}] {1} : 매수 하락 촉발가 {8:N0}, 매수 반등 촉발가 {9:N0}, 매도 목표가 {10:N0}"; WriteCurrent(format, args); if (StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) { // 거래 시작 금액 StartKRW = krwBalance; } try { if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) { // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 WriteLog("#### 거래 불가 : 보유현금 {0}, 코인보유금 {1}, 최소 거래 금액 {2},", krwBalance, coinBalance, minTradeKRW); } else if (krwBalance > minTradeKRW && // 보유 현금이 최소거래 금액 보다 크고 sellTs.TotalSeconds >= CandleType.Minute * 60 / 2 && // 매도 이후 분봉의 절반이상이 지나고 currPrice <= triggerDownPrice && currPrice >= triggerUpPrice && // 현재가가 촉발 금액 사이에서 반등하고 downUpRate <= candleCount * 2) // 반등율이 캔들갯수의 2배수가 넘지 않아야 함 { // BUY var total = ToOrderPrice(krwBalance); var avgBuyPrice = currPrice; result = React.executeDeal(true, false, coinName, 0, 0, total); } else if (coinBalance > minTradeKRW && // 코인 보유금이 최소거래 금액 보다 크고 (buyTs.TotalSeconds >= CandleType.Minute * 60 * candleCount / 3 * 2 || // 매도 이후 분봉의 3분2 이상이 지나고 currPrice >= targetSellPrice)) // 현재가가 평단가 보다 (수익율/캔들수-1) + 수료율2배 이상일때 전체 매도 { // SELL // 현재가가 평단가 보다 (수익율/캔들수 + 수료율2배) 이상일때 전체 매도 var vol = coinVol; vol = Math.Truncate(vol * 100000) / 100000; result = React.executeDeal(false, false, coinName, vol, 0, 0); } } catch (Exception ex) { WriteLog(ex.StackTrace); } if (result != null) { var uuid = result.Value <string>("uuid"); var side = result.Value <string>("side"); WriteLog("#### START GetOrderResultAsync : {0}", uuid); result = GetOrderResultAsync(uuid, coinName).GetAwaiter().GetResult(); WriteLog("#### FINISH GetOrderResultAsync : {0}", uuid); var state = result.Value <double>("state"); var price = result.Value <double>("price"); var volume = result.Value <double>("volume"); var tradeCount = result.Value <double>("trade_count"); var trades = result["trades"] as JArray; var tradePrice = trades[0].Value <double>("price"); var tradeVolume = trades[0].Value <double>("volume"); var tradeFunds = trades[0].Value <double>("funds"); args = new object[] { uuid, side, state, price, volume, tradeCount, tradePrice, tradeVolume, tradeFunds }; WriteLog("#### uuid {0}, side {1}, state {2}, price {3:N0}, volume {4:F6}, tradeCount {5:N0}, tradePrice {6:N0}, tradeVolume {7:N0}, tradeFunds {8:N0}", args); if ("bid".Equals(side)) { // BUY LastBuyDate = DateTime.Now; WriteLog("#### {0} BUY : 매수금 {1:N0} : 매수 평단가 {1:N0} : 수량 {3:F6}", coinName, price * volume, price, volume); } else if ("ask".Equals(side)) { // SELL LastSellDate = DateTime.Now; WriteLog("#### {0} SELL : 매도금 {1:N0} : 매도 평단가 {1:N0} : 수량 {3:F6}", coinName, price * volume, price, volume); } // 수익 var balance = GetBalance(coinName); krwBalance = balance.KRWBalance; coinBalance = currPrice * balance.CoinVol; var totalBalance = krwBalance + coinBalance; var profit = totalBalance - StartKRW; var profitRate = (StartKRW == 0) ? 0D : profit / StartKRW * 100; txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); args = new object[] { coinName, StartKRW, totalBalance, profit, profitRate, krwBalance, coinBalance }; WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}, 보유현금 {5:N0}, 코인 평가 {6:N0}", args); } }
private void MinuteCandleByTicks() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = OrderRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) var currPrice = candles.First().Close; // 현재가 var prevPrice = candles[1].Close; // 직전종가 var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 var downPrice = highPrice * (triggerRate + (feeRate * 2)) / 100; // 하락가 var triggerDownPrice = highPrice - downPrice; // 매수 하락 촉발가 var downRate = Math.Min(0D, (currPrice - highPrice) * 100 / highPrice); // 하락율 var upPrice = prevPrice * ((triggerRate / candleCount) + (feeRate * 2)) / 100; // 반등가 var triggerUpPrice = prevPrice + upPrice; // 매수 반등 촉발가 var upRate = Math.Max(0D, (currPrice - prevPrice) * 100 / prevPrice); // 반등 상승율 var downUpRate = upRate == 0 ? 0D : (-downRate / upRate); // 반등율 // 보유현금 및 주문 정보 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double?>("balance") ?? 0D; // 보유 코인 수량 var avgPrice = ask.Value <double?>("avg_buy_price") ?? 0D; // 매수 평단가 var buyLock = bid.Value <double?>("locked") ?? 0D; // 매수 대기 금액 var sellLock = ask.Value <double?>("locked") ?? 0D; // 매도 대기 금액 var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 var coinBalance = currPrice * coinVol; // 코인 평가금 var totalBalance = krwBalance + coinBalance; // 현재 자산 var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 avgPrice = avgPrice < minTradeKRW ? currPrice : avgPrice; // 거래 쿨다운 타임 var buyTs = (DateTime.Now - LastSellDate).TotalSeconds; // 마지막 매도 이후 경과 시간 (초) var buyCoolDownSec = CandleType.Minute * 60; // 매수 쿨다운 시간 (초) var buyCountDownSec = buyCoolDownSec - buyTs; // 매수 쿨다운 시간 (초) var sellTs = (DateTime.Now - LastBuyDate).TotalSeconds; // 마지막 매수 이후 경과 시간 (초) var sellCoolDownSec = (CandleType.Minute + (1 / candleCount)) * 60; // 매도 쿨다운 시간 (초) var sellCountDownSec = sellCoolDownSec - sellTs; // 매도 까지 남은 시간 (초) var targetRate = ((triggerRate / (candleCount - 1)) + (feeRate * 2)) / 100; // 목표 수익율 var targetSellPrice = avgPrice + (avgPrice * targetRate); // 매도 목표가 var args = new object[] { DateTime.Now, coinName, currPrice, prevPrice, highPrice, downRate, upRate, avgPrice, StartKRW, totalBalance, triggerDownPrice, triggerUpPrice, targetSellPrice, sellCountDownSec, buyCountDownSec, }; string format = "[{0:T}] {1} : 현재가 {2:N0}, 직전가 {3:N0}, 최고가 {4:N0}, 하락율 {5:F4}, 반등율 {6:F4}, 평단가 {7:N0}"; format += (sellCountDownSec > 0) ? ", 매수 까지 {13:N0}(초)" : ""; format += (buyCountDownSec > 0) ? ", 매도 까지 {14:N0}(초)" : ""; format += "\r\n[{0:T}] {1} : 시작자산 {8:N0}, 현재자산 {9:N0} 매수 하락 촉발가 {10:N0}, 매수 반등 촉발가 {11:N0}, 매도 목표가 {12:N0}, 매수 목표가 {12:N0}"; WriteCurrent(format, args); var now = DateTime.Now; var line1 = $"[{now:T}] {coinName}"; line1 += $" : 현재가 {currPrice:N0}, 직전가 {prevPrice:N0}, 최고가 {highPrice:N0}"; line1 += $", 하락율 {downRate:F4}, 반등율 {upRate:F4}, 평단가 {avgPrice:N0}"; line1 += (sellCountDownSec > 0) ? $", 매수 까지 {sellCountDownSec:N0}(초)" : ""; line1 += (buyCountDownSec > 0) ? $", 매도 까지 {buyCountDownSec:N0}(초)" : ""; var line2 = $"[{now:T}] {coinName}"; line2 += $" : 시작자산 {StartKRW:N0}, 현재자산 {totalBalance:N0}"; line2 += $", 매수 하락 촉발가 {triggerDownPrice:N0}, 매수 반등 촉발가 {triggerUpPrice:N0}, 매도 목표가 {targetSellPrice:N0}"; WriteCurrent("{0}\r\n{1}", line1, line2); log.Debug(orderChance.ToString(Formatting.Indented)); if (StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) { // 거래 시작 금액 StartKRW = krwBalance; } txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtStartKRW.Text = StartKRW.ToString("N0"); try { var orderResult = null as JObject; var order = null as JObject; var uuid = ""; var side = ""; var state = ""; if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) { // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 WriteLog("#### 거래 불가(금액 부족) : 보유현금 {0}, 코인보유금 {1}, 매도 대기 금액 {2}, 매수 대기 금액 {3}, 최소 거래 금액 {4}", krwBalance, coinBalance, buyLock, sellLock, minTradeKRW); return; } if (sellCountDownSec > 0 && buyCountDownSec > 0) { // 거래 쿨타임 일때 WriteLog("#### 거래 불가(쿨타임) : 매수 까지 남은 시간(초) {0}, 매수 까지 남은 시간(초) {1}, 마지막 매수 {2:T}, 마지막 매도 {3:T}", buyCountDownSec, sellCountDownSec, LastSellDate, LastBuyDate); return; } if (IsWaiting) { // 거래 대기 중일때 uuid = LastOrderResult.Value <string>("uuid"); side = LastOrderResult.Value <string>("side"); state = LastOrderResult.Value <string>("state"); WriteLog("#### 거래 불가(거래 대기중) : side {0}, state {1}, uuid {2}", side, state, uuid); return; } if (krwBalance > minTradeKRW && // 보유 현금이 최소거래 금액 보다 클때 currPrice <= Math.Truncate(triggerDownPrice) && currPrice >= Math.Truncate(triggerUpPrice) && // 현재가가 촉발 금액 사이에서 반등하고 downUpRate <= candleCount * 2) // 반등율이 캔들갯수의 2배수가 넘지 않아야 함 { // BUY var total = ToOrderPrice(krwBalance); var avgBuyPrice = currPrice; orderResult = React.executeDeal(true, false, coinName, 0, 0, total); LastBuyDate = DateTime.Now; WriteLog("#### BUY : {0}", orderResult.ToString(Formatting.Indented)); } else if (coinBalance > minTradeKRW && // 코인 보유금이 최소거래 금액 보다 클때 currPrice >= Math.Truncate(targetSellPrice)) // 현재가가 목표 매수 금액보다 클때 { // SELL var vol = coinVol; vol = Math.Truncate(vol * 100000) / 100000; orderResult = React.executeDeal(false, false, coinName, vol, 0, 0); LastSellDate = DateTime.Now; WriteLog("#### SELL : {0}", orderResult.ToString(Formatting.Indented)); } if (orderResult != null) { IsWaiting = true; LastOrderResult = orderResult; uuid = orderResult.Value <string>("uuid"); side = orderResult.Value <string>("side"); state = orderResult.Value <string>("state"); System.Threading.Thread.Sleep(1500); order = ApiData.checkOrder(uuid); if (order != null) { IsWaiting = false; WriteLog("#### TRADE RESULT : {0}", order.ToString(Formatting.Indented)); var orderState = order.Value <string>("state"); var orderPrice = order.Value <double?>("price") ?? 0D; var orderVolume = order.Value <double?>("volume") ?? 0D; var tradeCount = order.Value <double>("trade_count"); var trades = order["trades"] as JArray; var tradePrice = trades[0].Value <double?>("price") ?? 0D; var tradeVolume = trades[0].Value <double?>("volume") ?? 0D; var tradeFunds = trades[0].Value <double?>("funds") ?? 0D; if ("done".Equals(orderState)) { if ("bid".Equals(side)) { // BUY WriteLog("#### {0} BUY : 매수금 {1:N0} : 매수 평단가 {2:N0} : 수량 {3:F6}", coinName, tradeFunds, tradePrice, tradeVolume); } else if ("ask".Equals(side)) { // SELL WriteLog("#### {0} SELL : 매도금 {1:N0} : 매도 평단가 {2:N0} : 수량 {3:F6}", coinName, tradeFunds, tradePrice, tradeVolume); } // 수익 var balance = GetBalance(coinName); krwBalance = balance.KRWBalance; coinBalance = currPrice * balance.CoinVol; totalBalance = krwBalance + coinBalance; var profit = totalBalance - StartKRW; var profitRate = (StartKRW == 0) ? 0D : profit / StartKRW * 100; txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtProfitPrice.Text = profit.ToString("N0"); txtProfitRate.Text = profitRate.ToString("F4"); args = new object[] { coinName, StartKRW, totalBalance, profit, profitRate, krwBalance, coinBalance }; WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}, 보유현금 {5:N0}, 코인 평가 {6:N0}", args); } } else { WriteLog("#### 거래 결과를 가져올수 없습니다."); } } } catch (Exception ex) { WriteLog(ex.StackTrace); } }
private void PointHalfStrategy() { // 3분봉 2개를 기준으로 이전 시가 에서 현재 금액 등낙률을 가져온다. // 등낙률 0.5% 이상이 되면 오르면 팔고/ 내리면 산다. // 거래시 보유 현금, 보유 코인의 절반을 거래하되 거래 금액이 만원 미만인 경우 전체 금액으로 거래한다. var KRWAccount = ApiData.getAsset().Where(x => "KRW".Equals(x.Value <string>("currency"))).First(); var krwBalance = KRWAccount.Value <double>("balance"); // 보유 현금 txtKRW.Text = krwBalance.ToString("N0"); var candles = ApiData.getCandle <List <Candle> >(CoinName, CandleType, CandleCount); var prevCandle = candles[2]; var currCandle = candles[0]; var currPrice = currCandle.Close; var prevPrice = prevCandle.Close; var orderChance = ApiData.getOrdersChance(CoinName); var ask = orderChance["ask_account"]; var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = (coinVol * currPrice < 5000) ? currPrice : ask.Value <double>("avg_buy_price"); // 매수 평단가 var coinPrice = avgPrice * coinVol; // 보유 코인 금액 var upRatio = (currPrice - avgPrice) / currPrice * 100; // 평단 대비 상승폭 (%) var downRatio = (currPrice - prevPrice) / currPrice * 100; // 현재가 대비 하락폭 (%) var result = null as JObject; // 거래 결과 Debug.WriteLine("upRatio : {0}, downRatio {1}", upRatio, downRatio); WriteLog("upRatio : {0}, downRatio {1}", upRatio, downRatio); try { if (upRatio >= TriggerRatio && coinPrice > 5000) { // 올랐을때 코인 금액 절반 팔기 var vol = (coinPrice / 2) > 5000 ? coinVol / 2 : coinVol; vol = Math.Truncate(vol * 100000) / 100000; Debug.WriteLine("#### {2} SELL : 금액 {0}, 수량 {1}", vol * currPrice, vol, CoinName); WriteLog("#### {2} SELL : 금액 {0}, 수량 {1}", vol * currPrice, vol, CoinName); result = React.executeDeal(false, false, CoinName, vol, 0, 0); } else if (downRatio <= -(TriggerRatio) && krwBalance > 5000) { // 내렸을때 보유 현금 절반으로 코인 사기 var total = (krwBalance / 2) > 5000 ? krwBalance / 2 : krwBalance; total = Math.Truncate(total * 1000) / 1000; Debug.WriteLine("#### {2} BUY : 금액 {0}, 수량 {1}", total, total / currPrice, CoinName); WriteLog("#### {2} BUY : 금액 {0}, 수량 {1}", total, total / currPrice, CoinName); result = React.executeDeal(true, false, CoinName, 0, 0, total); } } catch (Exception ex) { Debug.WriteLine(ex); WriteLog(ex.StackTrace); } if (result != null) { Debug.WriteLine("#### RESULT : {0}", result.ToString()); WriteLog("#### RESULT : {0}", result.ToString()); } }
//private void MinuteCandleByTicks() //{ // // 설정값 // var coinName = Coin.Ticker; // var candleType = CandleType.Name; // var candleMinute = CandleType.Minute; // var candleCount = CandleCount; // var feeRate = FeeRate; // var tradeRate = OrderRate; // var triggerRate = TriggerRate; // // 캔들 갯수 많큼 캔들 가져오기 // var candles = ApiData.getCandle<List<Candle>>(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) // var currPrice = candles.First().Close; // 현재가 // var prevPrice = candles[1].Low; // 직전저가 // var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 // var downPrice = highPrice * (triggerRate + (feeRate * (candleCount - 1))) / 100; // 하락가 // var triggerDownPrice = highPrice - downPrice; // 매수 하락 촉발가 // var downRate = Math.Min(0D, (currPrice - highPrice) * 100 / highPrice); // 하락율 // var upPrice = prevPrice * (feeRate * (candleCount - 1)) / 100; // 반등가 // var triggerUpPrice = prevPrice + upPrice; // 매수 반등 촉발가 // var upRate = (currPrice - prevPrice) * 100 / prevPrice; // 반등 상승율 // var downUpRate = upRate <= 0 && downRate <= 0 ? 0D : (-downRate / upRate); // 반등율 // // 보유현금 및 주문 정보 // var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 // var bid = orderChance["bid_account"]; // var ask = orderChance["ask_account"]; // var krwBalance = bid.Value<double>("balance"); // 보유 현금 // var coinVol = ask.Value<double?>("balance") ?? 0D; // 보유 코인 수량 // var avgPrice = ask.Value<double?>("avg_buy_price") ?? 0D; // 매수 평단가 // var buyLock = bid.Value<double?>("locked") ?? 0D; // 매수 대기 금액 // var sellLock = ask.Value<double?>("locked") ?? 0D; // 매도 대기 금액 // var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 // var coinBalance = currPrice * coinVol; // 코인 평가금 // var totalBalance = krwBalance + coinBalance; // 현재 자산 // var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 // // 거래 쿨다운 타임 // var buyTs = (DateTime.Now - LastSellDate).TotalSeconds; // 마지막 매도 이후 경과 시간 (초) // var buyCoolDownSec = CandleType.Minute * 60 * (candleCount - 2) / (candleCount - 1); // 매수 쿨다운 시간 (초) // var buyRemainCoolDownSec = buyCoolDownSec - buyTs; // 매수 쿨다운 시간 (초) // var sellTs = (DateTime.Now - LastBuyDate).TotalSeconds; // 마지막 매수 이후 경과 시간 (초) // var sellCoolDownSec = (CandleType.Minute + (1 / candleCount)) * 60; // 매도 쿨다운 시간 (초) // var sellRemainCoolDownSec = sellCoolDownSec - sellTs; // 매도 까지 남은 시간 (초) // var targetRate = ((triggerRate / 2) + (feeRate * 2)) / 100; // 목표 수익율 // var targetSellPrice = Math.Round(avgPrice * (1 + targetRate) / 10) * 10; // 매도 목표가 // var now = DateTime.Now; // var line1 = $"[{now:T}] {coinName}"; // line1 += $" : 현재/직전/최고 {currPrice:N0}/{prevPrice:N0}/{highPrice:N0}"; // line1 += $", 하락율/반등율 {downRate:F2}/{upRate:F2}, 평단가 {avgPrice:N0}"; // line1 += (sellRemainCoolDownSec > 0) ? $", 매수쿨 {sellRemainCoolDownSec:N0}(초)" : ""; // line1 += (buyRemainCoolDownSec > 0) ? $", 매도쿨 {buyRemainCoolDownSec:N0}(초)" : ""; // var line2 = $"[{now:T}] {coinName}"; // line2 += $" : 시작자산 {StartKRW:N0}, 현재자산 {totalBalance:N0}"; // line2 += $", 매수 하락 촉발가 {triggerDownPrice:N0}, 매수 반등 촉발가 {triggerUpPrice:N0}, 매도 목표가 {targetSellPrice:N0}"; // WriteCurrent("{0}\r\n{1}", line1, line2); // //WriteLog("orderChance {0}", orderChance.ToString(Formatting.Indented)); // if (StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) // { // // 거래 시작 금액 // StartKRW = krwBalance; // } // txtKRWBalance.Text = krwBalance.ToString("N0"); // txtCoinBalance.Text = coinBalance.ToString("N0"); // txtBalance.Text = totalBalance.ToString("N0"); // txtStartKRW.Text = StartKRW.ToString("N0"); // try // { // var orderResult = null as JObject; // var order = null as JObject; // var uuid = ""; // var side = ""; // var state = ""; // if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) // { // // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 // WriteLog("#### 거래 불가(금액 부족) : 보유현금 {0}, 코인보유금 {1}, 매도 대기 금액 {2}, 매수 대기 금액 {3}, 최소 거래 금액 {4}", krwBalance, coinBalance, buyLock, sellLock, minTradeKRW); // return; // } // if (IsWaiting) // { // // 거래 대기 중일때 // uuid = LastOrderResult.Value<string>("uuid"); // side = LastOrderResult.Value<string>("side"); // state = LastOrderResult.Value<string>("state"); // WriteLog("#### 거래 불가(거래 대기중) : side {0}, state {1}, uuid {2}", side, state, uuid); // return; // } // if (krwBalance > minTradeKRW // 보유 현금이 최소거래 금액 보다 클때 // && buyRemainCoolDownSec <= 0 // 매도 유예시간이 지났을때 // && currPrice <= Math.Truncate(triggerDownPrice) && currPrice >= Math.Truncate(triggerUpPrice) // 현재가가 촉발 금액 사이에서 반등하고 // && downUpRate <= candleCount * 2) // 반등율이 캔들갯수의 2배수가 넘지 않아야 함 // { // // BUY // var total = ToOrderPrice(krwBalance); // var avgBuyPrice = currPrice; // orderResult = React.executeDeal(true, false, coinName, 0, 0, total); // LastBuyDate = DateTime.Now; // WriteLog("#### BUY : {0}", orderResult.ToString(Formatting.Indented)); // } // else if (coinBalance > minTradeKRW // 코인 보유금이 최소거래 금액 보다 클때 // && (sellRemainCoolDownSec <= 0 || currPrice >= Math.Truncate(targetSellPrice))) // 매수 유예시간이 지나거나 현재가가 목표 매수 금액보다 클때 // { // // SELL // var vol = coinVol; // vol = Math.Truncate(vol * 100000) / 100000; // orderResult = React.executeDeal(false, false, coinName, vol, 0, 0); // LastSellDate = DateTime.Now; // WriteLog("#### SELL : {0}", orderResult.ToString(Formatting.Indented)); // } // if (orderResult != null) // { // IsWaiting = true; // LastOrderResult = orderResult; // uuid = orderResult.Value<string>("uuid"); // side = orderResult.Value<string>("side"); // state = orderResult.Value<string>("state"); // System.Threading.Thread.Sleep(1500); // order = ApiData.checkOrder(uuid); // if (order != null) // { // IsWaiting = false; // WriteLog("#### TRADE RESULT : {0}", order.ToString(Formatting.Indented)); // var orderState = order.Value<string>("state"); // var orderPrice = order.Value<double?>("price") ?? 0D; // var orderVolume = order.Value<double?>("volume") ?? 0D; // var tradeCount = order.Value<double>("trade_count"); // var trades = order["trades"] as JArray; // var tradePrice = trades[0].Value<double?>("price") ?? 0D; // var tradeVolume = trades[0].Value<double?>("volume") ?? 0D; // var tradeFunds = trades[0].Value<double?>("funds") ?? 0D; // if ("done".Equals(orderState)) // { // if ("bid".Equals(side)) // { // // BUY // WriteLog("#### {0} BUY : 매수금 {1:N0} : 매수 평단가 {2:N0} : 수량 {3:F6}", coinName, tradeFunds, tradePrice, tradeVolume); // } // else if ("ask".Equals(side)) // { // // SELL // WriteLog("#### {0} SELL : 매도금 {1:N0} : 매도 평단가 {2:N0} : 수량 {3:F6}", coinName, tradeFunds, tradePrice, tradeVolume); // } // // 수익 // var balance = GetBalance(coinName); // krwBalance = balance.KRWBalance; // coinBalance = currPrice * balance.CoinVol; // totalBalance = krwBalance + coinBalance; // var profit = totalBalance - StartKRW; // var profitRate = (StartKRW == 0) ? 0D : profit / StartKRW * 100; // txtKRWBalance.Text = krwBalance.ToString("N0"); // txtCoinBalance.Text = coinBalance.ToString("N0"); // txtBalance.Text = totalBalance.ToString("N0"); // txtProfitPrice.Text = profit.ToString("N0"); // txtProfitRate.Text = profitRate.ToString("F4"); // var args = new object[] { coinName, StartKRW, totalBalance, profit, profitRate, krwBalance, coinBalance }; // WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}, 보유현금 {5:N0}, 코인 평가 {6:N0}", args); // } // } // else // { // WriteLog("#### 거래 결과를 가져올수 없습니다."); // } // } // } // catch (Exception ex) // { // WriteLog(ex.StackTrace); // } //} private async Task MinuteCandleByTicksAsync() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleMinute = CandleType.Minute; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = OrderRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) var currPrice = candles.First().Close; // 현재가 var prevPrice = candles[1].Low; // 직전저가 var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 var downPrice = highPrice * (triggerRate + (feeRate * (candleCount - 1))) / 100; // 하락가 var triggerDownPrice = highPrice - downPrice; // 매수 하락 촉발가 var downRate = Math.Min(0D, (currPrice - highPrice) * 100 / highPrice); // 하락율 var upPrice = prevPrice * (feeRate * (candleCount - 1)) / 100; // 반등가 var triggerUpPrice = prevPrice + upPrice; // 매수 반등 촉발가 var upRate = (currPrice - prevPrice) * 100 / prevPrice; // 반등 상승율 var downUpRate = upRate <= 0 && downRate <= 0 ? 0D : (-downRate / upRate); // 반등율 // 보유현금 및 주문 정보 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double?>("balance") ?? 0D; // 보유 코인 수량 var avgPrice = ask.Value <double?>("avg_buy_price") ?? 0D; // 매수 평단가 var buyLock = bid.Value <double?>("locked") ?? 0D; // 매수 대기 금액 var sellLock = ask.Value <double?>("locked") ?? 0D; // 매도 대기 금액 var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 var coinBalance = currPrice * coinVol; // 코인 평가금 var totalBalance = krwBalance + coinBalance; // 현재 자산 var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 var fee = currPrice * feeRate / 100; // 거래 수수료 var sellFee = coinBalance * feeRate / 100; // 매도 총 수수료 var buyFee = totalBalance * feeRate / 100; // 매수 총 수수료 var buyUnitPrice = GetOrderUnitPrice(krwBalance); // 매수 주문 가격 단위 var sellUnitPrice = GetOrderUnitPrice(coinBalance); // 매도 주문 가격 단위 //var orderUintPrice = GetOrderUnitPrice(currPrice); // 캔들 가격 단위 // 거래 쿨다운 타임 var buyTs = (DateTime.Now - LastSellDate).TotalSeconds; // 마지막 매도 이후 경과 시간 (초) var buyCoolDownSec = CandleType.Minute * 60 * (candleCount - 2) / (candleCount - 1); // 매수 쿨다운 시간 (초) var buyRemainCoolDownSec = buyCoolDownSec - buyTs; // 매수 쿨다운 시간 (초) var sellTs = (DateTime.Now - LastBuyDate).TotalSeconds; // 마지막 매수 이후 경과 시간 (초) var sellCoolDownSec = (CandleType.Minute + (1 / candleCount)) * 60; // 매도 쿨다운 시간 (초) var sellRemainCoolDownSec = sellCoolDownSec - sellTs; // 매도 까지 남은 시간 (초) var targetRate = ((triggerRate / 2) + (feeRate * 2)) / 100; // 목표 수익율 var targetSellPrice = Math.Round(avgPrice * (1 + targetRate) / 10) * 10; // 매도 목표가 var now = DateTime.Now; var line1 = $"[{now:T}] {coinName}"; line1 += $" : 현재/직전/최고 {currPrice:N0}/{prevPrice:N0}/{highPrice:N0}"; line1 += $", 하락율/반등율 {downRate:F2}/{upRate:F2}, 평단가 {avgPrice:N0}"; line1 += (sellRemainCoolDownSec > 0) ? $", 매수쿨 {sellRemainCoolDownSec:N0}(초)" : ""; line1 += (buyRemainCoolDownSec > 0) ? $", 매도쿨 {buyRemainCoolDownSec:N0}(초)" : ""; var line2 = $"[{now:T}] {coinName}"; line2 += $" : 시작자산 {StartKRW:N0}, 현재자산 {totalBalance:N0}"; line2 += $", 매수촉발가(하락/반등) {triggerDownPrice:N0} / {triggerUpPrice:N0}, 매도 목표가 {targetSellPrice:N0}, 매수 수수료 {totalBalance * feeRate / 100:F2}"; WriteCurrent("{0}\r\n{1}", line1, line2); //WriteLog("orderChance {0}", orderChance.ToString(Formatting.Indented)); if (StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) { // 거래 시작 금액 StartKRW = krwBalance; } if (InvokeRequired) { BeginInvoke(new Action(() => { txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtStartKRW.Text = StartKRW.ToString("N0"); })); } else { txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtStartKRW.Text = StartKRW.ToString("N0"); } try { var orderResult = null as JObject; var order = null as JObject; var uuid = ""; var side = ""; var state = ""; if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) { // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 WriteLog("#### 거래 불가(금액 부족) : 보유현금 {0}, 코인보유금 {1}, 매도 대기 금액 {2}, 매수 대기 금액 {3}, 최소 거래 금액 {4}", krwBalance, coinBalance, buyLock, sellLock, minTradeKRW); return; } if (IsWaiting) { // 거래 대기 중일때 uuid = LastOrderResult.Value <string>("uuid"); side = LastOrderResult.Value <string>("side"); state = LastOrderResult.Value <string>("state"); WriteLog("#### 거래 불가(거래 대기중) : side {0}, state {1}, uuid {2}", side, state, uuid); return; } if (krwBalance > minTradeKRW && // 보유 현금이 최소거래 금액 보다 클때 buyRemainCoolDownSec <= 0 && // 매도 유예시간이 지났을때 currPrice <= Math.Truncate(triggerDownPrice) && currPrice >= Math.Truncate(triggerUpPrice) && // 현재가가 촉발 금액 사이에서 반등하고 downUpRate <= candleCount * 2) // 반등율이 캔들갯수의 2배수가 넘지 않아야 함 { // BUY var unitPrice = GetOrderUnitPrice(currPrice); var total = Math.Truncate(coinBalance / unitPrice) * unitPrice; var avgBuyPrice = currPrice; orderResult = React.executeDeal(true, false, coinName, 0, 0, total); IsWaiting = true; LastBuyDate = DateTime.Now; WriteLog("#### BUY : {0}", orderResult.ToString(Formatting.Indented)); var buyUUID = orderResult.Value <string>("uuid"); var buyOrderResult = await GetBuyMarketResultAsync(buyUUID); // SELL if (buyOrderResult != null) { var buyPrice = buyOrderResult.Value <double>("price"); var targetBuyPrice = GetOrderUnitPrice(buyPrice + Math.Max((buyPrice * 0.5 / 100) + (fee * 2), 10)); var buyVol = buyOrderResult.Value <double>("executed_volume"); var sellOrderResult = await GetSellOrderResultAsync(coinName, targetBuyPrice, buyVol); IsWaiting = false; LastBuyDate = DateTime.Now; WriteLog("#### SELL : {0}", sellOrderResult.ToString(Formatting.Indented)); } } //else if (coinBalance > minTradeKRW // 코인 보유금이 최소거래 금액 보다 클때 // && (sellRemainCoolDownSec <= 0 || currPrice >= Math.Truncate(targetSellPrice))) // 매수 유예시간이 지나거나 현재가가 목표 매수 금액보다 클때 //{ // // SELL // var vol = coinVol; // vol = Math.Truncate(vol * 100000) / 100000; // orderResult = React.executeDeal(false, false, coinName, vol, 0, 0); // LastSellDate = DateTime.Now; // WriteLog("#### SELL : {0}", orderResult.ToString(Formatting.Indented)); //} if (orderResult != null) { IsWaiting = true; LastOrderResult = orderResult; uuid = orderResult.Value <string>("uuid"); side = orderResult.Value <string>("side"); state = orderResult.Value <string>("state"); await Task.Delay(1500); order = ApiData.checkOrder(uuid); if (order != null) { IsWaiting = false; WriteLog("#### CHECK ORDER RESULT : {0}", order.ToString(Formatting.Indented)); var orderState = order.Value <string>("state"); var orderPrice = order.Value <double?>("price") ?? 0D; var orderVolume = order.Value <double?>("volume") ?? 0D; var tradeCount = order.Value <double>("trade_count"); var trades = order["trades"] as JArray; var tradePrice = 0D; var tradeVolume = 0D; var tradeFunds = 0D; if (trades != null && trades.Count > 0) { tradePrice = trades[0].Value <double?>("price") ?? 0D; tradeVolume = trades[0].Value <double?>("volume") ?? 0D; tradeFunds = trades[0].Value <double?>("funds") ?? 0D; } if ("done".Equals(orderState)) { if ("bid".Equals(side)) { // BUY WriteLog("#### {0} BUY : 매수금 {1:N0} : 매수 평단가 {2:N0} : 수량 {3:F6}", coinName, tradeFunds, tradePrice, tradeVolume); } else if ("ask".Equals(side)) { // SELL WriteLog("#### {0} SELL : 매도금 {1:N0} : 매도 평단가 {2:N0} : 수량 {3:F6}", coinName, tradeFunds, tradePrice, tradeVolume); } // 수익 var balance = GetBalance(coinName); krwBalance = balance.KRWBalance; coinBalance = currPrice * balance.CoinVol; totalBalance = krwBalance + coinBalance; var profit = totalBalance - StartKRW; var profitRate = (StartKRW == 0) ? 0D : profit / StartKRW * 100; if (InvokeRequired) { BeginInvoke(new Action(() => { txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtProfitPrice.Text = profit.ToString("N0"); txtProfitRate.Text = profitRate.ToString("F4"); })); } else { txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtProfitPrice.Text = profit.ToString("N0"); txtProfitRate.Text = profitRate.ToString("F4"); } var args = new object[] { coinName, StartKRW, totalBalance, profit, profitRate, krwBalance, coinBalance }; WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}, 보유현금 {5:N0}, 코인 평가 {6:N0}", args); } } else { WriteLog("#### 거래 결과를 가져올수 없습니다."); } } } catch (Exception ex) { WriteLog(ex.StackTrace); } }
private void PointHalfStrategy() { // 1분봉 3개를 기준으로 이전 시가 에서 현재 금액 등낙률을 가져온다. // 등낙률 0.5% 이상이 되면 오르면 팔고/ 내리면 산다. // 거래시 보유 현금, 보유 코인의 절반을 거래하되 거래 금액이 만원 미만인 경우 전체 금액으로 거래한다. var idx = Convert.ToInt32(txtMaxRatio.Text); var candleType = BotSetting.CandleTypes[idx]; var candles = ApiData.getCandle <List <Candle> >(CoinName, candleType, 3); var prevCandle = candles[2]; // 시가 봉 var currCandle = candles[0]; // 현재가 봉 var currPrice = currCandle.Close; var prevPrice = prevCandle.Close; var orderChance = ApiData.getOrdersChance(CoinName); var ask = orderChance["ask_account"]; var bid = orderChance["bid_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 //var avgPrice = (coinVol * currPrice < 5000) ? currPrice : ask.Value<double>("avg_buy_price"); // 매수 평단가 var coinPrice = currPrice * coinVol; // 보유 코인 금액 //var upRatio = (currPrice - avgPrice) / currPrice * 100; // 평단 대비 상승폭 (%) //var downRatio = (currPrice - prevPrice) / currPrice * 100; // 현재가 대비 하락폭 (%) var ratio = (currPrice - prevPrice) / currPrice * 100; // 등락폭 (%) var result = null as JObject; // 거래 결과 txtKRW.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinPrice.ToString("N6"); Debug.WriteLine("이전가: {0:D0}, 현재가 {1:D0}, ratio : {2:D4}%", prevPrice, currPrice, ratio); WriteLog("이전가: {0:N0}, 현재가 {1:N0}, ratio : {2:D4}%", prevPrice, currPrice, ratio); //try //{ // if (upRatio >= TriggerRatio && coinPrice > 5000) // { // // 올랐을때 코인 금액 절반 팔기 // var vol = (coinPrice / 2) > 5000 ? coinVol / 2 : coinVol; // vol = Math.Truncate(vol * 100000) / 100000; // Debug.WriteLine("#### {2} SELL : 금액 {0}, 수량 {1}", vol * currPrice, vol, CoinName); // WriteLog("#### {2} SELL : 금액 {0}, 수량 {1}", vol * currPrice, vol, CoinName); // result = React.executeDeal(false, false, CoinName, vol, 0, 0); // } // else if (downRatio <= -(TriggerRatio) && krwBalance > 5000) // { // // 내렸을때 보유 현금 절반으로 코인 사기 // var total = (krwBalance / 2) > 5000 ? krwBalance / 2 : krwBalance; // total = Math.Truncate(total * 1000) / 1000; // Debug.WriteLine("#### {2} BUY : 금액 {0}, 수량 {1}", total, total / currPrice, CoinName); // WriteLog("#### {2} BUY : 금액 {0}, 수량 {1}", total, total / currPrice, CoinName); // result = React.executeDeal(true, false, CoinName, 0, 0, total); // } //} //catch (Exception ex) //{ // Debug.WriteLine(ex); // WriteLog(ex.StackTrace); //} orderChance = ApiData.getOrdersChance(CoinName); ask = orderChance["ask_account"]; bid = orderChance["bid_account"]; krwBalance = bid.Value <double>("balance"); // 보유 현금 coinVol = ask.Value <double>("balance"); // 보유 코인 수량 coinPrice = currPrice * coinVol; // 보유 코인 금액 txtKRW.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinPrice.ToString("N6"); //if (result != null) //{ // Debug.WriteLine("#### RESULT : {0}", result.ToString()); // WriteLog("#### RESULT : {0}", result.ToString()); //} }
private void MinuteCandleByTicks() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = TradeRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount); // 캔들 조회 var currPrice = candles.First().Close; // 현재가 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = ask.Value <double>("avg_buy_price"); // 매수 평단가 var bidLock = bid.Value <double>("locked"); var askLock = ask.Value <double>("locked"); //var avgPrice = ask.Value<double>("avg_buy_price"); // 매수 평단가 //var coinBalance = orderChance.CoinBalance; // 코인 보유금 //var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 //var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 WriteLog("krwBalance {0:N0}, coinVol {1:F6}, avgPrice {2:N0}, bidLock {3:N0}, askLock {4:N0}", krwBalance, coinVol, avgPrice, bidLock, askLock); //// 분봉 N개를 기준으로 직전 시가 에서 현재 금액 등낙률을 가져온다. //var prevCandle = candles[1]; // 직전 캔들 //var lastCandle = candles.Last(); // 마지막 캔들 //var prevPrice = prevCandle.Low; // 직전저가 //var highPrice = candles.GetRange(1, candles.Count - 1).Max(x => x.High); // 최고가 //var changePrice = (currPrice - prevPrice); // 변동가 //var changeRate = (changePrice / currPrice) * 100; // 변동율 //var candlesChange = (currPrice - highPrice); // 캔들 변동가 //var candlesRate = (candlesChange / highPrice) * 100; // 캔들 변동율 //var profit = coinBalance - coinBuyBalance; // 수익 ////var tradeProfitRate = (avgPrice == 0) ? 0D : (profit / avgPrice) * 100; // 수익율 //var targetProfit = coinBuyBalance + (coinBuyBalance * ((triggerRate / candleCount) + (feeRate * 2)) / 100); ////var targetPrice = avgPrice + targetProfit; ////var target = coinBuyPrice //var result = null as JObject; //var args = new object[] { coinName, currPrice, prevPrice, highPrice, changeRate, candlesRate, avgPrice, targetProfit }; //var buyTs = DateTime.Now - LastBuyDate; //var sellTs = DateTime.Now - LastSellDate; //var minutes = sellTs.TotalMinutes; //WriteCurrent("{0} : 현재가 {1:N0}, 직전가 {2:N0}, 시작가 {3:N0}, 직전등락폭 {4:F6}, 등락폭 {5:F6}, 평단가 {6:N0}, 목표가 {7:N0}", args); //if(StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) //{ // // 거래 시작 금액 // StartKRW = krwBalance; //} //try //{ // if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) // { // // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 // WriteLog("#### 거래 불가 : 보유현금 {0}, 코인보유금 {1}, 최소 거래 금액 {2},", krwBalance, coinBalance, minTradeKRW); // } // else if (krwBalance > minTradeKRW // && sellTs.TotalSeconds >= CandleType.Minute * 60 / 2 // && candlesRate <= -(triggerRate + (feeRate * 2)) // && changeRate >= (feeRate * 2)) // { // // BUY // // 보유현금이 최소 거래금액 보다 많음 // // 수익율 초과하여 떨어지다 수수료율 2배 이상 상승 했을때 거래비율 만큼 산다. // var total = ToOrderPrice(krwBalance); // result = React.executeDeal(true, false, coinName, 0, 0, total); // LastBuyDate = DateTime.Now; // WriteLog("#### {0} BUY : 금액 {1:N0}, 수량 {2:F6}", coinName, total, total / currPrice); // } // else if (coinBalance > minTradeKRW // && (buyTs.TotalSeconds >= CandleType.Minute * 60 * candleCount / 2 // || targetProfit <= coinBalance )) // { // // SELL // // 코인평가금 최소 거래금액 보다 많음 // // 분봉 하나의 시간이 지나면 시장가에 전체 매도 // // 현재가가 평단가 보다 (수익율/캔들수 + 수료율2배) 이상일때 전체 매도 // var vol = coinVol; // vol = Math.Truncate(vol * 100000) / 100000; // result = React.executeDeal(false, false, coinName, vol, 0, 0); // LastSellDate = DateTime.Now; // WriteLog("#### {0} SELL : 금액 {1:N0}, 수량 {2:F6}", coinName, vol * currPrice, vol); // } //} //catch (Exception ex) //{ // WriteLog(ex.StackTrace); //} //if (result != null) //{ // var uuid = result.Value<string>("uuid"); // var coinProfit = GetOrderResult(ApiData, uuid, coinName, currPrice, StartKRW); // //WriteLog("#### RESULT : {0}", result.ToString()); // //var coinProfit = GetBalance(ApiData, coinName, StartKRW); // //txtProfitPrice.Text = coinProfit.KrwProfit.ToString("N0"); // //txtProfitRate.Text = coinProfit.KrwProfitRate.ToString("F6"); // var profits = new object[] { coinName, StartKRW, coinProfit.TotalBalance, coinProfit.KrwProfit, coinProfit.KrwProfitRate }; // WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}", profits); //} }
private void MinuteCandleByTicks() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = TradeRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) var currPrice = candles.First().Close; // 현재가 // 보유현금 및 주문 정보 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = ask.Value <double>("avg_buy_price"); // 매수 평단가 var bidLock = bid.Value <double>("locked"); // 매수 대기 금액 var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 var coinBalance = currPrice * coinVol; // 코인 평가금 var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 // 분봉 N개를 기준으로 직전 시가 에서 현재 금액 등낙률을 가져온다. //var prevCandle = candles[1]; // 직전 캔들 //var lastCandle = candles.Last(); // 마지막 캔들 var prevPrice = candles[1].Close; // 직전종가 var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 var triggerDownPrice = highPrice - (highPrice * (triggerRate + (feeRate * 2)) / 100); // 매수 하락 촉발가 var downRate = (currPrice - highPrice) / highPrice * 100; // 하락율 var triggerUpPrice = prevPrice + (prevPrice * ((triggerRate / candleCount + 1) + (feeRate * 2)) / 100); // 매수 반등 촉발가 var upRate = (currPrice - prevPrice) / prevPrice * 100; // 반등 상승율 var downUpRate = upRate == 0 ? 0D : (-downRate / upRate); // 반등율 //var targetDownPrice = prevPrice + (prevPrice * (feeRate * 2) / 100); // 매수 목표가 WriteLog("currPrice {0:N0}, triggerDownPrice {1:N0}, triggerUpPrice {2:N0}, highPrice {3:N0}, prevPrice {4:N0}, downUpRate {5:N0}", currPrice, triggerDownPrice, triggerUpPrice, highPrice, prevPrice, downUpRate); //var changePrice = (currPrice - prevPrice); // 변동가 //var changeRate = (changePrice / currPrice) * 100; // 변동율 //var candlesChange = (currPrice - highPrice); // 캔들 변동가 //var candlesRate = (candlesChange / highPrice) * 100; // 캔들 변동율 //var profit = coinBalance - coinBuyBalance; // 수익 //var tradeProfitRate = (avgPrice == 0) ? 0D : (profit / avgPrice) * 100; // 수익율 //var targetProfit = coinBuyBalance + (coinBuyBalance * ((triggerRate / candleCount) + (feeRate * 2)) / 100); //var targetPrice = avgPrice + targetProfit; //var target = coinBuyPrice //var result = null as JObject; //var args = new object[] { coinName, currPrice, prevPrice, highPrice, changeRate, candlesRate, avgPrice, targetProfit }; var buyTs = DateTime.Now - LastBuyDate; var sellTs = DateTime.Now - LastSellDate; //var minutes = sellTs.TotalMinutes; //WriteCurrent("{0} : 현재가 {1:N0}, 직전가 {2:N0}, 시작가 {3:N0}, 직전등락폭 {4:F6}, 등락폭 {5:F6}, 평단가 {6:N0}, 목표가 {7:N0}", args); if (StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) { // 거래 시작 금액 StartKRW = krwBalance; } try { if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) { // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 WriteLog("#### 거래 불가 : 보유현금 {0}, 코인보유금 {1}, 최소 거래 금액 {2},", krwBalance, coinBalance, minTradeKRW); } else if (krwBalance > minTradeKRW && // 보유 현금이 최소거래 금액 보다 크고 sellTs.TotalSeconds >= CandleType.Minute * 60 / 2 && // 매도 이후 분봉의 절반이상이 지나고 currPrice <= triggerDownPrice && currPrice >= triggerUpPrice && // 현재가가 촉발 금액 사이에서 반등하고 downUpRate <= candleCount * 2) // 반등율이 캔들갯수의 2배수가 넘지 않아야 함 { // BUY var total = ToOrderPrice(krwBalance); var avgBuyPrice = currPrice; //result = React.executeDeal(true, false, coinName, 0, 0, total); LastBuyDate = DateTime.Now; WriteLog("#### {0} BUY : 매수 평단가 {1:N0}, 매수금 {2:N0}, 수량 {3:F6}", coinName, avgBuyPrice, total, total / avgBuyPrice); } //else if (coinBalance > minTradeKRW // && (buyTs.TotalSeconds >= CandleType.Minute * 60 * candleCount / 2 // || targetProfit <= coinBalance)) //{ // // SELL // // 코인평가금 최소 거래금액 보다 많음 // // 분봉 하나의 시간이 지나면 시장가에 전체 매도 // // 현재가가 평단가 보다 (수익율/캔들수 + 수료율2배) 이상일때 전체 매도 // var vol = coinVol; // vol = Math.Truncate(vol * 100000) / 100000; // //result = React.executeDeal(false, false, coinName, vol, 0, 0); // LastSellDate = DateTime.Now; // WriteLog("#### {0} SELL : 금액 {1:N0}, 수량 {2:F6}", coinName, vol * currPrice, vol); //} } catch (Exception ex) { WriteLog(ex.StackTrace); } //if (result != null) //{ // var uuid = result.Value<string>("uuid"); // var coinProfit = GetOrderResult(ApiData, uuid, coinName, currPrice, StartKRW); // //WriteLog("#### RESULT : {0}", result.ToString()); // //var coinProfit = GetBalance(ApiData, coinName, StartKRW); // //txtProfitPrice.Text = coinProfit.KrwProfit.ToString("N0"); // //txtProfitRate.Text = coinProfit.KrwProfitRate.ToString("F6"); // var profits = new object[] { coinName, StartKRW, coinProfit.TotalBalance, coinProfit.KrwProfit, coinProfit.KrwProfitRate }; // WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}", profits); //} }
private void MinuteCandleByTicks() { // 설정값 var coinName = Coin.Ticker; var candleType = CandleType.Name; var candleCount = CandleCount; var feeRate = FeeRate; var tradeRate = TradeRate; var triggerRate = TriggerRate; // 캔들 갯수 많큼 캔들 가져오기 var candles = ApiData.getCandle <List <Candle> >(coinName, candleType, candleCount * 2); // 캔들 조회 (2배로 여유롭게) var currPrice = candles.First().Close; // 현재가 var prevPrice = candles[1].Close; // 직전종가 var highPrice = candles.GetRange(1, candleCount - 1).Max(x => x.High); // 최고가 var downPrice = highPrice * (triggerRate + (feeRate * 2)) / 100; // 하락가 var triggerDownPrice = highPrice - downPrice; // 매수 하락 촉발가 var downRate = Math.Min(0D, (currPrice - highPrice) * 100 / highPrice); // 하락율 var upPrice = prevPrice * ((triggerRate / candleCount) + (feeRate * 2)) / 100; // 반등가 var triggerUpPrice = prevPrice + upPrice; // 매수 반등 촉발가 var upRate = Math.Max(0D, (currPrice - prevPrice) * 100 / prevPrice); // 반등 상승율 var downUpRate = upRate == 0 ? 0D : (-downRate / upRate); // 반등율 // 보유현금 및 주문 정보 var orderChance = ApiData.getOrdersChance(coinName); // 주문 가능 정보 var bid = orderChance["bid_account"]; var ask = orderChance["ask_account"]; var krwBalance = bid.Value <double>("balance"); // 보유 현금 var coinVol = ask.Value <double>("balance"); // 보유 코인 수량 var avgPrice = ask.Value <double>("avg_buy_price"); // 매수 평단가 var bidLock = bid.Value <double>("locked"); // 매수 대기 금액 var coinBuyBalance = avgPrice * coinVol; // 코인 매수금 var coinBalance = currPrice * coinVol; // 코인 평가금 var totalBalance = krwBalance + coinBalance; // 현재 자산 var minTradeKRW = Settings.Default.minTradeKRW; // 최소 거래 금액 avgPrice = avgPrice < minTradeKRW ? currPrice : avgPrice; // 거래 쿨다운 타임 var buyTs = (DateTime.Now - LastSellDate).TotalSeconds; // 매도 경과 시간 (초) var buyCoolDownSec = CandleType.Minute * 60; // 매수 쿨다운 시간 (초) var buyCountDownSec = buyCoolDownSec - buyTs; // 매수 쿨다운 시간 (초) var sellTs = (DateTime.Now - LastBuyDate).TotalSeconds; // 매수 경과 시간 (초) var sellCoolDownSec = (CandleType.Minute * 60 * candleCount / 3 * 2); // 매도 쿨다운 시간 (초) var sellCountDownSec = sellCoolDownSec - sellTs; // 매도 까지 남은 시간 (초) var targetRate = ((triggerRate / (candleCount - 1)) + (feeRate * 2)) / 100; // 목표 수익율 var targetSellPrice = avgPrice + (avgPrice * targetRate); // 매도 목표가 var result = null as JObject; var args = new object[] { DateTime.Now, coinName, currPrice, prevPrice, highPrice, downRate, upRate, avgPrice, StartKRW, totalBalance, triggerDownPrice, triggerUpPrice, targetSellPrice, sellCountDownSec, buyCoolDownSec, }; log.Debug(JsonConvert.SerializeObject(candles)); log.Debug(JsonConvert.SerializeObject(orderChance)); string format = "[{0:T}] {1} : 현재가 {2:N0}, 직전가 {3:N0}, 최고가 {4:N0}, 하락율 {5:F6}, 반등율 {6:F6}, 평단가 {7:N0}"; format += (sellCountDownSec > 0) ? ", 매수 까지 남은 시간(초) {13:N0}" : ""; format += (buyCoolDownSec > 0) ? ", 매도 까지 남은 시간(초) {14:N0}" : ""; format += "\r\n[{0:T}] {1} : 시작자산 {8:N0}, 현재자산 {9:N0} 매수 하락 촉발가 {10:N0}, 매수 반등 촉발가 {11:N0}, 매도 목표가 {12:N0}"; WriteCurrent(format, args); if (StartKRW < minTradeKRW && krwBalance > minTradeKRW && coinBalance < minTradeKRW) { // 거래 시작 금액 StartKRW = krwBalance; } txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtStartKRW.Text = StartKRW.ToString("N0"); var buySates = null as string; var sellSates = null as string; try { if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) { // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 WriteLog("#### 거래 불가 : 보유현금 {0}, 코인보유금 {1}, 최소 거래 금액 {2},", krwBalance, coinBalance, minTradeKRW); return; } if (coinBalance <= minTradeKRW && krwBalance <= minTradeKRW) { // 보유현금과 보유 코인이 최소 거래금액 보다 적으면 거래 없음 WriteLog("#### 거래 불가 : 보유현금 {0}, 코인보유금 {1}, 최소 거래 금액 {2},", krwBalance, coinBalance, minTradeKRW); return; } if (krwBalance > minTradeKRW && // 보유 현금이 최소거래 금액 보다 크고 buySec <= 0D && /* */ // 매도 이후 분봉의 절반이상이 지나고 currPrice <= Math.Truncate(triggerDownPrice) && currPrice >= Math.Truncate(triggerUpPrice) && // 현재가가 촉발 금액 사이에서 반등하고 downUpRate <= candleCount * 2) // 반등율이 캔들갯수의 2배수가 넘지 않아야 함 { // BUY var total = ToOrderPrice(krwBalance); var avgBuyPrice = currPrice; result = React.executeDeal(true, false, coinName, 0, 0, total); buySates = result.Value <string>("state"); if ("cancel".Equals(buySates)) { System.Threading.Thread.Sleep(1000); result = React.executeDeal(true, false, coinName, 0, 0, total); buySates = result.Value <string>("state"); } } else if (coinBalance > minTradeKRW && // 코인 보유금이 최소거래 금액 보다 크고 (sellCountDownSec <= 0D || // 매도 이후 분봉의 3분2 이상이 지나거나 currPrice >= Math.Truncate(targetSellPrice))) // 현재가가 평단가 보다 (수익율/캔들수-1) + 수료율2배 이상일때 전체 매도 { // SELL // 현재가가 평단가 보다 (수익율/캔들수 + 수료율2배) 이상일때 전체 매도 var vol = coinVol; vol = Math.Truncate(vol * 100000) / 100000; result = React.executeDeal(false, false, coinName, vol, 0, 0); sellSates = result.Value <string>("state"); } if (result != null) { WriteLog("{0} RESULT : {1}", coinName, JsonConvert.SerializeObject(result)); var uuid = result.Value <string>("uuid"); var side = result.Value <string>("side"); if (result != null && !"cancel".Equals(buySates)) { WriteLog("#### START GetOrderResultAsync : {0}", uuid); //result = GetOrderResultAsync(uuid); result = GetOrderResult(uuid); WriteLog("#### FINISH GetOrderResultAsync : {0}", uuid); if (result == null) { WriteLog("#### 거래 결과를 가져올수 없습니다."); return; } var state = result.Value <string>("state"); var price = result.Value <double?>("price") ?? 0D; var volume = result.Value <double?>("volume") ?? 0D; var tradeCount = result.Value <double>("trade_count"); var trades = result["trades"] as JArray; var tradePrice = trades[0].Value <double>("price"); var tradeVolume = trades[0].Value <double>("volume"); var tradeFunds = trades[0].Value <double>("funds"); args = new object[] { uuid, side, state, price, volume, tradeCount, tradePrice, tradeVolume, tradeFunds }; WriteLog("#### uuid {0}, side {1}, state {2}, price {3:N0}, volume {4:F6}, tradeCount {5:N0}, tradePrice {6:N0}, tradeVolume {7:N0}, tradeFunds {8:N0}", args); if ("bid".Equals(side)) { // BUY LastBuyDate = DateTime.Now; WriteLog("#### {0} BUY : 매수금 {1:N0} : 매수 평단가 {1:N0} : 수량 {3:F6}", coinName, price * volume, price, volume); } else if ("ask".Equals(side)) { // SELL LastSellDate = DateTime.Now; WriteLog("#### {0} SELL : 매도금 {1:N0} : 매도 평단가 {1:N0} : 수량 {3:F6}", coinName, price * volume, price, volume); } // 수익 var balance = GetBalance(coinName); krwBalance = balance.KRWBalance; coinBalance = currPrice * balance.CoinVol; totalBalance = krwBalance + coinBalance; var profit = totalBalance - StartKRW; var profitRate = (StartKRW == 0) ? 0D : profit / StartKRW * 100; txtKRWBalance.Text = krwBalance.ToString("N0"); txtCoinBalance.Text = coinBalance.ToString("N0"); txtBalance.Text = totalBalance.ToString("N0"); txtProfitPrice.Text = profit.ToString("N0"); txtProfitRate.Text = profitRate.ToString("F4"); args = new object[] { coinName, StartKRW, totalBalance, profit, profitRate, krwBalance, coinBalance }; WriteLog("#### {0} 수익 : 거래시작금액 {1:N0}, 현재평가 금액 {2:N0}, 수익금액 {3:N0}, 수익율 {4:F6}, 보유현금 {5:N0}, 코인 평가 {6:N0}", args); } } } catch (Exception ex) { WriteLog(ex.StackTrace); } }