|
|
@@ -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()
|