Forráskód Böngészése

大致完成了订单处理,仍需要进一步完成功能

KarsusNeko 6 éve
szülő
commit
0cf452e6f7

+ 2 - 0
MT5MonkPAMM/MT5MonkPAMM.vcxproj

@@ -109,6 +109,7 @@
       <ConformanceMode>true</ConformanceMode>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
       <AdditionalIncludeDirectories>..\MT5SDK;..\CommonLib\CommonLib;..\cpp_redis\include;</AdditionalIncludeDirectories>
+      <BufferSecurityCheck>false</BufferSecurityCheck>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -147,6 +148,7 @@
       <ConformanceMode>true</ConformanceMode>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
       <AdditionalIncludeDirectories>..\MT5SDK;..\CommonLib\CommonLib;..\cpp_redis\include;</AdditionalIncludeDirectories>
+      <BufferSecurityCheck>false</BufferSecurityCheck>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>

+ 230 - 6
MT5MonkPAMM/PluginInstance.cpp

@@ -136,19 +136,182 @@ void CPluginInstance::OnOrderDelete(const IMTOrder * order)
 
 	//m_api->LoggerOut(MTLogOK, L"OnOrderDelete, login: %lld, ord: %lld, pos: %lld, state: %d, vol_init: %lld, vol_cur: %lld",
 	//	order->Login(), order->Order(), order->PositionID(), order->State(), order->VolumeInitial(), order->VolumeCurrent());
+
+	if (order->Type() != IMTOrder::OP_BUY
+		&& order->Type() != IMTOrder::OP_SELL)
+	{
+		// 不是buy或者sell,不跟,直接退出
+		return;
+	}
 	
+	char order_buf[128];
+	sprintf(order_buf, "%lld", order->Order());
+	IMTAccount* account = m_api->UserCreateAccount();
+	IMTOrder* new_order = m_api->OrderCreate();
+
+	ScopeGuard guard([account, new_order]
+	{
+		account->Release();
+		new_order->Release();
+	});
+
 	// 订单在进入filled状态时,也会产生一个order delete回调
