|
|
@@ -42,9 +42,14 @@ MTAPIRES CPluginInstance::Start(IMTServerAPI * server)
|
|
|
m_api->LoggerOut(MTLogAtt, L"Order subscribe failed [%d]", ret);
|
|
|
return ret;
|
|
|
}
|
|
|
- if (ret = m_api->DealSubscribe(this) != MT_RET_OK)
|
|
|
+ //if (ret = m_api->DealSubscribe(this) != MT_RET_OK)
|
|
|
+ //{
|
|
|
+ // m_api->LoggerOut(MTLogAtt, L"Deal subscribe failed [%d]", ret);
|
|
|
+ // return ret;
|
|
|
+ //}
|
|
|
+ if (ret = m_api->TradeSubscribe(this) != MT_RET_OK)
|
|
|
{
|
|
|
- m_api->LoggerOut(MTLogAtt, L"Deal subscribe failed [%d]", ret);
|
|
|
+ m_api->LoggerOut(MTLogAtt, L"Trade subscribe failed [%d]", ret);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
@@ -75,13 +80,16 @@ MTAPIRES CPluginInstance::Stop()
|
|
|
}
|
|
|
|
|
|
if ((ret = m_api->PluginUnsubscribe(this)) != MT_RET_OK && ret != MT_RET_ERR_NOTFOUND)
|
|
|
- m_api->LoggerOut(MTLogErr, L"failed to unsubscribe from plugin config updates [%s (%u)]",
|
|
|
+ m_api->LoggerOut(MTLogErr, L"Failed to unsubscribe from plugin config updates [%s (%u)]",
|
|
|
SMTFormat::FormatError(ret), ret);
|
|
|
if ((ret = m_api->OrderUnsubscribe(this)) != MT_RET_OK && ret != MT_RET_ERR_NOTFOUND)
|
|
|
- m_api->LoggerOut(MTLogErr, L"failed to unsubscribe order [%s (%u)]",
|
|
|
+ m_api->LoggerOut(MTLogErr, L"Failed to unsubscribe order sink [%s (%u)]",
|
|
|
SMTFormat::FormatError(ret), ret);
|
|
|
- if ((ret = m_api->DealUnsubscribe(this)) != MT_RET_OK && ret != MT_RET_ERR_NOTFOUND)
|
|
|
- m_api->LoggerOut(MTLogErr, L"failed to unsubscribe deal [%s (%u)]",
|
|
|
+ //if ((ret = m_api->DealUnsubscribe(this)) != MT_RET_OK && ret != MT_RET_ERR_NOTFOUND)
|
|
|
+ // m_api->LoggerOut(MTLogErr, L"failed to unsubscribe deal [%s (%u)]",
|
|
|
+ // SMTFormat::FormatError(ret), ret);
|
|
|
+ if ((ret = m_api->TradeUnsubscribe(this)) != MT_RET_OK && ret != MT_RET_ERR_NOTFOUND)
|
|
|
+ m_api->LoggerOut(MTLogErr, L"Failed to unsubscribe trade sink [%s (%u)]",
|
|
|
SMTFormat::FormatError(ret), ret);
|
|
|
|
|
|
m_api = nullptr;
|
|
|
@@ -148,6 +156,8 @@ void CPluginInstance::OnOrderDelete(const IMTOrder * order)
|
|
|
|
|
|
char order_buf[128];
|
|
|
sprintf(order_buf, "%lld", order->PositionID());
|
|
|
+ UINT64 position = order->PositionID();
|
|
|
+ UINT64 order_id = order->Order();
|
|
|
IMTAccount* account = m_api->UserCreateAccount();
|
|
|
IMTOrder* new_order = m_api->OrderCreate();
|
|
|
|
|
|
@@ -165,7 +175,8 @@ void CPluginInstance::OnOrderDelete(const IMTOrder * order)
|
|
|
if (order->Order() == order->PositionID())
|
|
|
{
|
|
|
// 如果是新建订单,那么写入新纪录
|
|
|
- char login_buf[128];
|
|
|
+ char login_buf[128] = { 0 };
|
|
|
+ char req_buf[128] = { 0 };
|
|
|
for (auto login : m_followers)
|
|
|
{
|
|
|
if (m_api->UserAccountGet(login, account) != MT_RET_OK)
|
|
|
@@ -184,6 +195,18 @@ void CPluginInstance::OnOrderDelete(const IMTOrder * order)
|
|
|
|
|
|
m_api->LoggerOut(MTLogOK, L"add order, vol_init: %lld, vol_cur: %lld", init_volume, volume);
|
|
|
|
|
|
+ char msg[1024] = { 0 };
|
|
|
+ sprintf(msg, "orig_position=&lld&login=%lld&source_login=1005&symbol=%s&action=200&type=%d&volume=%lld&price_order=%lf",
|
|
|
+ order->PositionID(), login, ws2s(order->Symbol()).c_str(), order->Type(), init_volume, order->PriceOrder());
|
|
|
+ m_redis_client->publish("dealer_send", msg, [this, position, login, order_id](cpp_redis::reply& r)
|
|
|
+ {
|
|
|
+ // 记录下login order等信息
|
|
|
+ m_api->LoggerOut(MTLogErr, L"original position #%lld, original order #%lld, login %lld, failed to excute dealer_send",
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ // dealer send之后需要另外一边记录request id
|
|
|
+
|
|
|
// 尚未完成建仓,目前position id不填,仅完成订单后记录
|
|
|
new_order->Clear();
|
|
|
new_order->VolumeInitial(init_volume);
|
|
|
@@ -404,151 +427,161 @@ void CPluginInstance::OnOrderDelete(const IMTOrder * order)
|
|
|
// m_api->LoggerOut(MTLogOK, L"OndealClean, Login: %d", login);
|
|
|
//}
|
|
|
|
|
|
-void CPluginInstance::OnDealPerform(const IMTDeal * deal, IMTAccount * account, IMTPosition * position)
|
|
|
-{
|
|
|
- // position为nullptr时,说明该deal不是由交易本身触发
|
|
|
- // account是deal完成后的用户状况
|
|
|
- // position是交易完成后的持仓状况
|
|
|
- // 对于deal是关闭一个持仓的情况,该position的volume会是0
|
|
|
- if (position == nullptr
|
|
|
- || deal == nullptr
|
|
|
- || account == nullptr)
|
|
|
- return;
|
|
|
-
|
|
|
- std::lock_guard<decltype(m_lock)> lk(m_lock);
|
|
|
- if (!m_enable) return;
|
|
|
- if (deal->Login() != m_trader) return;
|
|
|
-
|
|
|
- //m_api->LoggerOut(MTLogOK, L"OnDealPerform, login: %lld, deal: %lld, ord: %lld, pos: %lld, vol: %lld, volc: %lld",
|
|
|
- // deal->Login(), deal->Deal(), deal->Order(), deal->PositionID(), deal->Volume(), deal->VolumeClosed());
|
|
|
-
|
|
|
- // FIXME: 需要检查现在的deal是否和之前的order对应。如果没有记录到,则没法根本无法正常跟单以及平仓
|
|
|
- char order_buf[128];
|
|
|
- sprintf(order_buf, "%lld", deal->PositionID());
|
|
|
- IMTDeal* new_deal = m_api->DealCreate();
|
|
|
-
|
|
|
- std::vector<std::string>* fields = nullptr;
|
|
|
-
|
|
|
- ScopeGuard guard([new_deal, &fields, this]
|
|
|
- {
|
|
|
- new_deal->Release();
|
|
|
- if (fields)
|
|
|
- {
|
|
|
- fields->clear();
|
|
|
- delete fields;
|
|
|
- fields = nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- // 退出前调用commit
|
|
|
- m_redis_client->commit();
|
|
|
- });
|
|
|
-
|
|
|
- char login_buf[128];
|
|
|
- for (auto login : m_followers)
|
|
|
- {
|
|
|
- ScopeGuard g([position, &fields, this, login, login_buf]()
|
|
|
- {
|
|
|
- if (position->Volume() == 0)
|
|
|
- {
|
|
|
- if (fields == nullptr)
|
|
|
- fields = new(std::vector<std::string>);
|
|
|
-
|
|
|
- m_api->LoggerOut(MTLogOK, L"add field %lld to be delete", login);
|
|
|
- fields->push_back(login_buf);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- sprintf(login_buf, "%lld", login);
|
|
|
- auto fut = m_redis_client->hget(order_buf, login_buf);
|
|
|
- m_redis_client->sync_commit();
|
|
|
- auto reply = fut.get();
|
|
|
-
|
|
|
- m_api->LoggerOut(MTLogOK, L"%lld add deal, original deal #%lld", login, deal->Deal());
|
|
|
-
|
|
|
- // 如果不存在,忽略
|
|
|
- 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;
|
|
|
-
|
|
|
- m_api->LoggerOut(MTLogOK, L"add new deal, volume %lld, volume closed %lld, order #%lld, position #%lld", volume, volume_closed, context.cur_ord, context.position_id);
|
|
|
-
|
|
|
- new_deal->Clear();
|
|
|
- new_deal->Assign(deal);
|
|
|
-
|
|
|
- new_deal->Login(login);
|
|
|
- new_deal->DealSet(0);
|
|
|
- new_deal->Volume(volume);
|
|
|
- new_deal->VolumeExt(volume_ext);
|
|
|
- new_deal->VolumeClosed(volume_closed);
|
|
|
- new_deal->VolumeClosedExt(volume_closed_ext);
|
|
|
- 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] to order #%lld, original deal: #%lld", login, ret, context.cur_ord, deal->Deal());
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- m_api->LoggerOut(MTLogOK, L"add deal #%lld, original deal #%lld", new_deal->Deal(), deal->Deal());
|
|
|
-
|
|
|
- m_redis_client->publish("mt5_balance_fix", login_buf, [this](cpp_redis::reply r)
|
|
|
- {
|
|
|
- if (r.ko())
|
|
|
- {
|
|
|
- m_api->LoggerOut(MTLogErr, L"redis publish: %s", r.error().c_str());
|
|
|
- }
|
|
|
- });
|
|
|
- // commit 在退出前完成
|
|
|
- }
|
|
|
+//void CPluginInstance::OnDealPerform(const IMTDeal * deal, IMTAccount * account, IMTPosition * position)
|
|
|
+//{
|
|
|
+// // position为nullptr时,说明该deal不是由交易本身触发
|
|
|
+// // account是deal完成后的用户状况
|
|
|
+// // position是交易完成后的持仓状况
|
|
|
+// // 对于deal是关闭一个持仓的情况,该position的volume会是0
|
|
|
+// if (position == nullptr
|
|
|
+// || deal == nullptr
|
|
|
+// || account == nullptr)
|
|
|
+// return;
|
|
|
+//
|
|
|
+// std::lock_guard<decltype(m_lock)> lk(m_lock);
|
|
|
+// if (!m_enable) return;
|
|
|
+// if (deal->Login() != m_trader) return;
|
|
|
+//
|
|
|
+// //m_api->LoggerOut(MTLogOK, L"OnDealPerform, login: %lld, deal: %lld, ord: %lld, pos: %lld, vol: %lld, volc: %lld",
|
|
|
+// // deal->Login(), deal->Deal(), deal->Order(), deal->PositionID(), deal->Volume(), deal->VolumeClosed());
|
|
|
+//
|
|
|
+// // FIXME: 需要检查现在的deal是否和之前的order对应。如果没有记录到,则没法根本无法正常跟单以及平仓
|
|
|
+// char order_buf[128];
|
|
|
+// sprintf(order_buf, "%lld", deal->PositionID());
|
|
|
+// IMTDeal* new_deal = m_api->DealCreate();
|
|
|
+//
|
|
|
+// std::vector<std::string>* fields = nullptr;
|
|
|
+//
|
|
|
+// ScopeGuard guard([new_deal, &fields, this]
|
|
|
+// {
|
|
|
+// new_deal->Release();
|
|
|
+// if (fields)
|
|
|
+// {
|
|
|
+// fields->clear();
|
|
|
+// delete fields;
|
|
|
+// fields = nullptr;
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 退出前调用commit
|
|
|
+// m_redis_client->commit();
|
|
|
+// });
|
|
|
+//
|
|
|
+// char login_buf[128];
|
|
|
+// for (auto login : m_followers)
|
|
|
+// {
|
|
|
+// ScopeGuard g([position, &fields, this, login, login_buf]()
|
|
|
+// {
|
|
|
+// if (position->Volume() == 0)
|
|
|
+// {
|
|
|
+// if (fields == nullptr)
|
|
|
+// fields = new(std::vector<std::string>);
|
|
|
+//
|
|
|
+// m_api->LoggerOut(MTLogOK, L"add field %lld to be delete", login);
|
|
|
+// fields->push_back(login_buf);
|
|
|
+// }
|
|
|
+// });
|
|
|
+//
|
|
|
+// sprintf(login_buf, "%lld", login);
|
|
|
+// auto fut = m_redis_client->hget(order_buf, login_buf);
|
|
|
+// m_redis_client->sync_commit();
|
|
|
+// auto reply = fut.get();
|
|
|
+//
|
|
|
+// m_api->LoggerOut(MTLogOK, L"%lld add deal, original deal #%lld", login, deal->Deal());
|
|
|
+//
|
|
|
+// // 如果不存在,忽略
|
|
|
+// 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;
|
|
|
+//
|
|
|
+// m_api->LoggerOut(MTLogOK, L"add new deal, volume %lld, volume closed %lld, order #%lld, position #%lld", volume, volume_closed, context.cur_ord, context.position_id);
|
|
|
+//
|
|
|
+// new_deal->Clear();
|
|
|
+// new_deal->Assign(deal);
|
|
|
+//
|
|
|
+// new_deal->Login(login);
|
|
|
+// new_deal->DealSet(0);
|
|
|
+// new_deal->Volume(volume);
|
|
|
+// new_deal->VolumeExt(volume_ext);
|
|
|
+// new_deal->VolumeClosed(volume_closed);
|
|
|
+// new_deal->VolumeClosedExt(volume_closed_ext);
|
|
|
+// 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] to order #%lld, original deal: #%lld", login, ret, context.cur_ord, deal->Deal());
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+//
|
|
|
+// m_api->LoggerOut(MTLogOK, L"add deal #%lld, original deal #%lld", new_deal->Deal(), deal->Deal());
|
|
|
+//
|
|
|
+// m_redis_client->publish("mt5_balance_fix", login_buf, [this](cpp_redis::reply r)
|
|
|
+// {
|
|
|
+// if (r.ko())
|
|
|
+// {
|
|
|
+// m_api->LoggerOut(MTLogErr, L"redis publish: %s", r.error().c_str());
|
|
|
+// }
|
|
|
+// });
|
|
|
+// // commit 在退出前完成
|
|
|
+// }
|
|
|
+//
|
|
|
+// m_api->LoggerOut(MTLogOK, L"deal #%lld, position #%lld, volume %lld", deal->Deal(), position->Position(), position->Volume());
|
|
|
+// if (position->Volume() == 0)
|
|
|
+// {
|
|
|
+// // 如果平仓,则删除hash值
|
|
|
+// if (position->Volume() == 0 && fields != nullptr)
|
|
|
+// {
|
|
|
+// m_redis_client->hdel(order_buf, *fields, [this](cpp_redis::reply& r)
|
|
|
+// {
|
|
|
+// if (r.ko())
|
|
|
+// {
|
|
|
+// // TODO 错误处理
|
|
|
+// try
|
|
|
+// {
|
|
|
+// m_api->LoggerOut(MTLogErr, L"redis: %s", r.error().c_str());
|
|
|
+// }
|
|
|
+// catch (...)
|
|
|
+// {
|
|
|
+// }
|
|
|
+// }
|
|
|
+// });
|
|
|
+// }
|
|
|
+//
|
|
|
+// // TODO 当position中的volume为0时,持仓被彻底平调,被跟订单是否也该检查
|
|
|
+// }
|
|
|
+//}
|
|
|
|
|
|
- m_api->LoggerOut(MTLogOK, L"deal #%lld, position #%lld, volume %lld", deal->Deal(), position->Position(), position->Volume());
|
|
|
- if (position->Volume() == 0)
|
|
|
+void CPluginInstance::OnTradeRequestAdd(const IMTRequest * request, const IMTConGroup * group, const IMTConSymbol * symbol, const IMTPosition * position, const IMTOrder * order)
|
|
|
+{
|
|
|
+ if (request == nullptr
|
|
|
+ || group == nullptr
|
|
|
+ || symbol == nullptr)
|
|
|
{
|
|
|
- // 如果平仓,则删除hash值
|
|
|
- if (position->Volume() == 0 && fields != nullptr)
|
|
|
- {
|
|
|
- m_redis_client->hdel(order_buf, *fields, [this](cpp_redis::reply& r)
|
|
|
- {
|
|
|
- if (r.ko())
|
|
|
- {
|
|
|
- // TODO 错误处理
|
|
|
- try
|
|
|
- {
|
|
|
- m_api->LoggerOut(MTLogErr, L"redis: %s", r.error().c_str());
|
|
|
- }
|
|
|
- catch (...)
|
|
|
- {
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- // TODO 当position中的volume为0时,持仓被彻底平调,被跟订单是否也该检查
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
|