1122 lines
47 KiB
C#
1122 lines
47 KiB
C#
using DevExpress.XtraTreeList.Nodes;
|
|
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
|
using Million;
|
|
using Million.Data;
|
|
using Million.Data.Upbit;
|
|
using Million.Data.Upbit.Order;
|
|
using Million.DbManagement;
|
|
using Million.IndicatorConditionSetup;
|
|
using Million.Manager;
|
|
using Million.SaveData;
|
|
using Million_Buyer.SubForm;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using static Million.CommonProperty;
|
|
|
|
namespace Million_Buyer
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
BuyerMode programMode = BuyerMode.BuyerRealtime;
|
|
|
|
private SavedResultData _saveResultData;
|
|
//결과 데이터
|
|
private List<SearchResult> resultDataList;
|
|
//구매 데이터
|
|
private List<CandleDataList> buyList;
|
|
|
|
bool SetIndicator = false;
|
|
bool ThreadFlag = false;
|
|
bool AliveCheckor = false;
|
|
|
|
private Thread thread = null;
|
|
private Thread orderThread = null;
|
|
private List<Account> accounts = null;
|
|
private PaymentType payment = PaymentType.KRW;
|
|
|
|
private Stopwatch unlimitThreadStopWatch = new Stopwatch();
|
|
private bool unlimitChecker = false;
|
|
private long second = 0;
|
|
|
|
private int cycleCount = 0;
|
|
private double cycleBuyMoney = 0;
|
|
|
|
private int buyCycleCount = 0;
|
|
|
|
private bool buyFlag = true;
|
|
private bool allSell = false;
|
|
|
|
private bool BuyBigthanHighValFlag = false;
|
|
private MCandleTimeType BuyBigthanHighValType;
|
|
private int BigMoneyVolCnt = 0;
|
|
|
|
private bool BigMoneyVolFlag = false;
|
|
private MCandleTimeType BigMoneyVolType;
|
|
|
|
|
|
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
Init();
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
InitManager.InitFunc("Upbit", PaymentType.KRW);
|
|
|
|
cb_BigMoneyVolType.Properties.Items.Clear();
|
|
cb_BigMoneyVolType.Properties.Items.AddRange(InitManager.GetCandleTimeTypes());
|
|
cb_BuyBigthanHighType.Properties.Items.Clear();
|
|
cb_BuyBigthanHighType.Properties.Items.AddRange(InitManager.GetCandleTimeTypes());
|
|
|
|
_saveResultData = new SavedResultData
|
|
{
|
|
BuySetupList = new List<object>(),
|
|
SellSetupList = new List<object>()
|
|
};
|
|
resultDataList = new List<SearchResult>();
|
|
buyList = new List<CandleDataList>();
|
|
|
|
// 현재 연결되어 있는 KEY를 이용하여 확인
|
|
cb_UserList.Items.AddRange(CommonProperty.UserList);
|
|
|
|
//cb_UserList.SelectedIndex = 0;
|
|
unlimitThreadStopWatch.Start();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 실시간 모드일 경우
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void rd_Realtime_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
programMode = BuyerMode.BuyerRealtime;
|
|
SetReadOnly(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Buyer 모드일 경우
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void rd_buyer_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
programMode = BuyerMode.Buyer;
|
|
SetReadOnly(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read Only Set(모드 변경)
|
|
/// </summary>
|
|
/// <param name="flag"></param>
|
|
private void SetReadOnly(bool flag)
|
|
{
|
|
tb_CycleCount.ReadOnly = flag;
|
|
tb_CycleMoneyValue.ReadOnly = flag;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 조건식 폼 띄우기
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_Modify_Click(object sender, EventArgs e)
|
|
{
|
|
var subForm = new IndicatorLoadForm();
|
|
if (subForm.ShowDialog() == DialogResult.OK)
|
|
{
|
|
_saveResultData.SellSetupList = ((List<object>)subForm.selectData["SellSetupList"]);
|
|
_saveResultData.BuySetupList = ((List<object>)subForm.selectData["BuySetupList"]);
|
|
_saveResultData.BuyRegularExpression = subForm.selectData["BuyRegularExpression"]?.ToString();
|
|
_saveResultData.SellRegularExpression = subForm.selectData["SellRegularExpression"]?.ToString();
|
|
_saveResultData.SellExceptionRegularExpression = subForm.selectData["SellExceptionRegularExpression"]?.ToString();
|
|
lb_IndiName.Text = subForm.selectData["Name"].ToString();
|
|
SetIndicator = true;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Start Button Event
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_Start_Click(object sender, EventArgs e)
|
|
{
|
|
if (!SetIndicator)
|
|
{
|
|
MessageBox.Show("Indicator Setting 필요");
|
|
}
|
|
else
|
|
{
|
|
int.TryParse(tb_CycleCount.Text, out cycleCount);
|
|
double.TryParse(tb_CycleMoneyValue.Text, out cycleBuyMoney);
|
|
|
|
|
|
int.TryParse(tb_BigMoneyVolCnt.Text, out BigMoneyVolCnt);
|
|
BigMoneyVolFlag = ck_BigMoneyVol.Checked;
|
|
BigMoneyVolType = (MCandleTimeType)Enum.Parse(typeof(MCandleTimeType), cb_BigMoneyVolType.Text.ToString());
|
|
|
|
BuyBigthanHighValFlag = ck_BuyBigthanHighVal.Checked;
|
|
BuyBigthanHighValType = (MCandleTimeType)Enum.Parse(typeof(MCandleTimeType), cb_BigMoneyVolType.Text.ToString());
|
|
|
|
bt_BuyStart_Click(null, null);
|
|
|
|
CommonProperty.UpperMainIndicatorFlag = cb_UpperMainIndi.Checked;
|
|
CommonProperty.DownBeforeValueFlag = cb_DownBeforeValueFlag.Checked;
|
|
|
|
if (programMode == BuyerMode.Buyer)
|
|
{
|
|
if (cycleCount == 0 || cycleBuyMoney == 0)
|
|
{
|
|
MessageBox.Show("한번에 구입 할 종목 수, 종목 별 구입 금액 입력 바람(Double, Int)");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!ThreadFlag)
|
|
{
|
|
SetReadOnly(true);
|
|
bt_Start.Enabled = false;
|
|
thread = new Thread(ThreadFunction);
|
|
thread.Start();
|
|
|
|
//실시간 검증에는 동작하지 않음
|
|
if (programMode == BuyerMode.Buyer)
|
|
{
|
|
orderThread = new Thread(OrderThreadFunction);
|
|
orderThread.Start();
|
|
}
|
|
|
|
ThreadFlag = true;
|
|
cb_UserList.Enabled = false;
|
|
cb_AccountList.Enabled = false;
|
|
cb_DownBeforeValueFlag.Enabled = false;
|
|
cb_IncludeClearIndicator.Enabled = false;
|
|
cb_UpperMainIndi.Enabled = false;
|
|
rd_buyer.Enabled = false;
|
|
rd_Realtime.Enabled = false;
|
|
cb_StarValueLowOverlapUp.Enabled = false;
|
|
|
|
ck_BigMoneyVol.Enabled = false;
|
|
ck_BuyBigthanHighVal.Enabled = false;
|
|
cb_BigMoneyVolType.Enabled = false;
|
|
cb_BuyBigthanHighType.Enabled = false;
|
|
tb_BigMoneyVolCnt.Enabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop Button Event
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_Stop_Click(object sender, EventArgs e)
|
|
{
|
|
ThreadFlag = false;
|
|
//if (!RealTimeMode && thread != null) thread.Abort();
|
|
//if (!RealTimeMode && orderThread != null) orderThread.Abort();
|
|
|
|
bt_Start.Enabled = true;
|
|
rd_buyer.Enabled = true;
|
|
rd_Realtime.Enabled = true;
|
|
if (rd_buyer.Checked)
|
|
SetReadOnly(false);
|
|
|
|
cb_UserList.Enabled = true;
|
|
cb_AccountList.Enabled = true;
|
|
cb_DownBeforeValueFlag.Enabled = true;
|
|
cb_IncludeClearIndicator.Enabled = true;
|
|
cb_UpperMainIndi.Enabled = true;
|
|
cb_StarValueLowOverlapUp.Enabled = true;
|
|
|
|
ck_BigMoneyVol.Enabled = true;
|
|
ck_BuyBigthanHighVal.Enabled = true;
|
|
cb_BigMoneyVolType.Enabled = true;
|
|
cb_BuyBigthanHighType.Enabled = true;
|
|
tb_BigMoneyVolCnt.Enabled = true;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 실시간 Order 현황 Check(1초에 한번씩 호출할까 2초에 한번할까 고민중
|
|
/// </summary>
|
|
private void OrderThreadFunction()
|
|
{
|
|
InsertLog("Order Thread Start");
|
|
var orderList = CommonProperty.UpbitApi.GetOrderListInformation(UpbitOrderListTypes.waitwatch);
|
|
//setting
|
|
foreach (var item in orderList)
|
|
{
|
|
var account = this.accounts.FirstOrDefault(t => t.UnitCurrency + "-" + t.Currency == item.CoinFullName);
|
|
if (account != null)
|
|
account.Balance = item.ExecutedVolume;
|
|
}
|
|
|
|
while (ThreadFlag)
|
|
{
|
|
//Oder List는 Wait, Watch로 구분되어 있는 List 최신 100개, Done, Cancel로 구분되어 있는 List 최신 100개를 표기함
|
|
orderList = CommonProperty.UpbitApi.GetOrderListInformation(UpbitOrderListTypes.waitwatch);
|
|
//orderList.AddRange(CommonProperty.UpbitApi.GetOrderListInformation(UpbitOrderListTypes.donecancel));
|
|
orderList = orderList.Distinct().ToList();
|
|
|
|
this.BeginInvoke(new Action(delegate ()
|
|
{
|
|
try
|
|
{
|
|
tl_RealtimeOrder.Nodes.Clear();
|
|
foreach (var item in orderList)
|
|
{
|
|
tl_RealtimeOrder.AppendNode(new object[]
|
|
{
|
|
item.Uuid,
|
|
item.CoinFullName,
|
|
item.Side,
|
|
item.OrderPrice,
|
|
item.State,
|
|
item.Volume,
|
|
item.ExecutedVolume,
|
|
item.CreateOrderTime.ToString("yyyy-MM-dd HH:mm:ss")
|
|
}, null);
|
|
}
|
|
|
|
var tempData = orderList.Select(t => t.CoinFullName).ToList();
|
|
var buyListUuids = buyList.Select(t => t.ConGoodsData.CoinFullName).ToList();
|
|
|
|
tempData.AddRange(buyListUuids);
|
|
buyCycleCount = tempData.Distinct().ToList().Count;
|
|
lb_BuyMarketCount.Text = buyCycleCount.ToString();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
InsertLog("Order Thread Error : " + e.Message);
|
|
}
|
|
}));
|
|
|
|
//5초에 한번씩 부르게 처리
|
|
Thread.Sleep(5000);
|
|
}
|
|
InsertLog("Order Thread End");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 실제 동작 Thread
|
|
/// </summary>
|
|
private void ThreadFunction()
|
|
{
|
|
#region Default Setting
|
|
//시간 체크
|
|
var sw = new System.Diagnostics.Stopwatch();
|
|
unlimitThreadStopWatch.Start();
|
|
|
|
var dataList = new Dictionary<MCandleTimeType, List<CandleDataList>>();
|
|
|
|
var sellIndicator = _saveResultData.SellSetupList.OfType<IndicatorCoditionSetup>().ToList();
|
|
var buyIndicator = _saveResultData.BuySetupList.OfType<IndicatorCoditionSetup>().ToList();
|
|
var totalIndicatorList = new List<IndicatorCoditionSetup>();
|
|
|
|
totalIndicatorList.AddRange(sellIndicator);
|
|
totalIndicatorList.AddRange(buyIndicator);
|
|
|
|
var subIndStringList = DataManager.GetSubIndicatorStringList(totalIndicatorList);
|
|
// Sub Indicator Class
|
|
var subIndicator = totalIndicatorList.Where(t => subIndStringList.Any(u => u == t.IndexString)).ToList();
|
|
|
|
var candleTypeList = totalIndicatorList.Select(t => t.MCandleTimeType).ToList();
|
|
candleTypeList.Add(MCandleTimeType.M1);
|
|
candleTypeList = candleTypeList.Distinct().ToList();
|
|
|
|
//사고 파는 rex 데이터 가져오는 부분
|
|
|
|
var buyScript = new InteratorScripter("Buy Script");
|
|
buyScript.regularExpressionString = _saveResultData.BuyRegularExpression;
|
|
var sellScript = new InteratorScripter("Sell Script");
|
|
sellScript.regularExpressionString = _saveResultData.SellRegularExpression;
|
|
var sellExceptionScript = new InteratorScripter("Sell Exception Script");
|
|
sellExceptionScript.regularExpressionString = _saveResultData.SellExceptionRegularExpression;
|
|
|
|
var scriptDic = new Dictionary<string, bool>();
|
|
|
|
//TODO 모든 조건 데이터 미리 계산 필요
|
|
|
|
//save 데이터
|
|
_saveResultData.StartDateTime = DateTime.Now;
|
|
|
|
//구매 후 데이터 여러개 계속 겹치는 경우 제외하기 위한 List
|
|
var overlapBuyManagementList = new Dictionary<string, bool>();
|
|
|
|
bool firstFlag = true;
|
|
|
|
RealtimeDataSettingManager realTimeMsg = null;
|
|
|
|
var standardTime = DateTime.Now;
|
|
|
|
|
|
this.BeginInvoke(new Action(delegate ()
|
|
{
|
|
lb_StartDate.Text = standardTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
}));
|
|
|
|
if (programMode == BuyerMode.BuyerRealtime)
|
|
InsertLog("실시간 검증 구동 중..");
|
|
else if (programMode == BuyerMode.Buyer)
|
|
InsertLog("Buyer 구동 중..");
|
|
|
|
var cnt = 0;
|
|
sw.Start();
|
|
#endregion
|
|
|
|
while (ThreadFlag)
|
|
{
|
|
try
|
|
{
|
|
unlimitThreadStopWatch.Restart();
|
|
if (AliveCheckor)
|
|
{
|
|
AliveCheckor = false;
|
|
InsertLog("Alive");
|
|
}
|
|
|
|
|
|
#region 기본 데이터 Setting
|
|
if (firstFlag)
|
|
{
|
|
realTimeMsg = new RealtimeDataSettingManager(null, programMode, this.payment);
|
|
|
|
var startDateTime = DateTime.Now;
|
|
var endDateTime = startDateTime;
|
|
|
|
dataList = realTimeMsg.GetRealTimeCandleData(candleTypeList, startDateTime, endDateTime, 200);
|
|
|
|
if (dataList == null)
|
|
{
|
|
InsertLog("Buyer Ticker List 종료");
|
|
break;
|
|
}
|
|
#region TODO 이미 구매되어 있는 종목에 대한 기본 데이터 Setting 필요
|
|
if (programMode == BuyerMode.Buyer)
|
|
{
|
|
buyList = InitManager.GetBuyListofAccounts(this.accounts, dataList);
|
|
}
|
|
|
|
this.BeginInvoke(new Action(delegate ()
|
|
{
|
|
InitManager.SettingInit(cb_IncludeClearIndicator.Checked, overlapBuyManagementList, totalIndicatorList);
|
|
foreach (var item in buyList)
|
|
{
|
|
var recentlyData = item.CandleDataLists_Im[0];
|
|
var time = recentlyData.BuyTime;
|
|
|
|
tl_BuyList.AppendNode(new object[]
|
|
{
|
|
item.ConGoodsData.CoinFullName, recentlyData.BuyValue, recentlyData.BuyCount, time.ToString("yyyy-MM-dd HH:mm:ss")
|
|
}, null);
|
|
}
|
|
|
|
lb_BuyMarketCount.Text = buyList.Count.ToString();
|
|
}));
|
|
|
|
#endregion
|
|
|
|
firstFlag = false;
|
|
|
|
sw.Stop();
|
|
InsertLog("Deafult Data Setting 완료..\\r\n" + "Default 계산 시간 : " + sw.Elapsed.ToString());
|
|
LogManager.WriteLog("Default 계산 시간 : " + sw.Elapsed.ToString());
|
|
}
|
|
else
|
|
{
|
|
sw.Restart();
|
|
dataList = realTimeMsg.ProcessRecentlyCandleDatas(dataList, candleTypeList);
|
|
|
|
if (dataList == null)
|
|
{
|
|
InsertLog("Buyer Ticker List 종료");
|
|
break;
|
|
}
|
|
|
|
sw.Stop();
|
|
if (sw.Elapsed.TotalSeconds > 1)
|
|
InsertLog("Ticker 계산 시간 : " + sw.Elapsed.ToString());
|
|
}
|
|
#endregion
|
|
|
|
if (buyList.Count == 0) allSell = false;
|
|
|
|
foreach (var item in realTimeMsg.coinFullNameList)
|
|
{
|
|
#region Indicator 계산 -> Code full name 으로 for문 돌면서 계산 처리
|
|
sw.Restart();
|
|
|
|
var dic = DataManager.GetExecuteData(dataList, totalIndicatorList, item);
|
|
|
|
sw.Stop();
|
|
if (sw.Elapsed.TotalSeconds > 1)
|
|
InsertLog("Execute 계산 시간 : " + sw.Elapsed.ToString());
|
|
|
|
var minDateTime = dic[MCandleTimeType.M1].Select(t => t.DateTime).Min();
|
|
var maxDateTime = dic[MCandleTimeType.M1].Select(t => t.DateTime).Max().AddHours(1);
|
|
|
|
var buyDataList = buyList.FirstOrDefault(t => t.ConGoodsData.CoinFullName == item);
|
|
sw.Restart();
|
|
if (buyDataList != null && buyDataList.CandleDataLists_Im.Count > 0)
|
|
{
|
|
dic = IndicatorSetupManager.CalculateIndicator(dic, totalIndicatorList, minDateTime, maxDateTime, item, true, buyDataList.CandleDataLists_Im[0]);
|
|
}
|
|
else
|
|
{
|
|
dic = IndicatorSetupManager.CalculateIndicator(dic, totalIndicatorList, minDateTime, maxDateTime, item, true);
|
|
}
|
|
|
|
sw.Stop();
|
|
if (sw.Elapsed.TotalSeconds > 1)
|
|
InsertLog("Indicator Calculate 계산 시간 : " + sw.Elapsed.ToString());
|
|
#endregion
|
|
|
|
#region 사고 파는 로직
|
|
//최신 데이터 가져오기
|
|
|
|
var recentlyData = DataManager.GetRecentlyData(dic, MCandleTimeType.M1, true);
|
|
var recentlyDate = recentlyData.DateTime;
|
|
recentlyDate = recentlyDate.AddMinutes(recentlyDate.Minute * -1);
|
|
recentlyDate = recentlyDate.AddHours(-1);
|
|
var beforeData = dic[MCandleTimeType.H1].FirstOrDefault(t => t.DateTime == recentlyDate);
|
|
if (recentlyData == null)
|
|
continue;
|
|
/*
|
|
* 로직 설명
|
|
* 1. Buy List에 있는지 확인
|
|
* 2. 없을 경우 추가(Buy Script 처리)
|
|
* 3. Buy List에 있을 경우 Sell Script 확인
|
|
* 4. Sell 처리 후 결과 처리
|
|
*/
|
|
|
|
//없을 시 -> BUY
|
|
if (!buyList.Any(t => t.ConGoodsData.CoinFullName == item))
|
|
{
|
|
if (!buyFlag) continue;
|
|
|
|
var flag = buyScript.DicExcuteScript(recentlyData.CalculateFlag);
|
|
if (flag)
|
|
{
|
|
if (overlapBuyManagementList[item])
|
|
{
|
|
if (StarValueLowBuyValueUp)
|
|
{
|
|
//if (recentlyData.StartValue < beforeData.HighValue)
|
|
//{
|
|
// foreach (var indi in totalIndicatorList)
|
|
// subIndicatorStateManagement[indi.IndexString][item] = false;
|
|
|
|
// overlapBuyManagementList[item] = false;
|
|
// continue;
|
|
//}
|
|
|
|
if (recentlyData.BuyValue < beforeData.HighValue)
|
|
{
|
|
foreach (var indi in totalIndicatorList)
|
|
subIndicatorStateManagement[indi.IndexString][item] = false;
|
|
|
|
overlapBuyManagementList[item] = true;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
#region Filter 추가
|
|
if (BuyBigthanHighValFlag)
|
|
{
|
|
if (recentlyData.EndValue < dic[BuyBigthanHighValType][dic[BuyBigthanHighValType].Count - 1].HighValue)
|
|
{
|
|
overlapBuyManagementList[item] = false;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (BigMoneyVolFlag)
|
|
{
|
|
var compareList = dic[BigMoneyVolType];
|
|
|
|
var recentlyCompareData = compareList.LastOrDefault();
|
|
var date = recentlyCompareData.DateTime;
|
|
|
|
if ((int)BigMoneyVolType < 60)
|
|
{
|
|
date = date.AddMinutes(((int)BigMoneyVolType * BigMoneyVolCnt) * -1);
|
|
}
|
|
else if ((int)BigMoneyVolType < 1440)
|
|
{
|
|
date = date.AddHours((((int)BigMoneyVolType / 60) * BigMoneyVolCnt) * -1);
|
|
}
|
|
|
|
//임시 5개 비교
|
|
var tempList = compareList.Where(t => t.DateTime > date).ToList();
|
|
tempList.Remove(recentlyCompareData);
|
|
var maxVol = tempList.Max(t => t.MoneyVolume);
|
|
if (maxVol > recentlyCompareData.MoneyVolume)
|
|
{
|
|
overlapBuyManagementList[item] = false;
|
|
continue;
|
|
}
|
|
}
|
|
#endregion
|
|
InsertLog("Insert Buy Logic");
|
|
if (programMode == BuyerMode.Buyer)
|
|
{
|
|
LogManager.WriteLog("Buy CoinFullName : " + item + "\r\nCandleData : " + JsonConvert.SerializeObject(recentlyData), "BuySell");
|
|
InsertLog("Buy Coin Name : " + item + ", DateTime : " + recentlyData.DateTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
if (buyCycleCount >= cycleCount)
|
|
continue;
|
|
}
|
|
sw.Restart();
|
|
//if (resultDataList.Select(t => t.MarketData).ToList().Any(t => t.CoinFullName == item)) continue;
|
|
var time = DateTime.Now;
|
|
var buyData = new CandleDataList();
|
|
buyData.CandleDataLists_Im.Add(recentlyData);
|
|
var valDic = ResultLogicManager.GetIndicateValue(recentlyData.CalculateFlag, totalIndicatorList, recentlyData);
|
|
|
|
recentlyData.BuyValue = OrderbookManager.GetAskPrice(CalculateManager.GetConditionValue(buyScript.regularExpressionString, valDic, recentlyData.CalculateFlag));
|
|
recentlyData.BuyTime = time;
|
|
buyData.ConGoodsData = CommonProperty.selectedMarketOfPlaceList.FirstOrDefault(t => t.CoinFullName == item);
|
|
|
|
// 임시 -> 실시간은 1개만 삿다고 처리
|
|
if (programMode != BuyerMode.Buyer)
|
|
{
|
|
recentlyData.BuyCount = 1;
|
|
}
|
|
else
|
|
{
|
|
recentlyData.BuyCount = Math.Round(cycleBuyMoney / recentlyData.BuyValue, 8);
|
|
buyData.Uuid = OrderBuy(item, recentlyData.BuyCount, recentlyData.BuyValue);
|
|
if (buyData.Uuid == "")
|
|
{
|
|
InsertLog("Return Data 가 에러라서 구매 불가. Log 확인 바람");
|
|
continue;
|
|
}
|
|
buyCycleCount++;
|
|
}
|
|
|
|
buyList.Add(buyData);
|
|
|
|
string str = "Buy : " + item + ",\r\n Buy Candle Data : " + JsonConvert.SerializeObject(recentlyData) + "\r\n";
|
|
LogManager.WriteLog(str, item);
|
|
|
|
overlapBuyManagementList[item] = false;
|
|
|
|
InsertLog(buyData.ConGoodsData.CoinFullName + " Market Data 구입 DateTime : " + time.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
|
|
//grid 처리 구매항목, 구매 가격, 구매 개수, 구매시점
|
|
this.BeginInvoke(new Action(delegate ()
|
|
{
|
|
try
|
|
{
|
|
tl_BuyList.AppendNode(new object[]
|
|
{
|
|
buyData.ConGoodsData.CoinFullName, recentlyData.BuyValue, recentlyData.BuyCount, time.ToString("yyyy-MM-dd HH:mm:ss")
|
|
}, null);
|
|
|
|
lb_BuyMarketCount.Text = buyList.Count.ToString();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
InsertLog("Buy 후 Grid Insert Error : " + e.Message);
|
|
}
|
|
}));
|
|
sw.Stop();
|
|
if (sw.Elapsed.TotalSeconds > 1)
|
|
InsertLog("Buy 계산 로직 : " + sw.Elapsed.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
overlapBuyManagementList[item] = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var flag = false;
|
|
var scriptStr = sellScript.regularExpressionString;
|
|
|
|
if (sellExceptionScript.regularExpressionString != null &&
|
|
sellExceptionScript.regularExpressionString.Length > 0)
|
|
{
|
|
//예외처리 로직 추가
|
|
flag = sellExceptionScript.DicExcuteScript(recentlyData.CalculateFlag);
|
|
if (flag) scriptStr = sellExceptionScript.regularExpressionString;
|
|
}
|
|
|
|
if (!flag)
|
|
{
|
|
//default sell
|
|
flag = sellScript.DicExcuteScript(recentlyData.CalculateFlag);
|
|
scriptStr = sellScript.regularExpressionString;
|
|
}
|
|
|
|
if (allSell) flag = true;
|
|
|
|
if (flag)
|
|
{
|
|
sw.Restart();
|
|
var buyItem = buyList.FirstOrDefault(x => x.ConGoodsData.CoinFullName == item);
|
|
var time = DateTime.Now;
|
|
|
|
var sellItem = recentlyData;
|
|
var valDic = ResultLogicManager.GetIndicateValue(sellItem.CalculateFlag, totalIndicatorList, sellItem);
|
|
|
|
|
|
|
|
sellItem.SellValue = OrderbookManager.GetAskPrice(CalculateManager.GetConditionValue(scriptStr, valDic, sellItem.CalculateFlag), false);
|
|
|
|
var sellVal = sellItem.SellValue;
|
|
|
|
if (allSell)
|
|
{
|
|
// 현재가 던지기
|
|
sellItem.SellValue = OrderbookManager.GetAskPrice(sellItem.EndValue, false);
|
|
sellVal = 0;
|
|
}
|
|
|
|
sellItem.SellTime = time;
|
|
|
|
var buyCandleData = buyItem.CandleDataLists_Im[0];
|
|
var result = DataManager.GetBuyerSearchResult(buyCandleData, recentlyData, buyItem.ConGoodsData);
|
|
|
|
// buycount 에서 sell count를 제외한 양이 미체결 량
|
|
if (programMode == BuyerMode.Buyer)
|
|
{
|
|
LogManager.WriteLog("Sell Point 진입 : " + item, item);
|
|
InsertLog("Sell Point 진입 : " + item);
|
|
recentlyData.BuyCount = Math.Round(cycleBuyMoney / recentlyData.BuyValue, 8);
|
|
result.SellCount = OrderSell(buyItem.ConGoodsData.CoinFullName, buyItem.Uuid, sellVal);
|
|
buyCycleCount--;
|
|
}
|
|
|
|
resultDataList.Add(result);
|
|
|
|
string str = "Sell : " + item + ",\r\n Sell Candle Data : " + JsonConvert.SerializeObject(recentlyData) + "\r\n";
|
|
LogManager.WriteLog(str, item);
|
|
|
|
//초기화 작업
|
|
foreach (var sublIndi in subIndicator)
|
|
{
|
|
CommonProperty.subIndicatorStateManagement[sublIndi.IndexString][item] = false;
|
|
}
|
|
|
|
//처리한 buyList는 삭제
|
|
buyList.Remove(buyItem);
|
|
InsertLog(buyItem.ConGoodsData.CoinFullName + " Market Data 판매 DateTime : " + time.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
this.BeginInvoke(new Action(delegate ()
|
|
{
|
|
try
|
|
{
|
|
//result data insert
|
|
DBConnection.QueryInsertExecuter_SavedBuyerResultData(cb_UserList.Text, Enum.GetName(typeof(BuyerMode), programMode), time, result);
|
|
|
|
//Grid 처리
|
|
TreeListNode buyNode = null;
|
|
|
|
foreach (TreeListNode node in tl_BuyList.Nodes)
|
|
{
|
|
if (node.GetValue("BuyMarket").ToString() == buyItem.ConGoodsData.CoinFullName)
|
|
{
|
|
buyNode = node;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var moneyVal = (sellItem.SellValue * (1 - 0.0015) - buyCandleData.BuyValue * (1 - 0.0015)) * result.SellCount;
|
|
|
|
tl_Result.AppendNode(new object[] {
|
|
buyNode.GetValue("BuyMarket"),
|
|
buyNode.GetValue("BuyValue"),
|
|
buyNode.GetValue("BuyCount"),
|
|
buyNode.GetValue("BuyDateTime"),
|
|
sellItem.SellValue,
|
|
result.SellCount,
|
|
time.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
result.FirstEarningRate,
|
|
moneyVal
|
|
}, null);
|
|
|
|
tl_BuyList.Nodes.Remove(buyNode);
|
|
|
|
lb_BuyMarketCount.Text = buyList.Count.ToString();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
InsertLog("Sell Logic Grid Error" + e.Message);
|
|
}
|
|
}));
|
|
if (sw.Elapsed.TotalSeconds > 1)
|
|
InsertLog("Sell 계산 로직 : " + sw.Elapsed.ToString());
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
cnt++;
|
|
if (cnt % 10000 == 0)
|
|
{
|
|
InsertLog("Scanning......" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
cnt = 0;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
InsertLog("Error : " + e.Message);
|
|
}
|
|
}
|
|
|
|
realTimeMsg.Flag = false;
|
|
|
|
SaveData();
|
|
InsertLog("Thread Out");
|
|
}
|
|
/// <summary>
|
|
/// 데이터 저장 기능
|
|
/// </summary>
|
|
/// <param name="resultDataList"></param>
|
|
public void SaveData()
|
|
{
|
|
if (resultDataList.Count > 0)
|
|
{
|
|
//수익 률 계산 로직 -> 이거는 추후 빼도 될듯
|
|
double totalVal = 0;
|
|
double win = 0;
|
|
double lose = 0;
|
|
double firstProfitRate = 0;
|
|
double firstWin = 0;
|
|
|
|
//승률, 수익률 계산
|
|
foreach (var item in resultDataList)
|
|
{
|
|
if (item.FirstWinFlag) firstWin++;
|
|
|
|
firstProfitRate += item.FirstEarningRate;
|
|
win += item.WinCount;
|
|
lose += item.LoseCount;
|
|
totalVal += item.TotalEarningRate;
|
|
}
|
|
double winRate;
|
|
if (win == 0)
|
|
{
|
|
winRate = 0;
|
|
}
|
|
else if (lose == 0)
|
|
{
|
|
winRate = 100;
|
|
}
|
|
else
|
|
{
|
|
winRate = (win * 100 / (win + lose));
|
|
}
|
|
_saveResultData.ResultDataCount = resultDataList.Count;
|
|
_saveResultData.FirstWinRate = (firstWin * 100) / resultDataList.Count;
|
|
_saveResultData.FirstProfitRate = firstProfitRate;
|
|
_saveResultData.WinRate = winRate;
|
|
_saveResultData.ProfitRate = totalVal / resultDataList.Count;
|
|
_saveResultData.SearchResultList = resultDataList;
|
|
_saveResultData.Name = _saveResultData.SavedDateTime.ToString("yyyy-MM-dd HH:mm:ss") + " Realtime Result";
|
|
_saveResultData.Type = "Data";
|
|
_saveResultData.SaveResultType = "Realtime";
|
|
_saveResultData.ExchangePlace = "Upbit";
|
|
_saveResultData.ParentId = null;
|
|
_saveResultData.EndDateTime = DateTime.Now;
|
|
_saveResultData.SavedDateTime = DateTime.Now;
|
|
|
|
//buy list가 남아 있을 시
|
|
if (buyList.Count > 0)
|
|
{
|
|
foreach (var item in buyList)
|
|
{
|
|
var result = new SearchResult();
|
|
|
|
var buyCandleData = item.CandleDataLists_Im[0];
|
|
|
|
result.CoinFullName = item.ConGoodsData.CoinFullName;
|
|
result.MarketData = item.ConGoodsData;
|
|
result.BuyValueList.Add(buyCandleData.BuyValue);
|
|
result.BuyList.ConGoodsData = item.ConGoodsData;
|
|
result.BuyList.CandleDataLists_Im.Add(buyCandleData);
|
|
result.StartDate = buyCandleData.DateTime;
|
|
result.BuyCount = buyCandleData.BuyCount;
|
|
resultDataList.Add(result);
|
|
}
|
|
}
|
|
|
|
_saveResultData.SearchResultList = resultDataList;
|
|
|
|
DBConnection.QueryInsertExecuter_SavedResultData(_saveResultData);
|
|
|
|
_saveResultData.StartDateTime = DateTime.Now;
|
|
resultDataList.Clear();
|
|
MessageBox.Show("데이터 저장 완료");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 데이터 저장 기능
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_Save_Click(object sender, EventArgs e)
|
|
{
|
|
SaveData();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Text Area 에 Log 입력
|
|
/// </summary>
|
|
/// <param name="log"></param>
|
|
private bool InsertLog(string log)
|
|
{
|
|
this.BeginInvoke(new Action(delegate ()
|
|
{
|
|
if (lb_log.Items.Count > 500)
|
|
{
|
|
lb_log.Items.Clear();
|
|
}
|
|
lb_log.Items.Insert(0, log);
|
|
DBConnection.QueryInsertExecuter_MainLog(DateTime.Now, cb_UserList.Text, log);
|
|
}));
|
|
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// Thread 가 살아 있는지 확인
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_alive_Click(object sender, EventArgs e)
|
|
{
|
|
if (thread != null && thread.IsAlive)
|
|
InsertLog("Realtime Thread Alive.");
|
|
else
|
|
InsertLog("Realtime Thread Death.");
|
|
|
|
if (orderThread != null && orderThread.IsAlive)
|
|
InsertLog("Order List Thread Alive.");
|
|
else
|
|
InsertLog("Order List Thread Death.");
|
|
|
|
AliveCheckor = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 구매 함수
|
|
/// Price가 0일경우 현재가 구매
|
|
/// return data는 uuid임
|
|
/// </summary>
|
|
/// <param name="coinFullName"></param>
|
|
/// <param name="volume"></param>
|
|
/// <param name="price"></param>
|
|
private string OrderBuy(string coinFullName, double volume, double price)
|
|
{
|
|
var side = UpbitOrderSide.bid;
|
|
var ordType = UpbitOrderType.limit;
|
|
|
|
if (price == 0)
|
|
ordType = UpbitOrderType.price;
|
|
var returnData = CommonProperty.UpbitApi.TryOrder(coinFullName, side, volume, price, InsertLog, ordType);
|
|
InsertLog("------------------------------------");
|
|
InsertLog("Buy Return Data : " + JsonConvert.SerializeObject(returnData));
|
|
InsertLog("------------------------------------");
|
|
if (returnData == null) return "";
|
|
return returnData.Uuid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 판매하는 함수
|
|
/// price가 0일 경우 지정가 판매
|
|
/// return data는 총 판매 체결량임
|
|
/// </summary>
|
|
/// <param name="coinFullName"></param>
|
|
/// <param name="volume"></param>
|
|
/// <param name="price"></param>
|
|
private double OrderSell(string coinFullName, string uuid, double price)
|
|
{
|
|
var side = UpbitOrderSide.ask;
|
|
var ordType = UpbitOrderType.limit;
|
|
|
|
if (price == 0)
|
|
ordType = UpbitOrderType.market;
|
|
|
|
// 판매시 Order Cancel 진행
|
|
OrderCancel(coinFullName, uuid);
|
|
|
|
var orderData = CommonProperty.UpbitApi.GetOrderInformation(uuid);
|
|
|
|
if (orderData == null)
|
|
{
|
|
orderData = new Order();
|
|
var account = this.accounts.FirstOrDefault(t => t.UnitCurrency + "-" + t.Currency == coinFullName);
|
|
if (account != null)
|
|
{
|
|
orderData.ExecutedVolume = account.Balance;
|
|
}
|
|
}
|
|
if (orderData.ExecutedVolume != 0)
|
|
{
|
|
var returnData = CommonProperty.UpbitApi.TryOrder(coinFullName, side, orderData.ExecutedVolume, price, InsertLog, ordType);
|
|
|
|
InsertLog("------------------------------------");
|
|
InsertLog("Sell Return Data : " + JsonConvert.SerializeObject(returnData));
|
|
InsertLog("------------------------------------");
|
|
}
|
|
return orderData.ExecutedVolume;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Order 취소 함수
|
|
/// </summary>
|
|
/// <param name="coinFullName"></param>
|
|
/// <param name="uuid"></param>
|
|
private void OrderCancel(string coinFullName, string uuid = "")
|
|
{
|
|
InsertLog("------------------------------------");
|
|
InsertLog("Order Cancel");
|
|
|
|
var orderList = CommonProperty.UpbitApi.GetOrderListInformation(UpbitOrderListTypes.waitwatch, uuid);
|
|
|
|
foreach (var item in orderList)
|
|
{
|
|
if (item.State == "wait" || item.State == "watch")
|
|
{
|
|
if (item.CoinFullName == coinFullName)
|
|
{
|
|
var returnData = CommonProperty.UpbitApi.CancelOrder(item.Uuid);
|
|
InsertLog("Order Cancel Data : " + JsonConvert.SerializeObject(returnData));
|
|
}
|
|
}
|
|
}
|
|
InsertLog("------------------------------------");
|
|
}
|
|
|
|
/// <summary>
|
|
/// User 변경
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void cb_UserList_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
//CommonProperty.ChangeUpbitApiKey.
|
|
var flag = CommonProperty.ChangeUpbitApiKey(cb_UserList.Text);
|
|
if (flag)
|
|
{
|
|
this.accounts = CommonProperty.UpbitApi.GetAccounts();
|
|
|
|
var list = this.accounts.Select(t => t.Currency).ToList();
|
|
foreach (var item in list)
|
|
cb_AccountList.Items.Add(item);
|
|
}
|
|
else
|
|
MessageBox.Show("해당 사용자는 Key List에 존재하지 않습니다.");
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Payment 변경
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void cb_AccountList_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
var account = this.accounts.FirstOrDefault(t => t.Currency == cb_AccountList.Text);
|
|
if (account == null)
|
|
{
|
|
MessageBox.Show("해당 사용자의 Account가 정상적이지 않습니다.");
|
|
}
|
|
else
|
|
{
|
|
var subStr = "원";
|
|
if (cb_AccountList.Text == "KRW")
|
|
{
|
|
this.payment = PaymentType.KRW;
|
|
}
|
|
else if (cb_AccountList.Text == "BTC")
|
|
{
|
|
this.payment = PaymentType.BTC;
|
|
subStr = "Bit Coin";
|
|
}
|
|
else if (cb_AccountList.Text == "USDT")
|
|
{
|
|
this.payment = PaymentType.USDT;
|
|
subStr = "USDT";
|
|
}
|
|
lb_TotalMoney.Text = account.Balance.ToString() + subStr;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 매수 정지 처리
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_BuyStop_Click(object sender, EventArgs e)
|
|
{
|
|
buyFlag = false;
|
|
lb_BuyFlag.Text = "매수 정지";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 매수 진행 처리
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_BuyStart_Click(object sender, EventArgs e)
|
|
{
|
|
buyFlag = true;
|
|
lb_BuyFlag.Text = "매수 진행 중";
|
|
}
|
|
|
|
private void timer1_Tick(object sender, EventArgs e)
|
|
{
|
|
var milli = unlimitThreadStopWatch.ElapsedMilliseconds;
|
|
if (milli > 60000)
|
|
{
|
|
if (!unlimitChecker)
|
|
{
|
|
InsertLog("무한루프 : 60초 이상 동작 하지 않음");
|
|
unlimitChecker = true;
|
|
}
|
|
}
|
|
|
|
if (second > milli)
|
|
{
|
|
unlimitChecker = false;
|
|
}
|
|
second = milli;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모두 팔기 버튼
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void bt_AllSell_Click(object sender, EventArgs e)
|
|
{
|
|
buyFlag = false;
|
|
lb_BuyFlag.Text = "매수 정지";
|
|
|
|
InsertLog("------------------------------------");
|
|
InsertLog("모두 팔기 시작");
|
|
allSell = true;
|
|
InsertLog("------------------------------------");
|
|
}
|
|
|
|
private void groupBox4_Enter(object sender, EventArgs e)
|
|
{
|
|
|
|
}
|
|
}
|
|
} |