521 lines
22 KiB
C#
521 lines
22 KiB
C#
using DevExpress.XtraTreeList.Nodes;
|
|
using Microsoft.CodeAnalysis.CSharp.Scripting;
|
|
using Million;
|
|
using Million.Data;
|
|
using Million.DbManagement;
|
|
using Million.IndicatorConditionSetup;
|
|
using Million.Manager;
|
|
using Million.SaveData;
|
|
using Million_Buyer.SubForm;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
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
|
|
{
|
|
bool RealTimeMode = true;
|
|
public SavedResultData _saveResultData;
|
|
bool SetIndicator = false;
|
|
bool ThreadFlag = false;
|
|
|
|
Thread thread = null;
|
|
|
|
//결과 데이터
|
|
List<SearchResult> resultDataList = new List<SearchResult>();
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
Init();
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
// data setting
|
|
DbServiceFunctions.GetMarketTable_FromDB("Upbit", "KRW");
|
|
|
|
// Result Data DB에 생성
|
|
Million.DbManagement.DBConnection.QueryUpdateExcuter
|
|
(CommonProperty.DbConnectionResultData, DbServiceFunctions.CreateSavedAnalysisDataTableQuery());
|
|
Million.DbManagement.DBConnection.QueryUpdateExcuter
|
|
(CommonProperty.DbConnectionResultData, DbServiceFunctions.CreateSavedResultDataTableQuery());
|
|
Million.DbManagement.DBConnection.QueryUpdateExcuter
|
|
(CommonProperty.DbConnectionResultData, DbServiceFunctions.CreateRealTimeIndicatorTableQuery());
|
|
|
|
// 데이터 검증을 위한 DB Table 생성
|
|
Million.DbManagement.DBConnection.QueryUpdateExcuter
|
|
(CommonProperty.DbConnectionResultData, DbServiceFunctions.CreateVerifyTickerDataTableQuery());
|
|
|
|
_saveResultData = new SavedResultData
|
|
{
|
|
BuySetupList = new List<object>(),
|
|
SellSetupList = new List<object>()
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 실시간 모드일 경우
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void rd_Realtime_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
SetReadOnly(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Buyer 모드일 경우
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void rd_buyer_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
SetReadOnly(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read Only Set(모드 변경)
|
|
/// </summary>
|
|
/// <param name="flag"></param>
|
|
private void SetReadOnly(bool flag)
|
|
{
|
|
RealTimeMode = 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();
|
|
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
|
|
{
|
|
if (!ThreadFlag)
|
|
{
|
|
thread = new Thread(ThreadFunction);
|
|
thread.Start();
|
|
ThreadFlag = true;
|
|
bt_Start.Enabled = false;
|
|
rd_buyer.Enabled = false;
|
|
rd_Realtime.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();
|
|
bt_Start.Enabled = true;
|
|
rd_buyer.Enabled = true;
|
|
rd_Realtime.Enabled = true;
|
|
/*
|
|
* 종료 된 후 데이터 처리 소스는 여기서 처리
|
|
* 1. Grid에 Stop 후 데이터 처리
|
|
* 2. 종료 후 데이터 저장 처리
|
|
*/
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 실제 동작 Thread
|
|
/// </summary>
|
|
private void ThreadFunction()
|
|
{
|
|
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 candleTypeList = totalIndicatorList.Select(t => t.MCandleTimeType).ToList();
|
|
candleTypeList.Add(MCandleTimeType.M1);
|
|
candleTypeList = candleTypeList.Distinct().ToList();
|
|
|
|
//사고 파는 rex 데이터 가져오는 부분
|
|
var buyRex = _saveResultData.BuyRegularExpression;
|
|
var sellRex = _saveResultData.SellRegularExpression;
|
|
|
|
var buyScript = new InteratorScripter();
|
|
buyScript.regularExpressionString = buyRex;
|
|
var sellScript = new InteratorScripter();
|
|
sellScript.regularExpressionString = sellRex;
|
|
|
|
//save 데이터
|
|
_saveResultData.StartDateTime = DateTime.Now;
|
|
|
|
//구매 데이터
|
|
var buyList = new List<CandleDataList>();
|
|
var saveFlag = true;
|
|
|
|
//구매 후 데이터 여러개 계속 겹치는 경우 제외하기 위한 List
|
|
var overlapBuyManagementList = new Dictionary<string, bool>();
|
|
|
|
int firstFlag = 0;
|
|
|
|
RealtimeDataSettingManager realTimeMsg = null;
|
|
|
|
var standardTime = DateTime.Now;
|
|
|
|
this.Invoke(new Action(delegate ()
|
|
{
|
|
lb_StartDate.Text = standardTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
}));
|
|
|
|
if (RealTimeFlag)
|
|
InsertLog("실시간 검증 구동 중..");
|
|
else
|
|
InsertLog("Buyer 구동 중..");
|
|
while (ThreadFlag)
|
|
{
|
|
# region 기본 데이터 Setting
|
|
if (firstFlag == 0)
|
|
{
|
|
realTimeMsg = new RealtimeDataSettingManager(null, PaymentType.KRW);
|
|
dataList = realTimeMsg.GetRealTimeCandleData(candleTypeList, 200);
|
|
foreach (var item in realTimeMsg.codeFullNameList)
|
|
{
|
|
if(cb_IncludeClearIndicator.Checked)
|
|
overlapBuyManagementList[item] = false;
|
|
else
|
|
overlapBuyManagementList[item] = true;
|
|
}
|
|
firstFlag = 1;
|
|
InsertLog("Deafult Data Setting 완료..");
|
|
}
|
|
else
|
|
{
|
|
if (firstFlag == 1)
|
|
{
|
|
dataList = realTimeMsg.ProcessRecentlyCandleDatas(dataList, candleTypeList);
|
|
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
//Ticker 초기화
|
|
if (DateTime.Now.Minute == 0 && saveFlag)
|
|
{
|
|
realTimeMsg.ClearTicker();
|
|
InsertLog("Ticker Data Clear..");
|
|
saveFlag = false;
|
|
}
|
|
else if (DateTime.Now.Minute > 1) saveFlag = true;
|
|
|
|
foreach (var item in realTimeMsg.codeFullNameList)
|
|
{
|
|
# region Indicator 계산 -> Code full name 으로 for문 돌면서 계산 처리
|
|
|
|
var dic = new Dictionary<MCandleTimeType, List<CandleData>>();
|
|
var distinctIndicator = IndicatorSetupManager.Distinct(totalIndicatorList);
|
|
|
|
foreach (var key in dataList.Keys)
|
|
{
|
|
var candleDataList = dataList[key].FirstOrDefault(t => t.ConGoodsData.CodeFullName == item);
|
|
dic[key] = candleDataList.CandleDataLists_Im;
|
|
|
|
var indicatorSetUpList = distinctIndicator.Where(t => t.MCandleTimeType == key).ToList();
|
|
foreach (var setup in indicatorSetUpList)
|
|
{
|
|
setup.excute(dic[key], true);
|
|
}
|
|
}
|
|
|
|
var minDateTime = dic[MCandleTimeType.M1].Select(t => t.DateTime).Min();
|
|
var maxDateTime = dic[MCandleTimeType.M1].Select(t => t.DateTime).Max().AddHours(1);
|
|
|
|
dic = IndicatorSetupManager.CalculateIndicator(dic, totalIndicatorList, minDateTime, maxDateTime, cb_UpperMainIndi.Checked, true);
|
|
#endregion
|
|
|
|
#region 사고 파는 로직
|
|
//최신 데이터 가져오기
|
|
var recentlyData = dic[MCandleTimeType.M1][dic[MCandleTimeType.M1].Count - 1];
|
|
if (recentlyData == null)
|
|
continue;
|
|
/*
|
|
* 로직 설명
|
|
* 1. Buy List에 있는지 확인
|
|
* 2. 없을 경우 추가(Buy Script 처리)
|
|
* 3. Buy List에 있을 경우 Sell Script 확인
|
|
* 4. Sell 처리 후 결과 처리
|
|
*/
|
|
|
|
//없을 시 -> BUY
|
|
if (!buyList.Any(t => t.ConGoodsData.CodeFullName == item))
|
|
{
|
|
var flag = buyScript.DicExcuteScript(recentlyData.CalculateFlag);
|
|
if (flag)
|
|
{
|
|
if (overlapBuyManagementList[item])
|
|
{
|
|
//if (resultDataList.Select(t => t.MarketData).ToList().Any(t => t.CodeFullName == 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(buyRex, valDic, recentlyData.CalculateFlag));
|
|
recentlyData.BuyTime = time;
|
|
|
|
// 임시 -> 실시간은 1개만 삿다고 처리
|
|
recentlyData.BuyCount = 1;
|
|
|
|
buyData.ConGoodsData = dataList[MCandleTimeType.M1].FirstOrDefault(t => t.ConGoodsData.CodeFullName == item).ConGoodsData;
|
|
buyList.Add(buyData);
|
|
overlapBuyManagementList[item] = false;
|
|
InsertLog(buyData.ConGoodsData.CodeFullName + " Market Data 구입 DateTime : " + time.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
//grid 처리 구매항목, 구매 가격, 구매 개수, 구매시점
|
|
this.Invoke(new Action(delegate ()
|
|
{
|
|
tl_BuyList.AppendNode(new object[]
|
|
{buyData.ConGoodsData.CodeFullName, recentlyData.BuyValue, recentlyData.BuyCount, time.ToString("yyyy-MM-dd HH:mm:ss") }, null);
|
|
|
|
lb_BuyMarketCount.Text = buyList.Count.ToString();
|
|
}));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
overlapBuyManagementList[item] = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var flag = sellScript.DicExcuteScript(recentlyData.CalculateFlag);
|
|
if (flag)
|
|
{
|
|
var buyItem = buyList.FirstOrDefault(x => x.ConGoodsData.CodeFullName == item);
|
|
|
|
var time = DateTime.Now;
|
|
var sellItem = recentlyData;
|
|
var valDic = ResultLogicManager.GetIndicateValue(sellItem.CalculateFlag, totalIndicatorList, sellItem);
|
|
sellItem.SellValue = OrderbookManager.GetAskPrice(CalculateManager.GetConditionValue(sellRex, valDic, sellItem.CalculateFlag));
|
|
sellItem.SellTime = time;
|
|
|
|
var buyCandleData = buyItem.CandleDataLists_Im[0];
|
|
|
|
var sellVal = sellItem.SellValue;
|
|
|
|
var result = new SearchResult();
|
|
var rate = ((sellVal - buyCandleData.BuyValue) / buyCandleData.BuyValue) * 100;
|
|
result.FirstEarningRate = rate;
|
|
result.EndDate = sellItem.DateTime;
|
|
result.CodeFullName = buyItem.ConGoodsData.CodeFullName;
|
|
result.MarketData = buyItem.ConGoodsData;
|
|
result.BuyEarningRate.Add(rate);
|
|
result.BuyValueList.Add(buyCandleData.BuyValue);
|
|
result.BuyList.ConGoodsData = buyItem.ConGoodsData;
|
|
result.BuyList.CandleDataLists_Im.Add(buyItem.CandleDataLists_Im[0]);
|
|
result.StartDate = buyItem.CandleDataLists_Im[0].DateTime;
|
|
result.SellData = sellItem;
|
|
result.SellValue = sellVal;
|
|
result.TotalEarningRate = rate;
|
|
result.WinCount = rate > 0 ? 1 : 0;
|
|
result.LoseCount = rate < 0 ? 1 : 0;
|
|
result.FirstWinFlag = rate > 0 ? true : false;
|
|
|
|
//실시간 검증은 1개로 처리
|
|
result.BuyCount = buyItem.CandleDataLists_Im[0].BuyCount;
|
|
result.SellCount = buyItem.CandleDataLists_Im[0].BuyCount;
|
|
|
|
resultDataList.Add(result);
|
|
//처리한 buyList는 삭제
|
|
buyList.Remove(buyItem);
|
|
InsertLog(buyItem.ConGoodsData.CodeFullName + " Market Data 판매 DateTime : " + time.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
this.Invoke(new Action(delegate ()
|
|
{
|
|
//Grid 처리
|
|
TreeListNode buyNode = null;
|
|
|
|
foreach (TreeListNode node in tl_BuyList.Nodes)
|
|
{
|
|
if (node.GetValue("BuyMarket").ToString() == buyItem.ConGoodsData.CodeFullName)
|
|
{
|
|
buyNode = node;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var moneyVal = (sellVal * (1 - 0.0005) - buyCandleData.BuyValue * (1 - 0.0005)) * result.BuyCount;
|
|
|
|
tl_Result.AppendNode(new object[] {
|
|
buyNode.GetValue("BuyMarket"),
|
|
buyNode.GetValue("BuyValue"),
|
|
buyNode.GetValue("BuyCount"),
|
|
buyNode.GetValue("BuyDateTime"),
|
|
sellVal,
|
|
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();
|
|
double totalRate = 0;
|
|
double totalMoneyValue = 0;
|
|
foreach (var resultData in resultDataList)
|
|
{
|
|
totalRate += resultData.FirstEarningRate;
|
|
if (!RealTimeFlag)
|
|
{
|
|
// 총 돈량 측정
|
|
totalMoneyValue += (resultData.SellValue * (1 - 0.0005) - resultData.BuyValueList[0] * (1 - 0.0005)) * resultData.BuyCount;
|
|
}
|
|
}
|
|
|
|
lb_TotalRate.Text = totalRate + "%";
|
|
|
|
if (!RealTimeFlag)
|
|
lb_TotalMoneyValue.Text = totalMoneyValue + "원";
|
|
}));
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
//Stop 시 저장 -> Real Time의 경우 Search Result List만 저장
|
|
if (RealTimeFlag)
|
|
{
|
|
SaveData(resultDataList);
|
|
}
|
|
else
|
|
{
|
|
//이거는 결정해야함
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 데이터 저장 기능
|
|
/// </summary>
|
|
/// <param name="resultDataList"></param>
|
|
public void SaveData(List<SearchResult> resultDataList)
|
|
{
|
|
if (resultDataList.Count > 0)
|
|
{
|
|
_saveResultData.EndDateTime = DateTime.Now;
|
|
_saveResultData.SavedDateTime = DateTime.Now;
|
|
_saveResultData.SearchResultList = resultDataList;
|
|
|
|
//수익 률 계산 로직 -> 이거는 추후 빼도 될듯
|
|
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;
|
|
|
|
DBConnection.QueryInsertExcuter_SavedResultData(_saveResultData);
|
|
|
|
_saveResultData.StartDateTime = DateTime.Now;
|
|
resultDataList.Clear();
|
|
MessageBox.Show("데이터 저장 완료");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 데이터 저장 기능
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void button1_Click(object sender, EventArgs e)
|
|
{
|
|
SaveData(resultDataList);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Text Area 에 Log 입력
|
|
/// </summary>
|
|
/// <param name="log"></param>
|
|
private void InsertLog(string log)
|
|
{
|
|
this.Invoke(new Action(delegate ()
|
|
{
|
|
if (lb_log.Items.Count > 500)
|
|
{
|
|
lb_log.Items.Clear();
|
|
}
|
|
lb_log.Items.Insert(0, log);
|
|
}));
|
|
}
|
|
}
|
|
}
|