-	for (auto login : m_followers)
+	if (order->Order() == order->PositionID())
 	{
-		if (order->Order() == order->PositionID())
+		// 如果是新建订单,那么写入新纪录
+		char login_buf[128];
+		for (auto login : m_followers)
 		{
-			// 如果是新建订单,那么写入新纪录
+			if (m_api->UserAccountGet(login, account) != MT_RET_OK)
+			{
+				// TODO: 这里失败直接跳过没有做其他处理,下一次进来可能依然会遇到一样的问题
+				continue;
+			}
+			sprintf(login_buf, "%lld", login);
+
+			UINT level = (UINT)(account->Balance() / m_step);
+			UINT volume = round((double)level * order->VolumeCurrent() / 10000) * 100;
+			UINT volume_ext = round((double)level * order->VolumeCurrentExt() / 10000) * 100;
+			UINT init_volume = round((double)level * order->VolumeInitial() / 10000) * 100;
+			UINT init_volume_ext = round((double)level * order->VolumeInitialExt() / 10000) * 100;
+			UINT64 new_order_id = 0;
+
+			// 尚未完成建仓,目前position id不填,仅完成订单后记录
+			new_order->Clear();
+			new_order->VolumeInitial(init_volume);
+			new_order->VolumeCurrent(volume);
+			new_order->Login(login);
+			new_order->Symbol(order->Symbol());
+			new_order->Type(order->Type());
+			new_order->Digits(order->Digits());
+			new_order->DigitsCurrency(order->DigitsCurrency());
+			//new_order->ContractSize(order->ContractSize());
+			new_order->PriceOrder(order->PriceOrder());
+			//new_order->PriceCurrent(order->PriceCurrent());
+			// State不能填PARTIAL FILLED REJECTED EXPIRED
+			new_order->StateSet(IMTOrder::ORDER_STATE_STARTED);
+			new_order->TimeSetup(m_api->TimeCurrent());
+			new_order->TimeSetupMsc(m_api->TimeCurrentMsc());
+			// 一定不能填入time done
+			//new_order->TimeDone(order->TimeDone());
+			//new_order->TimeDoneMsc(order->TimeDoneMsc());
+			// --
+			//new_order->PriceSL(order->PriceSL());
+			//new_order->PriceTP(order->PriceTP());
+			//new_order->Comment(order->Comment());
+			//new_order->ActivationFlags(order->ActivationFlags());
+			//new_order->ActivationMode(order->ActivationMode());
+			//new_order->ActivationPrice(order->ActivationPrice());
+			//new_order->ActivationTime(order->ActivationTime());
+			//new_order->PriceTrigger(order->PriceTrigger());
+			//new_order->RateMargin(order->RateMargin()); //
+			//new_order->ReasonSet(order->Reason()); //
+			//new_order->TypeFill(order->TypeFill()); //
+			//new_order->TypeTime(order->TypeTime()); //
+
+			MTAPIRES ret = m_api->OrderAdd(new_order);
+			if (ret != MT_RET_OK)
+			{
+				m_api->LoggerOut(MTLogErr, L"%lld failed to add order, original order #%lld [%d]", login, order->Login(), ret);
+			}
+			else
+			{
+				new_order_id = new_order->Order();
+			}
+
+			// TODO: 现在做法是,如果level为0,后面都不管
+			// 如果跟单失败,那么position id也为0,所以后面也不应该处理
+			position_context context;
+			context.level = level;
+			context.cur_ord = new_order_id;
+			context.position_id = new_order_id; // 建仓,order id = position id
+			int direction = 1;
+			if (order->Type() == IMTOrder::OP_SELL)
+				direction = -1;
+			context.volume = direction * order->VolumeInitial();
+
+			auto fut = m_redis_client->hset(order_buf, login_buf, std::string((char*)&context, sizeof(context)));
+			m_redis_client->sync_commit();
+			auto rep = fut.get();
+			if (rep.ko())
+			{
+				// FIXME: 错误处理
+			}
 		}
-		else
+	}
+	else
+	{
+		// 如果不是新建订单,先使用position id先检查记录是否存在
+		char login_buf[128];
+		for (auto login : m_followers)
 		{
-			// 如果不是新建订单,先使用position id先检查记录是否存在
+			sprintf(login_buf, "%lld", login);
+			auto fut = m_redis_client->hget(order_buf, login_buf);
+			m_redis_client->sync_commit();
+			auto reply = fut.get();
+
+			// 如果不存在,忽略
+			if (reply.ko())	continue;
+			if (reply.is_null())	continue;
+
+			// 获取context
+			position_context context;
+			memcpy(&context, reply.as_string().c_str(), sizeof(position_context));
+
+			// 按建仓时的叙述,如果level或者position为0,亦忽略该记录
+			if (context.level == 0)			continue;
+			if (context.position_id == 0)	continue;
+
 			// 如果存在,则继续操作
-			// 如果不存在,忽略
+			UINT volume = round((double)context.level * order->VolumeCurrent() / 10000) * 100;
+			UINT volume_ext = round((double)context.level * order->VolumeCurrentExt() / 10000) * 100;
+			UINT init_volume = round((double)context.level * order->VolumeInitial() / 10000) * 100;
+			UINT init_volume_ext = round((double)context.level * order->VolumeInitialExt() / 10000) * 100;
+			UINT64 new_order_id = 0;
+
+			new_order->Clear();
+			new_order->VolumeInitial(init_volume);
+			new_order->VolumeCurrent(volume);
+			new_order->Login(login);
+			new_order->Symbol(order->Symbol());
+			new_order->Type(order->Type());
+			new_order->Digits(order->Digits());
+			new_order->DigitsCurrency(order->DigitsCurrency());
+			//new_order->ContractSize(order->ContractSize());
+			new_order->PriceOrder(order->PriceOrder());
+			//new_order->PriceCurrent(order->PriceCurrent());
+			// State不能填PARTIAL FILLED REJECTED EXPIRED
+			new_order->StateSet(IMTOrder::ORDER_STATE_STARTED);
+			new_order->TimeSetup(m_api->TimeCurrent());
+			new_order->TimeSetupMsc(m_api->TimeCurrentMsc());
+			new_order->PositionID(context.position_id);
+
+			MTAPIRES ret = m_api->OrderAdd(new_order);
+			if (ret != MT_RET_OK)
+			{
+				m_api->LoggerOut(MTLogErr, L"%lld failed to add order, original order #%lld [%d]", login, order->Login(), ret);
+				// FIXME: 如果做单失败该怎么办
+				continue;
+			}
+			else
+			{
+				new_order_id = new_order->Order();
+			}
+
+			// 完成之后,写入新纪录
+			context.cur_ord = new_order_id;
+			int direction = 1;
+			if (order->Type() == IMTOrder::OP_SELL)
+				direction = -1;
+			context.volume += direction * order->VolumeInitial();
+
+			auto wfut = m_redis_client->hset(order_buf, login_buf, std::string((char*)&context, sizeof(context)));
+			m_redis_client->sync_commit();
+			auto wrep = fut.get();
+			if (wrep.ko())
+			{
+				// FIXME: 错误处理
+			}
 		}
 	}
 }
@@ -226,6 +389,67 @@ void CPluginInstance::OnDealPerform(const IMTDeal * deal, IMTAccount * account,
 	//	deal->Login(), deal->Deal(), deal->Order(), deal->PositionID(), deal->Volume(), deal->VolumeClosed());
 
 	// FIXME: 需要检查现在的deal是否和之前的order对应。如果没有记录到,则没法根本无法正常跟单以及平仓
+	char order_buf[128];
+	sprintf(order_buf, "%lld", deal->Order());
+	IMTDeal* new_deal = m_api->DealCreate();
+
+	ScopeGuard guard([new_deal]
+	{
+		new_deal->Release();
+	});
+
+	char login_buf[128];
+	for (auto login : m_followers)
+	{
+		sprintf(login_buf, "%lld", login);
+		auto fut = m_redis_client->hget(order_buf, login_buf);
+		m_redis_client->sync_commit();
+		auto reply = fut.get();
+
+		// 如果不存在,忽略
+		if (reply.ko())	continue;
+		if (reply.is_null())	continue;
+
+		// 获取context
+		position_context context;
+		memcpy(&context, reply.as_string().c_str(), sizeof(position_context));
+
+		// 按建仓时的叙述,如果level或者position为0,亦忽略该记录
+		if (context.level == 0)			continue;
+		if (context.position_id == 0)	continue;
+
+		uint64_t volume = context.level * deal->Volume() / 100;
+		uint64_t volume_ext = context.level * deal->VolumeExt() / 100;
+		uint64_t volume_closed = context.level * deal->VolumeClosed() / 100;
+		uint64_t volume_closed_ext = context.level * deal->VolumeClosed() / 100;
+
+		double prop = (double)volume / deal->Volume();
+		double profit = deal->Profit() * prop;
+		double commission = deal->Commission() * prop;
+		double storage = deal->Storage() * prop;
+		double raw_profit = deal->ProfitRaw() * prop;
+
+		new_deal->Clear();
+		new_deal->DealSet(0);
+		new_deal->Volume(volume);
+		new_deal->VolumeExt(volume_ext);
+		new_deal->VolumeClosed(volume_closed);
+		new_deal->VolumeClosedExt();
+		new_deal->ProfitRaw(raw_profit);
+		new_deal->Profit(profit);
+		new_deal->Commission(commission);
+		new_deal->Storage(storage);
+		new_deal->Order(context.cur_ord);
+		new_deal->PositionID(context.position_id);
+
+		MTAPIRES ret = m_api->DealAdd(new_deal);
+		if (ret != MT_RET_OK)
+		{
+			// TODO: 有没有更多的错误处理?
+			m_api->LoggerOut(MTLogErr, L"%lld cannot add deal [%d], original deal: #%lld", login, ret, deal->Deal());
+			continue;
+		}
+	}
 }
 
 MTAPIRES CPluginInstance::LoadParam()

+ 1 - 1
MT5MonkPAMM/PluginInstance.h

@@ -20,7 +20,7 @@ struct position_context
 	UINT32	level;
 	UINT64	position_id;
 	UINT64	cur_ord;
-	UINT64	volume;
+	INT64	volume; // Õý±íʾbuy£¬¸º±íʾsell
 };
 
 class CPluginInstance