mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-07-28 11:07:48 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db4bb44fb3 | |||
| 68d5fa98af | |||
| dc28823ca9 |
+341
-341
@@ -21,57 +21,57 @@ using namespace System::Security;
|
||||
#pragma pack(push, 1)
|
||||
public struct CMqlRates
|
||||
{
|
||||
__int64 time; // Period start time
|
||||
double open; // Open price
|
||||
double high; // The highest price of the period
|
||||
double low; // The lowest price of the period
|
||||
double close; // Close price
|
||||
__int64 tick_volume; // Tick volume
|
||||
int spread; // Spread
|
||||
__int64 real_volume; // Trade volume
|
||||
__int64 time; // Period start time
|
||||
double open; // Open price
|
||||
double high; // The highest price of the period
|
||||
double low; // The lowest price of the period
|
||||
double close; // Close price
|
||||
__int64 tick_volume; // Tick volume
|
||||
int spread; // Spread
|
||||
__int64 real_volume; // Trade volume
|
||||
};
|
||||
|
||||
public struct CMqlTick
|
||||
{
|
||||
__int64 time; // Time of the last prices update
|
||||
double bid; // Current Bid price
|
||||
double ask; // Current Ask price
|
||||
double last; // Price of the last deal (Last)
|
||||
unsigned __int64 volume; // Volume for the current Last price
|
||||
__int64 time; // Time of the last prices update
|
||||
double bid; // Current Bid price
|
||||
double ask; // Current Ask price
|
||||
double last; // Price of the last deal (Last)
|
||||
unsigned __int64 volume; // Volume for the current Last price
|
||||
};
|
||||
|
||||
public struct CMqlBookInfo
|
||||
{
|
||||
int type; // Order type from ENUM_BOOK_TYPE enumeration
|
||||
double price; // Price
|
||||
__int64 volume; // Volume
|
||||
int type; // Order type from ENUM_BOOK_TYPE enumeration
|
||||
double price; // Price
|
||||
__int64 volume; // Volume
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void convertSystemString(wchar_t* dest, String^ src)
|
||||
{
|
||||
pin_ptr<const wchar_t> wch = PtrToStringChars(src);
|
||||
memcpy(dest, wch, wcslen(wch) * sizeof(wchar_t));
|
||||
dest[wcslen(wch)] = '\0';
|
||||
pin_ptr<const wchar_t> wch = PtrToStringChars(src);
|
||||
memcpy(dest, wch, wcslen(wch) * sizeof(wchar_t));
|
||||
dest[wcslen(wch)] = '\0';
|
||||
}
|
||||
|
||||
bool VerifySignature(System::String^ inputData, System::String^ signature, System::String^ publicKey)
|
||||
{
|
||||
bool verifyResult = false;
|
||||
bool verifyResult = false;
|
||||
|
||||
try
|
||||
{
|
||||
DSACryptoServiceProvider^ dsa = gcnew DSACryptoServiceProvider();
|
||||
dsa->FromXmlString(publicKey);
|
||||
array<System::Byte>^ data = UTF8Encoding::ASCII->GetBytes(inputData);
|
||||
array<System::Byte>^ signatureData = Convert::FromBase64String(signature);
|
||||
verifyResult = dsa->VerifyData(data, signatureData);
|
||||
}
|
||||
catch(Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:VerifySignature(): failed. " + e->Message);
|
||||
verifyResult = false;
|
||||
}
|
||||
try
|
||||
{
|
||||
DSACryptoServiceProvider^ dsa = gcnew DSACryptoServiceProvider();
|
||||
dsa->FromXmlString(publicKey);
|
||||
array<System::Byte>^ data = UTF8Encoding::ASCII->GetBytes(inputData);
|
||||
array<System::Byte>^ signatureData = Convert::FromBase64String(signature);
|
||||
verifyResult = dsa->VerifyData(data, signatureData);
|
||||
}
|
||||
catch(Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:VerifySignature(): failed. " + e->Message);
|
||||
verifyResult = false;
|
||||
}
|
||||
|
||||
return verifyResult;
|
||||
}
|
||||
@@ -80,431 +80,431 @@ bool g_IsVerified = true;
|
||||
|
||||
void _stdcall verify(int isDemo, wchar_t* accountName, long accountNumber)
|
||||
{
|
||||
if (isDemo != 0)
|
||||
{
|
||||
g_IsVerified = true;
|
||||
return;
|
||||
}
|
||||
if (isDemo != 0)
|
||||
{
|
||||
g_IsVerified = true;
|
||||
return;
|
||||
}
|
||||
|
||||
System::String^ signature = MtRegistryManager::ReadSignatureKey(gcnew String(accountName), accountNumber.ToString());
|
||||
Resources::ResourceManager^ rm = gcnew Resources::ResourceManager(L"MT5Connector.cl", Assembly::GetExecutingAssembly());
|
||||
System::String^ inputData = gcnew System::String(accountName);
|
||||
inputData += accountNumber.ToString();
|
||||
System::String^ publicKey = rm->GetString(L"cl");
|
||||
g_IsVerified = VerifySignature(inputData, gcnew System::String(signature), publicKey);
|
||||
System::String^ signature = MtRegistryManager::ReadSignatureKey(gcnew String(accountName), accountNumber.ToString());
|
||||
Resources::ResourceManager^ rm = gcnew Resources::ResourceManager(L"MT5Connector.cl", Assembly::GetExecutingAssembly());
|
||||
System::String^ inputData = gcnew System::String(accountName);
|
||||
inputData += accountNumber.ToString();
|
||||
System::String^ publicKey = rm->GetString(L"cl");
|
||||
g_IsVerified = VerifySignature(inputData, gcnew System::String(signature), publicKey);
|
||||
}
|
||||
|
||||
int _stdcall initExpert(int expertHandle, int port, wchar_t* symbol, double bid, double ask, wchar_t* err)
|
||||
{
|
||||
if (g_IsVerified == false)
|
||||
{
|
||||
System::String^ errorVerified = "Verification is failed!\nPlease contact with support.";
|
||||
convertSystemString(err, errorVerified);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:initExpert(): not verified");
|
||||
return 0;
|
||||
}
|
||||
if (g_IsVerified == false)
|
||||
{
|
||||
System::String^ errorVerified = "Verification is failed!\nPlease contact with support.";
|
||||
convertSystemString(err, errorVerified);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:initExpert(): not verified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
MT5Handler^ mtHander = gcnew MT5Handler();
|
||||
MtServerInstance::GetInstance()->InitExpert(expertHandle, port, gcnew String(symbol), bid, ask, mtHander);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
convertSystemString(err, e->Message);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:initExpert(): " + e->Message);
|
||||
try
|
||||
{
|
||||
MT5Handler^ mtHander = gcnew MT5Handler();
|
||||
MtServerInstance::GetInstance()->InitExpert(expertHandle, port, gcnew String(symbol), bid, ask, mtHander);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
convertSystemString(err, e->Message);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:initExpert(): " + e->Message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall deinitExpert(int expertHandle, wchar_t* err)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->DeinitExpert(expertHandle);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
convertSystemString(err, e->Message);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:deinitExpert(): " + e->Message);
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->DeinitExpert(expertHandle);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
convertSystemString(err, e->Message);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:deinitExpert(): " + e->Message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall updateQuote(int expertHandle, wchar_t* symbol, double bid, double ask, wchar_t* err)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendQuote(expertHandle, gcnew String(symbol), bid, ask);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
convertSystemString(err, e->Message);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:updateQuote(): " + e->Message);
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendQuote(expertHandle, gcnew String(symbol), bid, ask);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
convertSystemString(err, e->Message);
|
||||
Debug::WriteLine("[ERROR] MT5Connector:updateQuote(): " + e->Message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendIntResponse(int expertHandle, int response)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseInt(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendIntResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseInt(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendIntResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendLongResponse(int expertHandle, __int64 response)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLong(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLong(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendULongResponse(int expertHandle, unsigned __int64 response)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseULong(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseULong(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendLongResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendBooleanResponse(int expertHandle, int response)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool value = (response != 0) ? true : false;
|
||||
try
|
||||
{
|
||||
bool value = (response != 0) ? true : false;
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseBool(value));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendBooleanResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseBool(value));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendBooleanResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendDoubleResponse(int expertHandle, double response)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDouble(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendDoubleResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDouble(response));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendDoubleResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendStringResponse(int expertHandle, wchar_t* response)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseString(gcnew String(response)));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendStringResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseString(gcnew String(response)));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendStringResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendVoidResponse(int expertHandle)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, nullptr);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendVoidResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, nullptr);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendVoidResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendDoubleArrayResponse(int expertHandle, double* values, int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
array<double>^ list = gcnew array<double>(size);
|
||||
try
|
||||
{
|
||||
array<double>^ list = gcnew array<double>(size);
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
list[i] = values[i];
|
||||
}
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
list[i] = values[i];
|
||||
}
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDoubleArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendDoubleArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseDoubleArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendDoubleArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendIntArrayResponse(int expertHandle, int* values, int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
array<int>^ list = gcnew array<int>(size);
|
||||
try
|
||||
{
|
||||
array<int>^ list = gcnew array<int>(size);
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
list[i] = values[i];
|
||||
}
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
list[i] = values[i];
|
||||
}
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseIntArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendIntArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseIntArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendIntArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendLongArrayResponse(int expertHandle, __int64* values, int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
array<System::Int64>^ list = gcnew array<System::Int64>(size);
|
||||
try
|
||||
{
|
||||
array<System::Int64>^ list = gcnew array<System::Int64>(size);
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
list[i] = values[i];
|
||||
}
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
list[i] = values[i];
|
||||
}
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLongArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendLongArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseLongArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendLongArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendMqlRatesArrayResponse(int expertHandle, CMqlRates values[], int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
array<MtMqlRates^>^ list = gcnew array<MtMqlRates^>(size);
|
||||
try
|
||||
{
|
||||
array<MtMqlRates^>^ list = gcnew array<MtMqlRates^>(size);
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
MtMqlRates^ rates = gcnew MtMqlRates();
|
||||
rates->time = values[i].time;
|
||||
rates->open = values[i].open;
|
||||
rates->high = values[i].high;
|
||||
rates->low = values[i].low;
|
||||
rates->close = values[i].close;
|
||||
rates->tick_volume = values[i].tick_volume;
|
||||
rates->spread = values[i].spread;
|
||||
rates->real_volume = values[i].real_volume;
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
MtMqlRates^ rates = gcnew MtMqlRates();
|
||||
rates->time = values[i].time;
|
||||
rates->open = values[i].open;
|
||||
rates->high = values[i].high;
|
||||
rates->low = values[i].low;
|
||||
rates->close = values[i].close;
|
||||
rates->tick_volume = values[i].tick_volume;
|
||||
rates->spread = values[i].spread;
|
||||
rates->real_volume = values[i].real_volume;
|
||||
|
||||
list[i] = rates;
|
||||
}
|
||||
list[i] = rates;
|
||||
}
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlRatesArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlRatesArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendMqlTickResponse(int expertHandle, CMqlTick* response, int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
MtMqlTick^ mtResponse = gcnew MtMqlTick();
|
||||
try
|
||||
{
|
||||
MtMqlTick^ mtResponse = gcnew MtMqlTick();
|
||||
|
||||
mtResponse->time = response->time;
|
||||
mtResponse->bid = response->bid;
|
||||
mtResponse->ask = response->ask;
|
||||
mtResponse->last = response->last;
|
||||
mtResponse->volume = response->volume;
|
||||
mtResponse->time = response->time;
|
||||
mtResponse->bid = response->bid;
|
||||
mtResponse->ask = response->ask;
|
||||
mtResponse->last = response->last;
|
||||
mtResponse->volume = response->volume;
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlTick(mtResponse));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendMqlTickResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlTick(mtResponse));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendMqlTickResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall sendMqlBookInfoArrayResponse(int expertHandle, CMqlBookInfo values[], int size)
|
||||
{
|
||||
try
|
||||
{
|
||||
array<MtMqlBookInfo^>^ list = gcnew array<MtMqlBookInfo^>(size);
|
||||
try
|
||||
{
|
||||
array<MtMqlBookInfo^>^ list = gcnew array<MtMqlBookInfo^>(size);
|
||||
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
MtMqlBookInfo^ info = gcnew MtMqlBookInfo();
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
MtMqlBookInfo^ info = gcnew MtMqlBookInfo();
|
||||
|
||||
info->type = values[i].type;
|
||||
info->price = values[i].price;
|
||||
info->volume = values[i].volume;
|
||||
info->type = values[i].type;
|
||||
info->price = values[i].price;
|
||||
info->volume = values[i].volume;
|
||||
|
||||
list[i] = info;
|
||||
}
|
||||
list[i] = info;
|
||||
}
|
||||
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlBookInfoArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
MtServerInstance::GetInstance()->SendResponse(expertHandle, gcnew MtResponseMqlBookInfoArray(list));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:sendMqlRatesArrayResponse(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------- get values -------------------------------
|
||||
|
||||
int _stdcall getCommandType(int expertHandle, int* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
*res = MtServerInstance::GetInstance()->GetCommandType(expertHandle);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getCommandType(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
*res = MtServerInstance::GetInstance()->GetCommandType(expertHandle);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getCommandType(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getIntValue(int expertHandle, int paramIndex, int* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
*res = (int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getIntValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
*res = (int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getIntValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getDoubleValue(int expertHandle, int paramIndex, double* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
*res = (double)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getDoubleValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
*res = (double)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getDoubleValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
convertSystemString(res, (String^)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getStringValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
convertSystemString(res, (String^)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex));
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getStringValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getULongValue(int expertHandle, int paramIndex, unsigned __int64* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
*res = (unsigned long)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getULongValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
*res = (unsigned long)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getULongValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getLongValue(int expertHandle, int paramIndex, __int64* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
*res = (long)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getLongValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
*res = (long)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getLongValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool val = (bool)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
*res = val == true ? 1 : 0;
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getBooleanValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
bool val = (bool)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
*res = val == true ? 1 : 0;
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getBooleanValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getUIntValue(int expertHandle, int paramIndex, unsigned int* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
*res = (unsigned int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getUIntValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
try
|
||||
{
|
||||
*res = (unsigned int)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getUIntValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -9,16 +9,16 @@ using namespace MTApiService;
|
||||
ref class MT5Handler: IMetaTraderHandler
|
||||
{
|
||||
public:
|
||||
MT5Handler()
|
||||
{
|
||||
msgId = WM_TIMER;
|
||||
}
|
||||
MT5Handler()
|
||||
{
|
||||
msgId = WM_USER + 4096;
|
||||
}
|
||||
|
||||
virtual void SendTickToMetaTrader(int handle)
|
||||
{
|
||||
PostMessage((HWND)handle, msgId, 0, 0);
|
||||
}
|
||||
virtual void SendTickToMetaTrader(int handle)
|
||||
{
|
||||
PostMessage((HWND)handle, msgId, 0x00000011, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int msgId;
|
||||
unsigned int msgId;
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- -->
|
||||
<!-- ILMerge project-specific settings. Almost never need to be set explicitly. -->
|
||||
<!-- for details, see http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx -->
|
||||
<!-- -->
|
||||
<!-- *** set this file to Type=None, CopyToOutput=Never *** -->
|
||||
|
||||
<!-- If True, all copy local dependencies will also be merged from referenced projects whether they are referenced in the current project explicitly or not -->
|
||||
<ILMergeTransitive>true</ILMergeTransitive>
|
||||
|
||||
<!-- Extra ILMerge library paths (semicolon-separated). Dont put your package dependencies here, they will be added automagically -->
|
||||
<ILMergeLibraryPath></ILMergeLibraryPath>
|
||||
|
||||
<!-- The solution NuGet package directory if not standard 'SOLUTION\packages' -->
|
||||
<ILMergePackagesPath></ILMergePackagesPath>
|
||||
|
||||
<!-- The merge order file name if differs from standard 'ILMergeOrder.txt' -->
|
||||
<ILMergeOrderFile></ILMergeOrderFile>
|
||||
|
||||
<!-- The strong key file name if not specified in the project -->
|
||||
<ILMergeKeyFile>MtApiKey.snk</ILMergeKeyFile>
|
||||
|
||||
<!-- The assembly version if differs for the version of the main assembly -->
|
||||
<ILMergeAssemblyVersion></ILMergeAssemblyVersion>
|
||||
|
||||
<!-- added in Version 1.0.4 -->
|
||||
<ILMergeFileAlignment></ILMergeFileAlignment>
|
||||
|
||||
<!-- added in Version 1.0.4, default=none -->
|
||||
<ILMergeAllowDuplicateType></ILMergeAllowDuplicateType>
|
||||
|
||||
<!-- If the <see cref="CopyAttributes"/> is also set, any assembly-level attributes names that have the same type are copied over into the target assembly -->
|
||||
<ILMergeAllowMultipleAssemblyLevelAttributes></ILMergeAllowMultipleAssemblyLevelAttributes>
|
||||
|
||||
<!-- See ILMerge documentation -->
|
||||
<ILMergeAllowZeroPeKind></ILMergeAllowZeroPeKind>
|
||||
|
||||
<!-- The assembly level attributes of each input assembly are copied over into the target assembly -->
|
||||
<ILMergeCopyAttributes></ILMergeCopyAttributes>
|
||||
|
||||
<!-- Creates a .pdb file for the output assembly and merges into it any .pdb files found for input assemblies, default=true -->
|
||||
<ILMergeDebugInfo></ILMergeDebugInfo>
|
||||
|
||||
<!-- Target assembly will be delay signed -->
|
||||
<ILMergeDelaySign></ILMergeDelaySign>
|
||||
|
||||
<!-- Types in assemblies other than the primary assembly have their visibility modified -->
|
||||
<ILMergeInternalize></ILMergeInternalize>
|
||||
|
||||
<!-- The path name of the file that will be used to identify types that are not to have their visibility modified -->
|
||||
<ILMergeInternalizeExcludeFile></ILMergeInternalizeExcludeFile>
|
||||
|
||||
<!-- XML documentation files are merged to produce an XML documentation file for the target assembly -->
|
||||
<ILMergeXmlDocumentation></ILMergeXmlDocumentation>
|
||||
|
||||
<!-- External assembly references in the manifest of the target assembly will use full public keys (false) or public key tokens (true, default value) -->
|
||||
<ILMergePublicKeyTokens></ILMergePublicKeyTokens>
|
||||
|
||||
<!-- Types with the same name are all merged into a single type in the target assembly -->
|
||||
<ILMergeUnionMerge></ILMergeUnionMerge>
|
||||
|
||||
<!-- The version of the target framework, default 40 (works for 45 too) -->
|
||||
<ILTargetPlatform></ILTargetPlatform>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,4 +0,0 @@
|
||||
# this file contains the partial list of the merged assemblies in the merge order
|
||||
# you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build
|
||||
# and finetune merge order to your satisfaction
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public interface IMtApiServer
|
||||
{
|
||||
MtResponse SendCommand(MtCommand command);
|
||||
List<MtQuote> GetQuotes();
|
||||
IEnumerable<MtQuote> GetQuotes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Core;
|
||||
using log4net.Layout;
|
||||
using log4net.Repository.Hierarchy;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class LogConfigurator
|
||||
{
|
||||
private const string LogFileNameExtension = "txt";
|
||||
|
||||
public static void Setup(string profileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(profileName))
|
||||
throw new ArgumentNullException();
|
||||
|
||||
var hierarchy = (Hierarchy) LogManager.GetRepository();
|
||||
|
||||
var patternLayout = new PatternLayout
|
||||
{
|
||||
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
|
||||
};
|
||||
patternLayout.ActivateOptions();
|
||||
|
||||
string filename = $"{DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss")}.{LogFileNameExtension}";
|
||||
|
||||
var roller = new RollingFileAppender
|
||||
{
|
||||
AppendToFile = false,
|
||||
File = $@"{System.IO.Path.GetTempPath()}{profileName}\Logs\{filename}",
|
||||
Layout = patternLayout,
|
||||
PreserveLogFileNameExtension = true,
|
||||
MaxSizeRollBackups = 5,
|
||||
MaximumFileSize = "1GB",
|
||||
RollingStyle = RollingFileAppender.RollingMode.Size,
|
||||
StaticLogFileName = false
|
||||
};
|
||||
roller.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(roller);
|
||||
|
||||
var memory = new MemoryAppender();
|
||||
memory.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(memory);
|
||||
|
||||
#if (DEBUG)
|
||||
hierarchy.Root.Level = Level.Debug;
|
||||
#else
|
||||
hierarchy.Root.Level = Level.Info;
|
||||
#endif
|
||||
hierarchy.Configured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props" Condition="Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -15,8 +14,6 @@
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -38,17 +35,12 @@
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
<AssemblyOriginatorKeyFile>MtApiKey.pfx</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.5\lib\net40-full\log4net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
@@ -62,7 +54,6 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="ICommandManager.cs" />
|
||||
<Compile Include="IMetaTraderHandler.cs" />
|
||||
<Compile Include="LogConfigurator.cs" />
|
||||
<Compile Include="MtCommandEventArgs.cs" />
|
||||
<Compile Include="IDisposableChannel.cs" />
|
||||
<Compile Include="IMtApiServer.cs" />
|
||||
@@ -87,28 +78,13 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ILMerge.props">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="MtApiKey.snk" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="ILMergeOrder.txt" />
|
||||
<None Include="MtApiKey.pfx" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets" Condition="Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
Executable
BIN
Binary file not shown.
Binary file not shown.
+14
-11
@@ -1,17 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
internal class MtApiProxy : DuplexClientBase<IMtApi>, IMtApi, IDisposable
|
||||
class MtApiProxy : DuplexClientBase<IMtApi>, IMtApi, IDisposable
|
||||
{
|
||||
public MtApiProxy(InstanceContext callbackContext, Binding binding, EndpointAddress remoteAddress)
|
||||
public MtApiProxy(InstanceContext callbackContext, Binding binding,
|
||||
EndpointAddress remoteAddress)
|
||||
: base(callbackContext, binding, remoteAddress)
|
||||
{
|
||||
InnerDuplexChannel.Faulted += InnerDuplexChannel_Faulted;
|
||||
InnerDuplexChannel.Open();
|
||||
base.InnerDuplexChannel.Faulted += new EventHandler(InnerDuplexChannel_Faulted);
|
||||
base.InnerDuplexChannel.Open();
|
||||
}
|
||||
|
||||
#region IMtApi Members
|
||||
@@ -31,7 +34,7 @@ namespace MTApiService
|
||||
return Channel.SendCommand(command);
|
||||
}
|
||||
|
||||
public List<MtQuote> GetQuotes()
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
return Channel.GetQuotes();
|
||||
}
|
||||
@@ -44,19 +47,19 @@ namespace MTApiService
|
||||
{
|
||||
try
|
||||
{
|
||||
Close();
|
||||
this.Close();
|
||||
}
|
||||
catch (CommunicationException)
|
||||
{
|
||||
Abort();
|
||||
this.Abort();
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Abort();
|
||||
this.Abort();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Abort();
|
||||
this.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,9 +68,9 @@ namespace MTApiService
|
||||
#region Private Methods
|
||||
private void InnerDuplexChannel_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
Faulted?.Invoke(this, e);
|
||||
if (Faulted != null)
|
||||
Faulted(this, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
+133
-171
@@ -1,208 +1,173 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
using System.ServiceModel;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
[CallbackBehavior(UseSynchronizationContext = false)]
|
||||
public class MtClient: IMtApiCallback, IDisposable
|
||||
{
|
||||
private const string ServiceName = "MtApiService";
|
||||
private static string SERVICE_NAME = "MtApiService";
|
||||
|
||||
public delegate void MtQuoteHandler(MtQuote quote);
|
||||
|
||||
#region Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtClient));
|
||||
|
||||
private MtApiProxy _proxy;
|
||||
private bool _isConnected;
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Open(string host, int port)
|
||||
{
|
||||
Log.DebugFormat("Open: begin. host = {0}, port = {1}", host, port);
|
||||
Debug.WriteLine("[INFO] MtClient::Open");
|
||||
|
||||
if (string.IsNullOrEmpty(host))
|
||||
throw new ArgumentNullException(nameof(host), "host is null or empty");
|
||||
throw new ArgumentNullException("host", "host is null or empty");
|
||||
|
||||
if (port < 0 || port > 65536)
|
||||
throw new ArgumentOutOfRangeException(nameof(port), "port value is invalid");
|
||||
throw new ArgumentOutOfRangeException("port", "port value is invalid");
|
||||
|
||||
var urlService = $"net.tcp://{host}:{port}/{ServiceName}";
|
||||
var urlService = string.Format("net.tcp://{0}:{1}/{2}", host, port, SERVICE_NAME);
|
||||
|
||||
if (_proxy != null)
|
||||
lock (mClientLocker)
|
||||
{
|
||||
Log.Warn("Open: end. _proxy is not null.");
|
||||
return;
|
||||
}
|
||||
if (mProxy != null)
|
||||
return;
|
||||
|
||||
var bind = new NetTcpBinding(SecurityMode.None)
|
||||
{
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
SendTimeout = new TimeSpan(12, 0, 0),
|
||||
ReceiveTimeout = new TimeSpan(12, 0, 0),
|
||||
ReaderQuotas =
|
||||
var bind = new NetTcpBinding(SecurityMode.None)
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
// Commented next statement since it is not required
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
ReaderQuotas =
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
// Commented next statement since it is not required
|
||||
|
||||
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
_proxy.Faulted += ProxyFaulted;
|
||||
|
||||
Log.Debug("Open: end.");
|
||||
mProxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
mProxy.Faulted += mProxy_Faulted;
|
||||
}
|
||||
}
|
||||
|
||||
public void Open(int port)
|
||||
{
|
||||
Log.DebugFormat("Open: begin. port = {0}", port);
|
||||
|
||||
if (port < 0 || port > 65536)
|
||||
throw new ArgumentOutOfRangeException(nameof(port), "port value is invalid");
|
||||
throw new ArgumentOutOfRangeException("port", "port value is invalid");
|
||||
|
||||
var urlService = $"net.pipe://localhost/{ServiceName}_{port}";
|
||||
var urlService = string.Format("net.pipe://localhost/{0}_{1}", SERVICE_NAME, port);
|
||||
|
||||
if (_proxy != null)
|
||||
lock (mClientLocker)
|
||||
{
|
||||
Log.Warn("Open: end. _proxy is not null.");
|
||||
return;
|
||||
}
|
||||
if (mProxy != null)
|
||||
return;
|
||||
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
|
||||
{
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
SendTimeout = new TimeSpan(12, 0, 0),
|
||||
ReceiveTimeout = new TimeSpan(12, 0, 0),
|
||||
ReaderQuotas =
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
// Commented next statement since it is not required
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
ReaderQuotas =
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
// Commented next statement since it is not required
|
||||
|
||||
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
_proxy.Faulted += ProxyFaulted;
|
||||
|
||||
Log.Debug("Open: end.");
|
||||
mProxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
|
||||
mProxy.Faulted += mProxy_Faulted;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Log.Debug("Close: begin.");
|
||||
Debug.WriteLine("[INFO] MtClient::Close");
|
||||
|
||||
if (_proxy != null)
|
||||
lock (mClientLocker)
|
||||
{
|
||||
_proxy.Faulted -= ProxyFaulted;
|
||||
_proxy.Dispose();
|
||||
_proxy = null;
|
||||
if (mProxy != null)
|
||||
{
|
||||
mProxy.Faulted -= mProxy_Faulted;
|
||||
mProxy.Dispose();
|
||||
mProxy = null;
|
||||
}
|
||||
|
||||
mIsConnected = false;
|
||||
}
|
||||
|
||||
_isConnected = false;
|
||||
|
||||
Log.Debug("Close: end.");
|
||||
}
|
||||
|
||||
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
|
||||
public void Connect()
|
||||
{
|
||||
Log.Debug("Connect: begin.");
|
||||
|
||||
if (_proxy == null)
|
||||
{
|
||||
Log.Error("Connect: _proxy is not defined.");
|
||||
throw new CommunicationException("Connection failed to service. Proxy is not defined (needs to call Open)");
|
||||
}
|
||||
|
||||
if (_isConnected)
|
||||
{
|
||||
Log.Warn("Connected: end. Client is already connected.");
|
||||
return;
|
||||
}
|
||||
Debug.WriteLine("[INFO] MtClient::Connect");
|
||||
|
||||
try
|
||||
{
|
||||
_isConnected = _proxy.Connect();
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null && mIsConnected == true)
|
||||
return;
|
||||
|
||||
mIsConnected = mProxy.Connect();
|
||||
|
||||
if (mIsConnected == false)
|
||||
throw new Exception("Connected failed");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorFormat("Connect: Exception - {0}", ex.Message);
|
||||
Debug.WriteLine("[ERROR] MtClient::Connect: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException($"Connection failed to service. {ex.Message}");
|
||||
throw new CommunicationException(string.Format("Connection failed to service"));
|
||||
}
|
||||
|
||||
if (_isConnected == false)
|
||||
{
|
||||
Log.Error("Connect: end. Connection failed.");
|
||||
throw new CommunicationException("Connection failed");
|
||||
}
|
||||
|
||||
Log.Debug("Connect: end.");
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Log.Debug("Disconnect: begin.");
|
||||
Debug.WriteLine("[INFO] MtClient::Disconnect");
|
||||
|
||||
try
|
||||
{
|
||||
_isConnected = false;
|
||||
lock (mClientLocker)
|
||||
{
|
||||
mIsConnected = false;
|
||||
|
||||
_proxy?.Disconnect();
|
||||
if (mProxy != null)
|
||||
mProxy.Disconnect();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorFormat("Disconnect: Exception - {0}", ex.Message);
|
||||
Debug.WriteLine("[ERROR] MtClient::Disconnect: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
Log.Debug("Disconnect: end.");
|
||||
}
|
||||
|
||||
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
|
||||
public MtResponse SendCommand(int commandType, ArrayList parameters)
|
||||
public MtResponse SendCommand(int commandType, ArrayList commandParameters)
|
||||
{
|
||||
Log.DebugFormat("SendCommand: begin. commandType = {0}, parameters count = {1}", commandType, parameters?.Count);
|
||||
Debug.WriteLine("[INFO] MtClient::SendCommand: commandType = {0}", commandType);
|
||||
|
||||
MtResponse result;
|
||||
|
||||
if (_isConnected == false)
|
||||
{
|
||||
Log.Error("SendCommand: Client is not connected.");
|
||||
throw new CommunicationException("Client is not connected.");
|
||||
}
|
||||
|
||||
if (_proxy == null)
|
||||
{
|
||||
Log.Error("SendCommand: Proxy is not defined.");
|
||||
throw new CommunicationException("Proxy is not defined.");
|
||||
}
|
||||
MtResponse result = null;
|
||||
|
||||
try
|
||||
{
|
||||
result = _proxy.SendCommand(new MtCommand(commandType, parameters));
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null && mIsConnected == true)
|
||||
result = mProxy.SendCommand(new MtCommand(commandType, commandParameters));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorFormat("SendCommand: Exception - {0}", ex.Message);
|
||||
Debug.WriteLine("[ERROR] MtClient::SendCommand: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
@@ -212,41 +177,30 @@ namespace MTApiService
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
Log.Debug("GetQuotes: begin.");
|
||||
Debug.WriteLine("[INFO] MtClient::GetQuotes");
|
||||
|
||||
if (_isConnected == false)
|
||||
{
|
||||
Log.Warn("GetQuotes: end. Client is not connected.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_proxy == null)
|
||||
{
|
||||
Log.Warn("GetQuotes: end. _proxy is not defined.");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<MtQuote> result;
|
||||
IEnumerable<MtQuote> result = null;
|
||||
|
||||
try
|
||||
{
|
||||
result = _proxy.GetQuotes();
|
||||
lock (mClientLocker)
|
||||
{
|
||||
if (mProxy != null && mIsConnected == true)
|
||||
result = mProxy.GetQuotes();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorFormat("GetQuotes: Exception - {0}", ex.Message);
|
||||
Debug.WriteLine("[ERROR] MtClient::GetQuotes: {0}", ex.Message);
|
||||
|
||||
Close();
|
||||
|
||||
throw new CommunicationException($"Service connection failed! {ex.Message}");
|
||||
throw new CommunicationException("Service connection failed");
|
||||
}
|
||||
|
||||
Log.DebugFormat("GetQuotes: end. quotes count = {0}", result?.Count);
|
||||
|
||||
return result;
|
||||
return result;;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -255,70 +209,74 @@ namespace MTApiService
|
||||
|
||||
public void OnQuoteUpdate(MtQuote quote)
|
||||
{
|
||||
Log.DebugFormat("OnQuoteUpdate: begin. quote = {0}", quote);
|
||||
if (quote != null)
|
||||
{
|
||||
if (QuoteUpdated != null)
|
||||
{
|
||||
QuoteUpdated(quote);
|
||||
}
|
||||
|
||||
if (quote == null) return;
|
||||
|
||||
QuoteUpdated?.Invoke(quote);
|
||||
|
||||
Log.Debug("OnQuoteUpdate: end.");
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteUpdate: " + quote);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnQuoteAdded(MtQuote quote)
|
||||
{
|
||||
Log.DebugFormat("OnQuoteAdded: begin. quote = {0}", quote);
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteAdded");
|
||||
|
||||
QuoteAdded?.Invoke(quote);
|
||||
|
||||
Log.Debug("OnQuoteAdded: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteRemoved(MtQuote quote)
|
||||
{
|
||||
Log.DebugFormat("OnQuoteRemoved: begin. quote = {0}", quote);
|
||||
Debug.WriteLine("[INFO] MtClient::OnQuoteRemoved");
|
||||
|
||||
QuoteRemoved?.Invoke(quote);
|
||||
|
||||
Log.Debug("OnQuoteRemoved: end.");
|
||||
}
|
||||
|
||||
public void OnServerStopped()
|
||||
{
|
||||
Log.Debug("OnServerStopped: begin.");
|
||||
Debug.WriteLine("[INFO] MtClient::OnServerStopped");
|
||||
|
||||
Close();
|
||||
ServerDisconnected?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
Log.Debug("OnServerStopped: end.");
|
||||
ServerDisconnected?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
|
||||
public void OnMtEvent(MtEvent mtEvent)
|
||||
{
|
||||
Log.DebugFormat("OnMtEvent: begin. event = {0}", mtEvent);
|
||||
|
||||
MtEventReceived?.Invoke(this, new MtEventArgs(mtEvent));
|
||||
|
||||
Log.Debug("OnMtEvent: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public bool IsConnected => _proxy.State == CommunicationState.Opened && _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (mClientLocker)
|
||||
{
|
||||
return mProxy.State == CommunicationState.Opened && mIsConnected == true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void ProxyFaulted(object sender, EventArgs e)
|
||||
void mProxy_Faulted(object sender, EventArgs e)
|
||||
{
|
||||
Log.Debug("ProxyFaulted: begin.");
|
||||
Debug.WriteLine("[INFO] MtClient::mProxy_Faulted");
|
||||
|
||||
Close();
|
||||
ServerFailed?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
Log.Debug("ProxyFaulted: end.");
|
||||
if (ServerFailed != null)
|
||||
{
|
||||
ServerFailed(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -327,11 +285,9 @@ namespace MTApiService
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Log.Debug("Dispose: begin.");
|
||||
Debug.WriteLine("[INFO] MtClient::Dispose");
|
||||
|
||||
Close();
|
||||
|
||||
Log.Debug("Dispose: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -344,5 +300,11 @@ namespace MTApiService
|
||||
public event EventHandler ServerFailed;
|
||||
public event EventHandler<MtEventArgs> MtEventReceived;
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly object mClientLocker = new object();
|
||||
private MtApiProxy mProxy = null;
|
||||
private bool mIsConnected = false;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections;
|
||||
|
||||
namespace MTApiService
|
||||
@@ -18,9 +22,5 @@ namespace MTApiService
|
||||
[DataMember]
|
||||
public ArrayList Parameters { get; private set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"CommandType = {CommandType}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+3
-11
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -11,9 +10,6 @@ namespace MTApiService
|
||||
|
||||
public MtCommandTask(MtCommand command)
|
||||
{
|
||||
if (command == null)
|
||||
throw new ArgumentNullException(nameof(command));
|
||||
|
||||
Command = command;
|
||||
}
|
||||
|
||||
@@ -24,7 +20,7 @@ namespace MTApiService
|
||||
_responseWaiter.WaitOne(time);
|
||||
lock (_locker)
|
||||
{
|
||||
return _result;
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +32,6 @@ namespace MTApiService
|
||||
}
|
||||
_responseWaiter.Set();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Command = {Command}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtConnectionProfile
|
||||
|
||||
@@ -1,50 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
internal class MtCommandExecutorManager : ICommandManager
|
||||
{
|
||||
#region Private Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtCommandExecutorManager));
|
||||
|
||||
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
|
||||
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
|
||||
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Log.Debug("Stop: begin.");
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
_commandExecutors.Clear();
|
||||
_commandTasks.Clear();
|
||||
}
|
||||
|
||||
Log.Debug("Stop: end.");
|
||||
}
|
||||
|
||||
public void AddCommandExecutor(MtExpert commandExecutor)
|
||||
{
|
||||
if (commandExecutor == null)
|
||||
throw new ArgumentNullException(nameof(commandExecutor));
|
||||
|
||||
Log.DebugFormat("AddCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
|
||||
return;
|
||||
|
||||
var notify = false;
|
||||
lock (_locker)
|
||||
{
|
||||
if (_commandExecutors.Contains(commandExecutor))
|
||||
{
|
||||
Log.Warn("AddCommandExecutor: end. Command executor already exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
_commandExecutors.Add(commandExecutor);
|
||||
if (_commandTasks.Count > 0)
|
||||
@@ -60,25 +41,18 @@ namespace MTApiService
|
||||
{
|
||||
NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.Debug("AddCommandExecutor: end.");
|
||||
}
|
||||
|
||||
public void RemoveCommandExecutor(MtExpert commandExecutor)
|
||||
{
|
||||
if (commandExecutor == null)
|
||||
throw new ArgumentNullException(nameof(commandExecutor));
|
||||
|
||||
Log.DebugFormat("RemoveCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
|
||||
return;
|
||||
|
||||
var notify = false;
|
||||
lock (_locker)
|
||||
{
|
||||
if (_commandExecutors.Contains(commandExecutor) == false)
|
||||
{
|
||||
Log.Warn("RemoveCommandExecutor: end. Command executor is not exist in collection.");
|
||||
return;
|
||||
}
|
||||
|
||||
_commandExecutors.Remove(commandExecutor);
|
||||
if (_commandTasks.Count > 0)
|
||||
@@ -94,31 +68,23 @@ namespace MTApiService
|
||||
{
|
||||
NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.Debug("RemoveCommandExecutor: end.");
|
||||
}
|
||||
|
||||
public void EnqueueCommandTask(MtCommandTask task)
|
||||
{
|
||||
if (task == null)
|
||||
throw new ArgumentNullException(nameof(task));
|
||||
|
||||
Log.DebugFormat("EnqueueCommandTask: begin. task = {0}", task);
|
||||
return;
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
_commandTasks.Enqueue(task);
|
||||
_commandTasks.Enqueue(task);
|
||||
}
|
||||
|
||||
NotifyCommandReady();
|
||||
|
||||
Log.Debug("EnqueueCommandTask: end.");
|
||||
}
|
||||
|
||||
public MtCommandTask DequeueCommandTask()
|
||||
{
|
||||
Log.Debug("DequeueCommandTask: called.");
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
return _commandTasks.Count > 0 ? _commandTasks.Dequeue() : null;
|
||||
@@ -130,8 +96,6 @@ namespace MTApiService
|
||||
#region Private Methods
|
||||
private void NotifyCommandReady()
|
||||
{
|
||||
Log.Debug("NotifyCommandReady: begin.");
|
||||
|
||||
var commandExecutors = new List<MtExpert>();
|
||||
lock (_locker)
|
||||
{
|
||||
@@ -142,14 +106,10 @@ namespace MTApiService
|
||||
{
|
||||
executor.NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.DebugFormat("NotifyCommandReady: end. Notified executor count = {0}", commandExecutors.Count);
|
||||
}
|
||||
|
||||
private void CommandExecutor_CommandExecuted(object sender, EventArgs e)
|
||||
{
|
||||
Log.Debug("CommandExecutor_CommandExecuted: begin.");
|
||||
|
||||
var notify = false;
|
||||
lock (_locker)
|
||||
{
|
||||
@@ -164,8 +124,14 @@ namespace MTApiService
|
||||
NotifyCommandReady();
|
||||
}
|
||||
|
||||
Log.Debug("CommandExecutor_CommandExecuted: end.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
|
||||
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
|
||||
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
+68
-93
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -7,103 +6,20 @@ namespace MTApiService
|
||||
{
|
||||
public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote);
|
||||
|
||||
#region Private Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtExpert));
|
||||
|
||||
private readonly IMetaTraderHandler _mtHadler;
|
||||
private MtCommandTask _commandTask;
|
||||
private ICommandManager _commandManager;
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
if (mtHandler == null)
|
||||
throw new ArgumentNullException(nameof(mtHandler));
|
||||
|
||||
Quote = quote;
|
||||
Handle = handle;
|
||||
_mtHadler = mtHandler;
|
||||
}
|
||||
|
||||
public void Deinit()
|
||||
{
|
||||
Log.Debug("Deinit: begin.");
|
||||
|
||||
IsEnable = false;
|
||||
FireOnDeinited();
|
||||
|
||||
Log.Debug("Deinit: end.");
|
||||
}
|
||||
|
||||
public void SendResponse(MtResponse response)
|
||||
{
|
||||
Log.DebugFormat("SendResponse: begin. response = {0}", response);
|
||||
|
||||
_commandTask.SetResult(response);
|
||||
_commandTask = null;
|
||||
FireOnCommandExecuted();
|
||||
|
||||
Log.Debug("SendResponse: end.");
|
||||
}
|
||||
|
||||
public int GetCommandType()
|
||||
{
|
||||
Log.Debug("GetCommandType: called.");
|
||||
|
||||
var commandManager = CommandManager;
|
||||
if (commandManager != null)
|
||||
{
|
||||
_commandTask = commandManager.DequeueCommandTask();
|
||||
}
|
||||
|
||||
return _commandTask?.Command?.CommandType ?? 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int index)
|
||||
{
|
||||
Log.DebugFormat("GetCommandType: called. index = {0}", index);
|
||||
|
||||
var command = _commandTask?.Command;
|
||||
if (command?.Parameters != null && index >= 0 && index < command.Parameters.Count)
|
||||
{
|
||||
return command.Parameters[index];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SendEvent(MtEvent mtEvent)
|
||||
{
|
||||
Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent);
|
||||
|
||||
FireOnMtEvent(mtEvent);
|
||||
|
||||
Log.Debug("SendEvent: end.");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ExpertHandle = {Handle}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
private MtQuote _quote;
|
||||
public MtQuote Quote
|
||||
public MtQuote Quote
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return _quote;
|
||||
return _quote;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_locker)
|
||||
lock(_locker)
|
||||
{
|
||||
_quote = value;
|
||||
}
|
||||
@@ -112,7 +28,7 @@ namespace MTApiService
|
||||
}
|
||||
}
|
||||
|
||||
public int Handle { get; }
|
||||
public int Handle { get; private set; }
|
||||
|
||||
private bool _isEnable = true;
|
||||
public bool IsEnable
|
||||
@@ -153,21 +69,73 @@ namespace MTApiService
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
Quote = quote;
|
||||
Handle = handle;
|
||||
_mtHadler = mtHandler;
|
||||
}
|
||||
|
||||
public void Deinit()
|
||||
{
|
||||
IsEnable = false;
|
||||
FireOnDeinited();
|
||||
}
|
||||
|
||||
public void SendResponse(MtResponse response)
|
||||
{
|
||||
_commandTask.SetResult(response);
|
||||
_commandTask = null;
|
||||
FireOnCommandExecuted();
|
||||
}
|
||||
|
||||
public int GetCommandType()
|
||||
{
|
||||
var commandManager = CommandManager;
|
||||
if (commandManager != null)
|
||||
{
|
||||
_commandTask = commandManager.DequeueCommandTask();
|
||||
}
|
||||
|
||||
return _commandTask != null && _commandTask.Command != null ? _commandTask.Command.CommandType : 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int index)
|
||||
{
|
||||
if (_commandTask != null)
|
||||
{
|
||||
var command = _commandTask.Command;
|
||||
if (command != null && command.Parameters != null
|
||||
&& index >= 0 && index < command.Parameters.Count)
|
||||
{
|
||||
return command.Parameters[index];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SendEvent(MtEvent mtEvent)
|
||||
{
|
||||
FireOnMtEvent(mtEvent);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMtCommandExecutor
|
||||
public void NotifyCommandReady()
|
||||
{
|
||||
Log.Debug("NotifyCommandReady: begin.");
|
||||
|
||||
SendTickToMetaTrader();
|
||||
|
||||
Log.Debug("NotifyCommandReady: end.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void SendTickToMetaTrader()
|
||||
{
|
||||
_mtHadler.SendTickToMetaTrader(Handle);
|
||||
if (_mtHadler != null)
|
||||
{
|
||||
_mtHadler.SendTickToMetaTrader(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
private void FireOnQuoteChanged(MtQuote quote)
|
||||
@@ -197,5 +165,12 @@ namespace MTApiService
|
||||
public event EventHandler CommandExecuted;
|
||||
public event EventHandler<MtEventArgs> OnMtEvent;
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly IMetaTraderHandler _mtHadler;
|
||||
private MtCommandTask _commandTask;
|
||||
private ICommandManager _commandManager;
|
||||
private readonly object _locker = new object();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MTApiService
|
||||
@@ -7,34 +10,34 @@ namespace MTApiService
|
||||
public class MtMqlTradeRequest
|
||||
{
|
||||
[DataMember]
|
||||
public int Action { get; set; }
|
||||
public int Action { get; set; }
|
||||
[DataMember]
|
||||
public uint Magic { get; set; }
|
||||
public uint Magic { get; set; }
|
||||
[DataMember]
|
||||
public uint Order { get; set; }
|
||||
public uint Order { get; set; }
|
||||
[DataMember]
|
||||
public string Symbol { get; set; }
|
||||
public string Symbol { get; set; }
|
||||
[DataMember]
|
||||
public double Volume { get; set; }
|
||||
public double Volume { get; set; }
|
||||
[DataMember]
|
||||
public double Price { get; set; }
|
||||
public double Price { get; set; }
|
||||
[DataMember]
|
||||
public double Stoplimit { get; set; }
|
||||
public double Stoplimit { get; set; }
|
||||
[DataMember]
|
||||
public double Sl { get; set; }
|
||||
public double Sl { get; set; }
|
||||
[DataMember]
|
||||
public double Tp { get; set; }
|
||||
public double Tp { get; set; }
|
||||
[DataMember]
|
||||
public uint Deviation { get; set; }
|
||||
public uint Deviation { get; set; }
|
||||
[DataMember]
|
||||
public int Type { get; set; }
|
||||
public int Type { get; set; }
|
||||
[DataMember]
|
||||
public int Type_filling { get; set; }
|
||||
public int Type_filling { get; set; }
|
||||
[DataMember]
|
||||
public int Type_time { get; set; }
|
||||
public int Type_time { get; set; }
|
||||
[DataMember]
|
||||
public DateTime Expiration { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
[DataMember]
|
||||
public string Comment { get; set; }
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
using System.Diagnostics;
|
||||
|
||||
@@ -7,12 +9,12 @@ namespace MTApiService
|
||||
{
|
||||
public class MtRegistryManager
|
||||
{
|
||||
private const string Software = "Software";
|
||||
private const string AppName = "MtApi";
|
||||
private const string ProfilesRegkey = "ConnectionProfiles";
|
||||
private const string HostRegvalueName = "Host";
|
||||
private const string PortRegvalueName = "Port";
|
||||
private const string SignatureRegvalueName = "MtSignature";
|
||||
private const string SOFTWARE = "Software";
|
||||
private const string APP_NAME = "MtApi";
|
||||
private const string PROFILES_REGKEY = "ConnectionProfiles";
|
||||
private const string HOST_REGVALUE_NAME = "Host";
|
||||
private const string PORT_REGVALUE_NAME = "Port";
|
||||
private const string SIGNATURE_REGVALUE_NAME = "MtSignature";
|
||||
|
||||
#region Public Methods
|
||||
public static IEnumerable<MtConnectionProfile> LoadConnectionProfiles()
|
||||
@@ -51,12 +53,12 @@ namespace MTApiService
|
||||
|
||||
string signature = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
@@ -71,7 +73,7 @@ namespace MTApiService
|
||||
{
|
||||
using (numberKey)
|
||||
{
|
||||
signature = numberKey.GetValue(SignatureRegvalueName).ToString();
|
||||
signature = numberKey.GetValue(SIGNATURE_REGVALUE_NAME).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +94,7 @@ namespace MTApiService
|
||||
return null;
|
||||
}
|
||||
|
||||
var softwareRgKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
|
||||
if (softwareRgKey == null)
|
||||
return null;
|
||||
@@ -103,33 +105,35 @@ namespace MTApiService
|
||||
{
|
||||
|
||||
//app name
|
||||
var appRegKey = softwareRgKey.OpenSubKey(AppName, true) ?? softwareRgKey.CreateSubKey(AppName);
|
||||
|
||||
if (appRegKey != null)
|
||||
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
{
|
||||
using (appRegKey)
|
||||
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
|
||||
}
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
//account name
|
||||
var accountKey = appRegKey.OpenSubKey(accountName, true);
|
||||
if (accountKey == null)
|
||||
{
|
||||
//account name
|
||||
var accountKey = appRegKey.OpenSubKey(accountName, true) ?? appRegKey.CreateSubKey(accountName);
|
||||
accountKey = appRegKey.CreateSubKey(accountName);
|
||||
}
|
||||
|
||||
if (accountKey != null)
|
||||
using (accountKey)
|
||||
{
|
||||
//account number
|
||||
var numberKey = accountKey.OpenSubKey(accountNumber, true);
|
||||
if (numberKey == null)
|
||||
{
|
||||
using (accountKey)
|
||||
{
|
||||
//account number
|
||||
var numberKey = accountKey.OpenSubKey(accountNumber, true) ??
|
||||
accountKey.CreateSubKey(accountNumber);
|
||||
numberKey = accountKey.CreateSubKey(accountNumber);
|
||||
}
|
||||
|
||||
if (numberKey != null)
|
||||
{
|
||||
using (numberKey)
|
||||
{
|
||||
numberKey.SetValue(SignatureRegvalueName, signature);
|
||||
using (numberKey)
|
||||
{
|
||||
numberKey.SetValue(SIGNATURE_REGVALUE_NAME, signature);
|
||||
|
||||
retVal = numberKey.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
retVal = numberKey.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,19 +142,20 @@ namespace MTApiService
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static bool ExportKey(string regKey, string savePath)
|
||||
public static bool ExportKey(string RegKey, string SavePath)
|
||||
{
|
||||
var path = $"\"{savePath}\"";
|
||||
var key = $"\"{regKey}\"";
|
||||
string path = "\"" + SavePath + "\"";
|
||||
string key = "\"" + RegKey + "\"";
|
||||
|
||||
var proc = new Process();
|
||||
Process proc = new Process();
|
||||
try
|
||||
{
|
||||
proc.StartInfo.FileName = "regedit.exe";
|
||||
proc.StartInfo.UseShellExecute = false;
|
||||
proc = Process.Start("regedit.exe", "/e " + path + " " + key + "");
|
||||
|
||||
proc?.WaitForExit();
|
||||
if (proc != null)
|
||||
proc.WaitForExit();
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
@@ -158,7 +163,8 @@ namespace MTApiService
|
||||
}
|
||||
finally
|
||||
{
|
||||
proc?.Dispose();
|
||||
if (proc != null)
|
||||
proc.Dispose();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -171,38 +177,33 @@ namespace MTApiService
|
||||
{
|
||||
List<MtConnectionProfile> profiles = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
profiles = new List<MtConnectionProfile>();
|
||||
|
||||
foreach (var profileNameKey in profilesRegKey.GetSubKeyNames())
|
||||
foreach (string profileNameKey in profilesRegKey.GetSubKeyNames())
|
||||
{
|
||||
var tempKey = profilesRegKey.OpenSubKey(profileNameKey);
|
||||
if (tempKey != null)
|
||||
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileNameKey))
|
||||
{
|
||||
using (tempKey)
|
||||
{
|
||||
var profile = new MtConnectionProfile(profileNameKey)
|
||||
{
|
||||
Host = tempKey.GetValue(HostRegvalueName).ToString(),
|
||||
Port = (int) tempKey.GetValue(PortRegvalueName)
|
||||
};
|
||||
var profile = new MtConnectionProfile(profileNameKey);
|
||||
|
||||
profiles.Add(profile);
|
||||
}
|
||||
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
|
||||
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
|
||||
|
||||
profiles.Add(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,33 +220,27 @@ namespace MTApiService
|
||||
{
|
||||
MtConnectionProfile profile = null;
|
||||
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey != null)
|
||||
{
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey != null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey != null)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
var tempKey = profilesRegKey.OpenSubKey(profileName);
|
||||
if (tempKey != null)
|
||||
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileName))
|
||||
{
|
||||
using (tempKey)
|
||||
{
|
||||
profile = new MtConnectionProfile(profileName)
|
||||
{
|
||||
Host = tempKey.GetValue(HostRegvalueName).ToString(),
|
||||
Port = (int) tempKey.GetValue(PortRegvalueName)
|
||||
};
|
||||
profile = new MtConnectionProfile(profileName);
|
||||
|
||||
}
|
||||
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
|
||||
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +254,7 @@ namespace MTApiService
|
||||
|
||||
private static void SaveConnectionProfileToRegistry(MtConnectionProfile profile)
|
||||
{
|
||||
var softwareRgKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
|
||||
if (softwareRgKey == null)
|
||||
return;
|
||||
@@ -267,30 +262,29 @@ namespace MTApiService
|
||||
using (softwareRgKey)
|
||||
{
|
||||
//app name
|
||||
var appRegKey = softwareRgKey.OpenSubKey(AppName, true) ?? softwareRgKey.CreateSubKey(AppName);
|
||||
|
||||
if (appRegKey != null)
|
||||
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
{
|
||||
using (appRegKey)
|
||||
{
|
||||
//ConnectionProfiles key
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true) ??
|
||||
appRegKey.CreateSubKey(ProfilesRegkey);
|
||||
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
|
||||
}
|
||||
|
||||
if (profilesRegKey != null)
|
||||
using (appRegKey)
|
||||
{
|
||||
//ConnectionProfiles key
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey == null)
|
||||
{
|
||||
profilesRegKey = appRegKey.CreateSubKey(PROFILES_REGKEY);
|
||||
}
|
||||
|
||||
using (profilesRegKey)
|
||||
{
|
||||
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
|
||||
|
||||
using (profileKey)
|
||||
{
|
||||
using (profilesRegKey)
|
||||
{
|
||||
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
|
||||
if (profileKey != null)
|
||||
{
|
||||
using (profileKey)
|
||||
{
|
||||
profileKey.SetValue(HostRegvalueName, profile.Host);
|
||||
profileKey.SetValue(PortRegvalueName, profile.Port);
|
||||
}
|
||||
}
|
||||
}
|
||||
profileKey.SetValue(HOST_REGVALUE_NAME, profile.Host);
|
||||
profileKey.SetValue(PORT_REGVALUE_NAME, profile.Port);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,19 +293,19 @@ namespace MTApiService
|
||||
|
||||
private static void DeleteConnectionProfileFromRegistry(string profileName)
|
||||
{
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
|
||||
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
|
||||
if (softwareRegKey == null)
|
||||
return;
|
||||
|
||||
using (softwareRegKey)
|
||||
{
|
||||
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
|
||||
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
|
||||
if (appRegKey == null)
|
||||
return;
|
||||
|
||||
using (appRegKey)
|
||||
{
|
||||
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
|
||||
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
|
||||
if (profilesRegKey == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -20,8 +21,6 @@ namespace MTApiService
|
||||
typeof(MtResponseArrayList), typeof(MtResponseMqlRatesArray),
|
||||
typeof(MtResponseMqlBookInfoArray)};
|
||||
}
|
||||
|
||||
public abstract object GetValue();
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -34,13 +33,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public int Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -53,13 +45,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public long Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -72,13 +57,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public ulong Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -91,13 +69,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public double Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -110,13 +81,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public string Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -129,13 +93,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public bool Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -148,13 +105,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public double[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -167,13 +117,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public int[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -186,13 +129,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public long[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -205,13 +141,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public ArrayList Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -224,13 +153,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public MtMqlRates[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -243,13 +165,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public MtMqlTick Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
@@ -262,13 +177,6 @@ namespace MTApiService
|
||||
|
||||
[DataMember]
|
||||
public MtMqlBookInfo[] Value { get; private set; }
|
||||
|
||||
public override object GetValue() { return Value; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+105
-195
@@ -3,26 +3,17 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ServiceModel;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Net.Sockets;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
internal class MtServer : IDisposable, IMtApiServer
|
||||
{
|
||||
#region Constants
|
||||
private const int WaitResponseTime = 40000; // 40 sec
|
||||
private const int StopExpertInterval = 1000; // 1 sec
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServer));
|
||||
|
||||
private readonly MtService _service;
|
||||
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
|
||||
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
|
||||
private readonly List<MtExpert> _experts = new List<MtExpert>();
|
||||
private const int WAIT_RESPONSE_TIME = 40000; // 40 sec
|
||||
private const int STOP_EXPERT_INTERVAL = 1000; // 1 sec
|
||||
#endregion
|
||||
|
||||
#region ctor
|
||||
@@ -34,126 +25,99 @@ namespace MTApiService
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public int Port { get; }
|
||||
public int Port { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void Start()
|
||||
{
|
||||
Log.Debug("Start: begin");
|
||||
|
||||
var hostsInitialized = InitHosts(Port);
|
||||
|
||||
Log.DebugFormat("Start: end. hostsInitialized = {0}", hostsInitialized);
|
||||
if (hostsInitialized == false)
|
||||
{
|
||||
Debug.WriteLine("Start: InitHosts failed. ");
|
||||
}
|
||||
}
|
||||
|
||||
private bool InitHosts(int port)
|
||||
{
|
||||
Log.DebugFormat("InitHosts: begin. port = {0}", port);
|
||||
|
||||
int count;
|
||||
|
||||
lock (_hosts)
|
||||
{
|
||||
if (_hosts.Count > 0)
|
||||
{
|
||||
Log.Info("InitHosts: end. Host's has been initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
//init local pipe host
|
||||
var localUrl = CreateConnectionAddress(null, port, true);
|
||||
var localServiceHost = CreateServiceHost(localUrl, true);
|
||||
string localUrl = CreateConnectionAddress(null, port, true);
|
||||
ServiceHost localServiceHost = CreateServiceHost(localUrl, true);
|
||||
if (localServiceHost != null)
|
||||
{
|
||||
_hosts.Add(localServiceHost);
|
||||
}
|
||||
|
||||
//init network hosts
|
||||
var dnsHostName = Dns.GetHostName();
|
||||
var ips = Dns.GetHostEntry(dnsHostName);
|
||||
if (ips == null)
|
||||
IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());
|
||||
if (ips != null)
|
||||
{
|
||||
Log.WarnFormat("InitHosts: end. Dns.GetHostEntry has returned null for DNS Host Name {0}", dnsHostName);
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var ipAddress in ips.AddressList)
|
||||
{
|
||||
if (ipAddress?.AddressFamily == AddressFamily.InterNetwork)
|
||||
foreach (IPAddress ipAddress in ips.AddressList)
|
||||
{
|
||||
var ip = ipAddress.ToString();
|
||||
var networkUrl = CreateConnectionAddress(ip, port, false);
|
||||
var serviceHost = CreateServiceHost(networkUrl, false);
|
||||
if (serviceHost != null)
|
||||
if (ipAddress != null)
|
||||
{
|
||||
_hosts.Add(serviceHost);
|
||||
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
string ip = ipAddress.ToString();
|
||||
string networkUrl = CreateConnectionAddress(ip, port, false);
|
||||
ServiceHost serviceHost = CreateServiceHost(networkUrl, false);
|
||||
if (serviceHost != null)
|
||||
{
|
||||
_hosts.Add(serviceHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
count = _hosts.Count;
|
||||
}
|
||||
|
||||
Log.DebugFormat("InitHosts: end. Host's count = {0}", count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private ServiceHost CreateServiceHost(string serverUrlAdress, bool local)
|
||||
{
|
||||
Log.DebugFormat("CreateServiceHost: begin. serverUrlAdress = {0}; local = {1}", serverUrlAdress, local);
|
||||
|
||||
if (serverUrlAdress == null)
|
||||
ServiceHost serviceHost = null;
|
||||
if (serverUrlAdress != null)
|
||||
{
|
||||
Log.Warn("CreateServiceHost: end. serverUrlAdress is not defined");
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
serviceHost = new ServiceHost(_service);
|
||||
var binding = CreateConnectionBinding(local);
|
||||
|
||||
ServiceHost serviceHost;
|
||||
try
|
||||
{
|
||||
serviceHost = new ServiceHost(_service);
|
||||
var binding = CreateConnectionBinding(local);
|
||||
|
||||
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
|
||||
serviceHost.Open();
|
||||
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
|
||||
serviceHost.Open();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Debug.WriteLine("CreateServiceHost: Create ServiceHost failed. " + e.Message);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.ErrorFormat("CreateServiceHost: Error! {0}", e.Message);
|
||||
serviceHost = null;
|
||||
}
|
||||
|
||||
Log.Debug("CreateServiceHost: end.");
|
||||
|
||||
return serviceHost;
|
||||
}
|
||||
|
||||
public void AddExpert(MtExpert expert)
|
||||
{
|
||||
Log.DebugFormat("AddExpert: begin. expert {0}", expert);
|
||||
|
||||
if (expert == null)
|
||||
if (expert != null)
|
||||
{
|
||||
Log.Warn("AddExpert: end. expert is not defined");
|
||||
return;
|
||||
expert.Deinited += expert_Deinited;
|
||||
expert.QuoteChanged += expert_QuoteChanged;
|
||||
expert.OnMtEvent += Expert_OnMtEvent;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
_experts.Add(expert);
|
||||
}
|
||||
|
||||
_executorManager.AddCommandExecutor(expert);
|
||||
|
||||
_service.OnQuoteAdded(expert.Quote);
|
||||
}
|
||||
|
||||
expert.Deinited += expert_Deinited;
|
||||
expert.QuoteChanged += expert_QuoteChanged;
|
||||
expert.OnMtEvent += Expert_OnMtEvent;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
_experts.Add(expert);
|
||||
}
|
||||
|
||||
_executorManager.AddCommandExecutor(expert);
|
||||
|
||||
_service.OnQuoteAdded(expert.Quote);
|
||||
|
||||
Log.Debug("AddExpert: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -162,30 +126,25 @@ namespace MTApiService
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
Log.DebugFormat("SendCommand: begin. command {0}", command);
|
||||
MtResponse response = null;
|
||||
|
||||
if (command == null)
|
||||
if (command != null)
|
||||
{
|
||||
Log.Warn("SendCommand: end. command is not defined");
|
||||
return null;
|
||||
var task = new MtCommandTask(command);
|
||||
_executorManager.EnqueueCommandTask(task);
|
||||
|
||||
//wait for execute command in MetaTrader
|
||||
response = task.WaitResult(WAIT_RESPONSE_TIME);
|
||||
}
|
||||
|
||||
var task = new MtCommandTask(command);
|
||||
_executorManager.EnqueueCommandTask(task);
|
||||
|
||||
//wait for execute command in MetaTrader
|
||||
var response = task.WaitResult(WaitResponseTime);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public List<MtQuote> GetQuotes()
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
Log.Debug("GetQuotes: called");
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
return _experts.Select(s => s.Quote).ToList();
|
||||
return (from s in _experts select s.Quote);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,131 +153,99 @@ namespace MTApiService
|
||||
#region Private Methods
|
||||
private void stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
Log.DebugFormat("stopTimer_Elapsed: begin");
|
||||
|
||||
int expertsCount;
|
||||
var expertsCount = 0;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
expertsCount = _experts.Count;
|
||||
expertsCount = _experts.Count();
|
||||
}
|
||||
|
||||
if (expertsCount == 0)
|
||||
{
|
||||
_service.OnStopServer();
|
||||
|
||||
Log.DebugFormat("stopTimer_Elapsed: experts count is 0. Call Stop().");
|
||||
|
||||
Stop();
|
||||
}
|
||||
|
||||
var stopTimer = sender as System.Timers.Timer;
|
||||
if (stopTimer == null) return;
|
||||
|
||||
stopTimer.Stop();
|
||||
stopTimer.Elapsed -= stopTimer_Elapsed;
|
||||
|
||||
Log.DebugFormat("stopTimer_Elapsed: end");
|
||||
if (stopTimer != null)
|
||||
{
|
||||
stopTimer.Stop();
|
||||
stopTimer.Elapsed -= stopTimer_Elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateConnectionAddress(string host, int port, bool local)
|
||||
private string CreateConnectionAddress(string host, int port, bool local)
|
||||
{
|
||||
Log.DebugFormat("CreateConnectionAddress: begin. host = {0}, port = {1}, local = {2}", host, port, local);
|
||||
|
||||
string connectionAddress = null;
|
||||
|
||||
if (local)
|
||||
if (local == true)
|
||||
{
|
||||
//by Pipe
|
||||
connectionAddress = "net.pipe://localhost/MtApiService_" + port;
|
||||
connectionAddress = "net.pipe://localhost/MtApiService_" + port.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
//by Socket
|
||||
if (host != null)
|
||||
{
|
||||
connectionAddress = "net.tcp://" + host + ":" + port + "/MtApiService";
|
||||
}
|
||||
connectionAddress = "net.tcp://" + host.ToString() + ":" + port.ToString() + "/MtApiService";
|
||||
}
|
||||
}
|
||||
|
||||
Log.DebugFormat("CreateConnectionAddress: end. connectionAddress = {0}", connectionAddress);
|
||||
|
||||
return connectionAddress;
|
||||
}
|
||||
|
||||
private static Binding CreateConnectionBinding(bool local)
|
||||
{
|
||||
Log.DebugFormat("CreateConnectionBinding: begin. local = {0}", local);
|
||||
Binding connectionBinding = null;
|
||||
|
||||
Binding connectionBinding;
|
||||
|
||||
if (local)
|
||||
if (local == true)
|
||||
{
|
||||
//by Pipe
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
|
||||
{
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
SendTimeout = new TimeSpan(12, 0, 0),
|
||||
ReceiveTimeout = new TimeSpan(12, 0, 0),
|
||||
ReaderQuotas =
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 2147483647;
|
||||
|
||||
// Commented next statement since it is not required
|
||||
bind.MaxBufferPoolSize = 2147483647;
|
||||
bind.ReaderQuotas.MaxArrayLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxBytesPerRead = 2147483647;
|
||||
bind.ReaderQuotas.MaxDepth = 2147483647;
|
||||
bind.ReaderQuotas.MaxStringContentLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxNameTableCharCount = 2147483647;
|
||||
|
||||
connectionBinding = bind;
|
||||
}
|
||||
else
|
||||
{
|
||||
//by Socket
|
||||
var bind = new NetTcpBinding(SecurityMode.None)
|
||||
{
|
||||
MaxReceivedMessageSize = 2147483647,
|
||||
MaxBufferSize = 2147483647,
|
||||
MaxBufferPoolSize = 2147483647,
|
||||
SendTimeout = new TimeSpan(12, 0, 0),
|
||||
ReceiveTimeout = new TimeSpan(12, 0, 0),
|
||||
ReaderQuotas =
|
||||
{
|
||||
MaxArrayLength = 2147483647,
|
||||
MaxBytesPerRead = 2147483647,
|
||||
MaxDepth = 2147483647,
|
||||
MaxStringContentLength = 2147483647,
|
||||
MaxNameTableCharCount = 2147483647
|
||||
}
|
||||
};
|
||||
var bind = new NetTcpBinding(SecurityMode.None);
|
||||
bind.MaxReceivedMessageSize = 2147483647;
|
||||
bind.MaxBufferSize = 2147483647;
|
||||
|
||||
// Commented next statement since it is not required
|
||||
bind.MaxBufferPoolSize = 2147483647;
|
||||
bind.ReaderQuotas.MaxArrayLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxBytesPerRead = 2147483647;
|
||||
bind.ReaderQuotas.MaxDepth = 2147483647;
|
||||
bind.ReaderQuotas.MaxStringContentLength = 2147483647;
|
||||
bind.ReaderQuotas.MaxNameTableCharCount = 2147483647;
|
||||
|
||||
connectionBinding = bind;
|
||||
}
|
||||
|
||||
Log.Debug("CreateConnectionBinding: end.");
|
||||
|
||||
return connectionBinding;
|
||||
}
|
||||
|
||||
private void Stop()
|
||||
{
|
||||
Log.Debug("Stop: begin.");
|
||||
|
||||
_executorManager.Stop();
|
||||
|
||||
lock (_hosts)
|
||||
{
|
||||
if (_hosts.Count == 0)
|
||||
{
|
||||
Log.Debug("Stop: end. Host count is 0.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -327,18 +254,15 @@ namespace MTApiService
|
||||
host.Close();
|
||||
}
|
||||
}
|
||||
catch (TimeoutException ex)
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Log.ErrorFormat("Stop: TimeoutException - {0}", ex.Message);
|
||||
|
||||
foreach (var host in _hosts)
|
||||
{
|
||||
host.Abort();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception)
|
||||
{
|
||||
Log.ErrorFormat("Stop: Exception - {0}", ex.Message);
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
@@ -348,27 +272,20 @@ namespace MTApiService
|
||||
}
|
||||
|
||||
FireOnStopped();
|
||||
|
||||
Log.Debug("Stop: end.");
|
||||
}
|
||||
|
||||
private void expert_Deinited(object sender, EventArgs e)
|
||||
{
|
||||
Log.Debug("expert_Deinited: begin.");
|
||||
|
||||
var expert = sender as MtExpert;
|
||||
if (expert == null)
|
||||
{
|
||||
Log.Warn("expert_Deinited: end. Expert is not defined.");
|
||||
if (sender == null)
|
||||
return;
|
||||
}
|
||||
|
||||
int expertsCount;
|
||||
var expert = (MtExpert)sender;
|
||||
var expertsCount = 0;
|
||||
|
||||
lock (_experts)
|
||||
{
|
||||
_experts.Remove(expert);
|
||||
expertsCount = _experts.Count;
|
||||
expertsCount = _experts.Count();
|
||||
}
|
||||
|
||||
_executorManager.RemoveCommandExecutor(expert);
|
||||
@@ -382,29 +299,19 @@ namespace MTApiService
|
||||
{
|
||||
var stopTimer = new System.Timers.Timer();
|
||||
stopTimer.Elapsed += stopTimer_Elapsed;
|
||||
stopTimer.Interval = StopExpertInterval;
|
||||
stopTimer.Interval = STOP_EXPERT_INTERVAL;
|
||||
stopTimer.Start();
|
||||
}
|
||||
|
||||
Log.Debug("expert_Deinited: end.");
|
||||
}
|
||||
|
||||
private void expert_QuoteChanged(MtExpert expert, MtQuote quote)
|
||||
{
|
||||
Log.DebugFormat("expert_QuoteChanged: begin. expert = {0}, quote = {1}", expert, quote);
|
||||
|
||||
_service.QuoteUpdate(quote);
|
||||
|
||||
Log.Debug("expert_QuoteChanged: end.");
|
||||
}
|
||||
|
||||
private void Expert_OnMtEvent(object sender, MtEventArgs e)
|
||||
{
|
||||
Log.DebugFormat("Expert_OnMtEvent: begin. event = {0}", e.Event);
|
||||
|
||||
_service.OnMtEvent(e.Event);
|
||||
|
||||
Log.Debug("Expert_OnMtEvent: end.");
|
||||
}
|
||||
|
||||
private void FireOnStopped()
|
||||
@@ -421,13 +328,16 @@ namespace MTApiService
|
||||
#region IDispose
|
||||
public void Dispose()
|
||||
{
|
||||
Log.Debug("Dispose: begin");
|
||||
|
||||
Stop();
|
||||
|
||||
Log.Debug("Dispose: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly MtService _service;
|
||||
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
|
||||
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
|
||||
private readonly List<MtExpert> _experts = new List<MtExpert>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ServiceModel;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
public class MtServerInstance
|
||||
{
|
||||
#region Fields
|
||||
private const string LogProfileName = "MtApiService";
|
||||
#region Init_Instance
|
||||
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServerInstance));
|
||||
private static readonly MtServerInstance Instance = new MtServerInstance();
|
||||
|
||||
private readonly Dictionary<int, MtServer> _servers = new Dictionary<int, MtServer>();
|
||||
private readonly Dictionary<int, MtExpert> _experts = new Dictionary<int, MtExpert>();
|
||||
#endregion
|
||||
|
||||
#region Init Instance
|
||||
static readonly MtServerInstance mInstance = new MtServerInstance();
|
||||
|
||||
private MtServerInstance()
|
||||
{
|
||||
LogConfigurator.Setup(LogProfileName);
|
||||
{
|
||||
}
|
||||
|
||||
static MtServerInstance()
|
||||
{
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
public static MtServerInstance GetInstance()
|
||||
{
|
||||
return Instance;
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -38,23 +33,20 @@ namespace MTApiService
|
||||
#region Public Methods
|
||||
public void InitExpert(int expertHandle, int port, string symbol, double bid, double ask, IMetaTraderHandler mtHandler)
|
||||
{
|
||||
if (mtHandler == null)
|
||||
throw new ArgumentNullException(nameof(mtHandler));
|
||||
Debug.WriteLine("MtApiServerInstance::InitExpert: symbol = {0}, expertHandle = {1}, port = {2}", symbol, expertHandle, port);
|
||||
|
||||
Log.InfoFormat("InitExpert: begin. symbol = {0}, expertHandle = {1}, port = {2}", symbol, expertHandle, port);
|
||||
|
||||
MtServer server;
|
||||
lock (_servers)
|
||||
MtServer server = null;
|
||||
lock (mServersDictionary)
|
||||
{
|
||||
if (_servers.ContainsKey(port))
|
||||
if (mServersDictionary.ContainsKey(port))
|
||||
{
|
||||
server = _servers[port];
|
||||
server = mServersDictionary[port];
|
||||
}
|
||||
else
|
||||
{
|
||||
server = new MtServer(port);
|
||||
server.Stopped += server_Stopped;
|
||||
_servers[port] = server;
|
||||
server.Stopped += new EventHandler(server_Stopped);
|
||||
mServersDictionary[port] = server;
|
||||
|
||||
server.Start();
|
||||
}
|
||||
@@ -62,172 +54,137 @@ namespace MTApiService
|
||||
|
||||
var expert = new MtExpert(expertHandle, new MtQuote(symbol, bid, ask), mtHandler);
|
||||
|
||||
lock (_experts)
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
_experts[expert.Handle] = expert;
|
||||
mExpertsDictionary[expert.Handle] = expert;
|
||||
}
|
||||
|
||||
server.AddExpert(expert);
|
||||
|
||||
Log.Info("InitExpert: end");
|
||||
}
|
||||
|
||||
public void DeinitExpert(int expertHandle)
|
||||
{
|
||||
Log.InfoFormat("DeinitExpert: begin. expertHandle = {0}", expertHandle);
|
||||
Debug.WriteLine("MtApiServerInstance::DeinitExpert: expertHandle = {0}", expertHandle);
|
||||
|
||||
MtExpert expert = null;
|
||||
|
||||
lock (_experts)
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
if (_experts.ContainsKey(expertHandle))
|
||||
if (mExpertsDictionary.ContainsKey(expertHandle) == true)
|
||||
{
|
||||
expert = _experts[expertHandle];
|
||||
_experts.Remove(expertHandle);
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
mExpertsDictionary.Remove(expertHandle);
|
||||
}
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Deinit();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("DeinitExpert: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Log.Info("DeinitExpert: end");
|
||||
}
|
||||
}
|
||||
|
||||
public void SendQuote(int expertHandle, string symbol, double bid, double ask)
|
||||
{
|
||||
Log.DebugFormat("SendQuote: begin. symbol = {0}, bid = {1}, ask = {2}", symbol, bid, ask);
|
||||
Debug.WriteLine("MtApiServerInstance::SendQuote: enter. symbol = {0}, bid = {1}, ask = {2}", symbol, bid, ask);
|
||||
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = _experts[expertHandle];
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.Quote = new MtQuote(symbol, bid, ask);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("SendQuote: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Log.Debug("SendQuote: end");
|
||||
Debug.WriteLine("MtApiServerInstance::SendQuote: finish.");
|
||||
}
|
||||
|
||||
public void SendEvent(int expertHandle, int eventType, string payload)
|
||||
{
|
||||
Log.DebugFormat("SendEvent: begin. eventType = {0}, payload = {1}", eventType, payload);
|
||||
Debug.WriteLine("MtApiServerInstance::SendEvent called. eventType = {0}, payload = {1}", eventType, payload);
|
||||
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = _experts[expertHandle];
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.SendEvent(new MtEvent(eventType, payload));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("SendEvent: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Log.Debug("SendEvent: end");
|
||||
Debug.WriteLine("MtApiServerInstance::SendEvent: finished");
|
||||
}
|
||||
|
||||
public void SendResponse(int expertHandle, MtResponse response)
|
||||
{
|
||||
Log.DebugFormat("SendResponse: begin. id = {0}, response = {1}", expertHandle, response);
|
||||
Debug.WriteLine("MtApiServerInstance::SendResponse: id = {0}, response = {1}", expertHandle, response);
|
||||
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = _experts[expertHandle];
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert != null)
|
||||
{
|
||||
expert.SendResponse(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.WarnFormat("SendResponse: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
Log.Debug("SendResponse: end");
|
||||
Debug.WriteLine("MtApiServerInstance::SendResponse: finish");
|
||||
}
|
||||
|
||||
public int GetCommandType(int expertHandle)
|
||||
{
|
||||
Log.DebugFormat("GetCommandType: begin. expertHandle = {0}", expertHandle);
|
||||
Debug.WriteLine("MtApiServerInstance::GetCommandType: expertHandle = {0}", expertHandle);
|
||||
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = _experts[expertHandle];
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert == null)
|
||||
{
|
||||
Log.WarnFormat("GetCommandType: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
var retval = expert?.GetCommandType() ?? 0;
|
||||
|
||||
Log.DebugFormat("GetCommandType: end. retval = {0}", retval);
|
||||
|
||||
return retval;
|
||||
return (expert != null) ? expert.GetCommandType() : 0;
|
||||
}
|
||||
|
||||
public object GetCommandParameter(int expertHandle, int index)
|
||||
{
|
||||
Log.DebugFormat("GetCommandParameter: begin. expertHandle = {0}, index = {1}", expertHandle, index);
|
||||
Debug.WriteLine("MtApiServerInstance::GetCommandParameter: expertHandle = {0}, index = {1}", expertHandle, index);
|
||||
|
||||
MtExpert expert;
|
||||
lock (_experts)
|
||||
MtExpert expert = null;
|
||||
lock (mExpertsDictionary)
|
||||
{
|
||||
expert = _experts[expertHandle];
|
||||
expert = mExpertsDictionary[expertHandle];
|
||||
}
|
||||
|
||||
if (expert == null)
|
||||
{
|
||||
Log.WarnFormat("GetCommandParameter: expert with id {0} has not been found.", expertHandle);
|
||||
}
|
||||
|
||||
var retval = expert?.GetCommandParameter(index);
|
||||
|
||||
Log.DebugFormat("GetCommandParameter: end. retval = {0}", retval);
|
||||
|
||||
return retval;
|
||||
return (expert != null) ? expert.GetCommandParameter(index) : null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void server_Stopped(object sender, EventArgs e)
|
||||
{
|
||||
var server = (MtServer)sender;
|
||||
MtServer server = (MtServer)sender;
|
||||
server.Stopped -= server_Stopped;
|
||||
|
||||
var port = server.Port;
|
||||
|
||||
Log.InfoFormat("server_Stopped: port = {0}", port);
|
||||
|
||||
lock (_servers)
|
||||
lock (mServersDictionary)
|
||||
{
|
||||
if (_servers.ContainsKey(port))
|
||||
if (mServersDictionary.ContainsKey(port))
|
||||
{
|
||||
_servers.Remove(port);
|
||||
mServersDictionary.Remove(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly MtRegistryManager mConnectionManager = new MtRegistryManager();
|
||||
private readonly Dictionary<int, MtServer> mServersDictionary = new Dictionary<int, MtServer>();
|
||||
private readonly Dictionary<int, MtExpert> mExpertsDictionary = new Dictionary<int, MtExpert>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
+48
-99
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
|
||||
namespace MTApiService
|
||||
{
|
||||
@@ -19,7 +18,7 @@ namespace MTApiService
|
||||
MtResponse SendCommand(MtCommand command);
|
||||
|
||||
[OperationContract]
|
||||
List<MtQuote> GetQuotes();
|
||||
IEnumerable<MtQuote> GetQuotes();
|
||||
}
|
||||
|
||||
[ServiceContract]
|
||||
@@ -47,149 +46,107 @@ namespace MTApiService
|
||||
InstanceContextMode = InstanceContextMode.Single)]
|
||||
public sealed class MtService : IMtApi
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(MtService));
|
||||
|
||||
public MtService(IMtApiServer serverCallback)
|
||||
{
|
||||
if (serverCallback == null)
|
||||
throw new ArgumentNullException(nameof(serverCallback));
|
||||
throw new ArgumentNullException("serverCallback");
|
||||
|
||||
_server = serverCallback;
|
||||
mServer = serverCallback;
|
||||
}
|
||||
|
||||
#region IMtApi
|
||||
public bool Connect()
|
||||
{
|
||||
Log.Debug("Connect: begin");
|
||||
bool connected = false;
|
||||
|
||||
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
if (callback == null)
|
||||
if (callback != null)
|
||||
{
|
||||
Log.Warn("Connect: end. Callback is not definded.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var connected = false;
|
||||
|
||||
try
|
||||
{
|
||||
_clientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
if (_clientCallbacks.Contains(callback) == false)
|
||||
_clientCallbacks.Add(callback);
|
||||
mClientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
connected = true;
|
||||
try
|
||||
{
|
||||
if (mClientCallbacks.Contains(callback) == false)
|
||||
mClientCallbacks.Add(callback);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
finally
|
||||
catch (ApplicationException)
|
||||
{
|
||||
_clientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
Log.ErrorFormat("Connect: ApplicationException - {0}", ex.Message);
|
||||
}
|
||||
|
||||
Log.DebugFormat("Connect: end. connected = {0}", connected);
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Log.Debug("Disconnect: begin");
|
||||
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
|
||||
|
||||
if (callback == null)
|
||||
if (callback != null)
|
||||
{
|
||||
Log.Warn("Disconnect: end. Callback is not definded.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_clientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
try
|
||||
{
|
||||
_clientCallbacks.Remove(callback);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_clientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
{
|
||||
Log.ErrorFormat("Disconnect: ApplicationException - {0}", ex.Message);
|
||||
}
|
||||
mClientsLocker.AcquireWriterLock(10000);
|
||||
|
||||
Log.Debug("Disconnect: end.");
|
||||
try
|
||||
{
|
||||
mClientCallbacks.Remove(callback);
|
||||
}
|
||||
finally
|
||||
{
|
||||
mClientsLocker.ReleaseWriterLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MtResponse SendCommand(MtCommand command)
|
||||
{
|
||||
Log.DebugFormat("SendCommand: called. command = {0}", command);
|
||||
|
||||
return _server.SendCommand(command);
|
||||
return mServer.SendCommand(command);
|
||||
}
|
||||
|
||||
public List<MtQuote> GetQuotes()
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
Log.Debug("GetQuotes: called.");
|
||||
|
||||
return _server.GetQuotes();
|
||||
return mServer.GetQuotes();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
public void OnStopServer()
|
||||
{
|
||||
Log.Debug("OnStopServer: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnServerStopped());
|
||||
|
||||
Log.Debug("OnStopServer: end.");
|
||||
}
|
||||
|
||||
public void QuoteUpdate(MtQuote quote)
|
||||
{
|
||||
Log.Debug("QuoteUpdate: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
|
||||
|
||||
Log.Debug("QuoteUpdate: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteAdded(MtQuote quote)
|
||||
{
|
||||
Log.Debug("OnQuoteAdded: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
|
||||
|
||||
Log.Debug("OnQuoteAdded: end.");
|
||||
}
|
||||
|
||||
public void OnQuoteRemoved(MtQuote quote)
|
||||
{
|
||||
Log.Debug("OnQuoteRemoved: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
|
||||
|
||||
Log.Debug("OnQuoteRemoved: end.");
|
||||
}
|
||||
|
||||
public void OnMtEvent(MtEvent mtEvent)
|
||||
{
|
||||
Log.Debug("OnMtEvent: begin.");
|
||||
|
||||
ExecuteCallbackAction(a => a.OnMtEvent(mtEvent));
|
||||
|
||||
Log.Debug("OnMtEvent: end.");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -197,26 +154,22 @@ namespace MTApiService
|
||||
|
||||
private void ExecuteCallbackAction(Action<IMtApiCallback> action)
|
||||
{
|
||||
Log.Debug("ExecuteCallbackAction: begin.");
|
||||
|
||||
try
|
||||
{
|
||||
_clientsLocker.AcquireReaderLock(2000);
|
||||
mClientsLocker.AcquireReaderLock(2000);
|
||||
|
||||
List<IMtApiCallback> crashedClientCallbacks = null;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var callback in _clientCallbacks)
|
||||
foreach (var callback in mClientCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(callback);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception)
|
||||
{
|
||||
Log.ErrorFormat("ExecuteCallbackAction: Exception - {0}", ex.Message);
|
||||
|
||||
if (crashedClientCallbacks == null)
|
||||
crashedClientCallbacks = new List<IMtApiCallback>();
|
||||
|
||||
@@ -226,33 +179,29 @@ namespace MTApiService
|
||||
|
||||
if (crashedClientCallbacks != null)
|
||||
{
|
||||
Log.WarnFormat("ExecuteCallbackAction: crashed callback count = {0}", crashedClientCallbacks.Count);
|
||||
|
||||
foreach (var crashedCallback in crashedClientCallbacks)
|
||||
{
|
||||
_clientCallbacks.Remove(crashedCallback);
|
||||
mClientCallbacks.Remove(crashedCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_clientsLocker.ReleaseReaderLock();
|
||||
mClientsLocker.ReleaseReaderLock();
|
||||
}
|
||||
}
|
||||
catch (ApplicationException ex)
|
||||
catch (ApplicationException)
|
||||
{
|
||||
Log.ErrorFormat("ExecuteCallbackAction: ApplicationException - {0}", ex.Message);
|
||||
//TODO: add logging
|
||||
}
|
||||
|
||||
Log.Debug("ExecuteCallbackAction: end.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
private readonly IMtApiServer _server;
|
||||
private readonly List<IMtApiCallback> _clientCallbacks = new List<IMtApiCallback>();
|
||||
private readonly ReaderWriterLock _clientsLocker = new ReaderWriterLock();
|
||||
private readonly IMtApiServer mServer;
|
||||
private readonly List<IMtApiCallback> mClientCallbacks = new List<IMtApiCallback>();
|
||||
private readonly ReaderWriterLock mClientsLocker = new ReaderWriterLock();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.22.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.22.0")]
|
||||
[assembly: AssemblyVersion("1.0.21.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.21.0")]
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ILMerge" version="2.13.0307" targetFramework="net40" />
|
||||
<package id="log4net" version="2.0.5" targetFramework="net40" />
|
||||
<package id="MSBuild.ILMerge.Task" version="1.0.5" targetFramework="net40" />
|
||||
</packages>
|
||||
@@ -11,11 +11,13 @@ ref class MT4Handler: IMetaTraderHandler
|
||||
public:
|
||||
MT4Handler()
|
||||
{
|
||||
//msgId = RegisterWindowMessage("MetaTrader4_Internal_Message");
|
||||
msgId = WM_TIMER;
|
||||
}
|
||||
|
||||
virtual void SendTickToMetaTrader(int handle)
|
||||
{
|
||||
//PostMessage((HWND)handle, msgId, 2, 1);
|
||||
PostMessage((HWND)handle, msgId, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -255,4 +255,19 @@ int _stdcall getStringValue(int expertHandle, int paramIndex, wchar_t* res)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _stdcall getBooleanValue(int expertHandle, int paramIndex, int* res)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool val = (bool)MtServerInstance::GetInstance()->GetCommandParameter(expertHandle, paramIndex);
|
||||
*res = val == true ? 1 : 0;
|
||||
}
|
||||
catch (Exception^ e)
|
||||
{
|
||||
Debug::WriteLine("[ERROR] MT5Connector:getBooleanValue(): " + e->Message);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -14,4 +14,5 @@ EXPORTS initExpert
|
||||
getCommandType
|
||||
getIntValue
|
||||
getDoubleValue
|
||||
getStringValue
|
||||
getStringValue
|
||||
getBooleanValue
|
||||
+201
-178
@@ -15,34 +15,25 @@ namespace MtApi
|
||||
|
||||
public sealed class MtApiClient
|
||||
{
|
||||
private volatile bool _isBacktestingMode;
|
||||
private const int DoubleArrayLimit = 64800;
|
||||
private volatile bool IsBacktestingMode = false;
|
||||
|
||||
#region MetaTrader Constants
|
||||
|
||||
//Special constant
|
||||
public const int NULL = 0;
|
||||
public const int EMPTY = -1;
|
||||
|
||||
private const string LogProfileName = "MtApiClient";
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly MtClient _client = new MtClient();
|
||||
private readonly object _locker = new object();
|
||||
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
|
||||
#endregion
|
||||
|
||||
#region ctor
|
||||
|
||||
public MtApiClient()
|
||||
{
|
||||
LogConfigurator.Setup(LogProfileName);
|
||||
|
||||
_client.QuoteAdded += _client_QuoteAdded;
|
||||
_client.QuoteRemoved += _client_QuoteRemoved;
|
||||
_client.QuoteUpdated += _client_QuoteUpdated;
|
||||
_client.ServerDisconnected += _client_ServerDisconnected;
|
||||
_client.ServerFailed += _client_ServerFailed;
|
||||
_client.QuoteAdded += mClient_QuoteAdded;
|
||||
_client.QuoteRemoved += mClient_QuoteRemoved;
|
||||
_client.QuoteUpdated += mClient_QuoteUpdated;
|
||||
_client.ServerDisconnected += mClient_ServerDisconnected;
|
||||
_client.ServerFailed += mClient_ServerFailed;
|
||||
_client.MtEventReceived += _client_MtEventReceived;
|
||||
}
|
||||
#endregion
|
||||
@@ -55,8 +46,15 @@ namespace MtApi
|
||||
///<param name="port">Port of host connection (default 8222) </param>
|
||||
public void BeginConnect(string host, int port)
|
||||
{
|
||||
//if (string.IsNullOrEmpty(host) == false && (host.Equals("localhost") || host.Equals("127.0.0.1")))
|
||||
//{
|
||||
// this.BeginConnect(port);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
Action<string, int> connectAction = Connect;
|
||||
connectAction.BeginInvoke(host, port, null, null);
|
||||
//}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
@@ -83,16 +81,12 @@ namespace MtApi
|
||||
///</summary>
|
||||
public IEnumerable<MtQuote> GetQuotes()
|
||||
{
|
||||
IEnumerable<MTApiService.MtQuote> quotes;
|
||||
lock (_client)
|
||||
{
|
||||
quotes = _client.GetQuotes();
|
||||
}
|
||||
return quotes?.Select(q => q.Convert());
|
||||
var quotes = _client.GetQuotes();
|
||||
return quotes != null ? (from q in quotes select q.Convert()) : null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
#region Properties
|
||||
|
||||
///<summary>
|
||||
///Connection status of MetaTrader API.
|
||||
@@ -180,7 +174,7 @@ namespace MtApi
|
||||
public double OrderOpenPrice(int ticket)
|
||||
{
|
||||
var commandParameters = new ArrayList { ticket };
|
||||
var retVal = SendCommand<double>(MtCommandType.OrderOpenPriceByTicket, commandParameters);
|
||||
double retVal = SendCommand<double>(MtCommandType.OrderOpenPriceByTicket, commandParameters);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
@@ -225,7 +219,7 @@ namespace MtApi
|
||||
[Obsolete("OrderType is deprecated, please use GetOrder instead.")]
|
||||
public TradeOperation OrderType()
|
||||
{
|
||||
var retVal = SendCommand<int>(MtCommandType.OrderType, null);
|
||||
int retVal = SendCommand<int>(MtCommandType.OrderType, null);
|
||||
|
||||
return (TradeOperation)retVal;
|
||||
}
|
||||
@@ -256,7 +250,7 @@ namespace MtApi
|
||||
Expiration = MtApiTimeConverter.ConvertToMtTime(expiration),
|
||||
ArrowColor = MtApiColorConverter.ConvertToMtColor(arrowColor)
|
||||
});
|
||||
return response?.Ticket ?? -1;
|
||||
return response != null ? response.Ticket : -1;
|
||||
}
|
||||
|
||||
public int OrderSend(string symbol, TradeOperation cmd, double volume, double price, int slippage, double stoploss, double takeprofit
|
||||
@@ -284,7 +278,7 @@ namespace MtApi
|
||||
|
||||
public int OrderSend(string symbol, TradeOperation cmd, double volume, string price, int slippage, double stoploss, double takeprofit)
|
||||
{
|
||||
double dPrice;
|
||||
double dPrice = 0;
|
||||
return double.TryParse(price, out dPrice) ?
|
||||
OrderSend(symbol, cmd, volume, dPrice, slippage, stoploss, takeprofit, null, 0, DateTime.MinValue, Color.Empty) : 0;
|
||||
}
|
||||
@@ -322,7 +316,7 @@ namespace MtApi
|
||||
Comment = comment,
|
||||
Magic = magic,
|
||||
});
|
||||
return response?.Ticket ?? -1;
|
||||
return response != null ? response.Ticket : -1;
|
||||
}
|
||||
|
||||
public int OrderSendSell(string symbol, double volume, int slippage, double stoploss, double takeprofit, string comment, int magic)
|
||||
@@ -338,7 +332,7 @@ namespace MtApi
|
||||
Comment = comment,
|
||||
Magic = magic,
|
||||
});
|
||||
return response?.Ticket ?? -1;
|
||||
return response != null ? response.Ticket : -1;
|
||||
}
|
||||
|
||||
public bool OrderClose(int ticket, double lots, double price, int slippage, Color color)
|
||||
@@ -427,7 +421,7 @@ namespace MtApi
|
||||
return response != null;
|
||||
}
|
||||
|
||||
public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration, Color arrowColor)
|
||||
public bool OrderModify(int ticket, double price, double stoploss, double takeprofit, DateTime expiration, Color arrow_color)
|
||||
{
|
||||
var response = SendRequest<ResponseBase>(new OrderModifyRequest
|
||||
{
|
||||
@@ -436,7 +430,7 @@ namespace MtApi
|
||||
Stoploss = stoploss,
|
||||
Takeprofit = takeprofit,
|
||||
Expiration = MtApiTimeConverter.ConvertToMtTime(expiration),
|
||||
ArrowColor = MtApiColorConverter.ConvertToMtColor(arrowColor)
|
||||
ArrowColor = MtApiColorConverter.ConvertToMtColor(arrow_color)
|
||||
});
|
||||
return response != null;
|
||||
}
|
||||
@@ -488,7 +482,7 @@ namespace MtApi
|
||||
public MtOrder GetOrder(int index, OrderSelectMode select, OrderSelectSource pool)
|
||||
{
|
||||
var response = SendRequest<GetOrderResponse>(new GetOrderRequest { Index = index, Select = (int) select, Pool = (int) pool});
|
||||
return response?.Order;
|
||||
return response != null ? response.Order : null;
|
||||
}
|
||||
|
||||
public List<MtOrder> GetOrders(OrderSelectSource pool)
|
||||
@@ -658,6 +652,26 @@ namespace MtApi
|
||||
|
||||
#endregion
|
||||
|
||||
#region Symbols
|
||||
public int SymbolsTotal(bool selected)
|
||||
{
|
||||
var commandParameters = new ArrayList { selected };
|
||||
return SendCommand<int>(MtCommandType.SymbolsTotal, commandParameters);
|
||||
}
|
||||
|
||||
public string SymbolName(int pos, bool selected)
|
||||
{
|
||||
var commandParameters = new ArrayList { pos, selected };
|
||||
return SendCommand<string>(MtCommandType.SymbolName, commandParameters);
|
||||
}
|
||||
|
||||
public bool SymbolSelect(string name, bool select)
|
||||
{
|
||||
var commandParameters = new ArrayList { name, select };
|
||||
return SendCommand<bool>(MtCommandType.SymbolSelect, commandParameters);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Common Function
|
||||
|
||||
public void Alert(string msg)
|
||||
@@ -718,15 +732,15 @@ namespace MtApi
|
||||
return SendCommand<bool>(MtCommandType.SendFTP, commandParameters);
|
||||
}
|
||||
|
||||
public bool SendFTP(string filename, string ftpPath)
|
||||
public bool SendFTP(string filename, string ftp_path)
|
||||
{
|
||||
var commandParameters = new ArrayList { filename, ftpPath };
|
||||
var commandParameters = new ArrayList { filename, ftp_path };
|
||||
return SendCommand<bool>(MtCommandType.SendFTPA, commandParameters);
|
||||
}
|
||||
|
||||
public void SendMail(string subject, string someText)
|
||||
public void SendMail(string subject, string some_text)
|
||||
{
|
||||
var commandParameters = new ArrayList { subject, someText };
|
||||
var commandParameters = new ArrayList { subject, some_text };
|
||||
SendCommand<object>(MtCommandType.SendMail, commandParameters);
|
||||
}
|
||||
|
||||
@@ -894,15 +908,15 @@ namespace MtApi
|
||||
return MtApiTimeConverter.ConvertFromMtTime(commandResponse);
|
||||
}
|
||||
|
||||
public bool GlobalVariableSetOnCondition(string name, double value, double checkValue)
|
||||
public bool GlobalVariableSetOnCondition(string name, double value, double check_value)
|
||||
{
|
||||
var commandParameters = new ArrayList { name, value, checkValue };
|
||||
var commandParameters = new ArrayList { name, value, check_value };
|
||||
return SendCommand<bool>(MtCommandType.GlobalVariableSetOnCondition, commandParameters);
|
||||
}
|
||||
|
||||
public int GlobalVariablesDeleteAll(string prefixName)
|
||||
public int GlobalVariablesDeleteAll(string prefix_name)
|
||||
{
|
||||
var commandParameters = new ArrayList { prefixName };
|
||||
var commandParameters = new ArrayList { prefix_name };
|
||||
return SendCommand<int>(MtCommandType.GlobalVariableSetOnCondition, commandParameters);
|
||||
}
|
||||
|
||||
@@ -926,15 +940,15 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iAD, commandParameters);
|
||||
}
|
||||
|
||||
public double iAlligator(string symbol, int timeframe, int jawPeriod, int jawShift, int teethPeriod, int teethShift, int lipsPeriod, int lipsShift, int maMethod, int appliedPrice, int mode, int shift)
|
||||
public double iAlligator(string symbol, int timeframe, int jaw_period, int jaw_shift, int teeth_period, int teeth_shift, int lips_period, int lips_shift, int ma_method, int applied_price, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, jawPeriod, jawShift, teethPeriod, teethShift, lipsPeriod, lipsShift, maMethod, appliedPrice, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, jaw_period, jaw_shift, teeth_period, teeth_shift, lips_period, lips_shift, ma_method, applied_price, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iAlligator, commandParameters);
|
||||
}
|
||||
|
||||
public double iADX(string symbol, int timeframe, int period, int appliedPrice, int mode, int shift)
|
||||
public double iADX(string symbol, int timeframe, int period, int applied_price, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, appliedPrice, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, applied_price, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iADX, commandParameters);
|
||||
}
|
||||
|
||||
@@ -950,50 +964,50 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iAO, commandParameters);
|
||||
}
|
||||
|
||||
public double iBearsPower(string symbol, int timeframe, int period, int appliedPrice, int shift)
|
||||
public double iBearsPower(string symbol, int timeframe, int period, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iBearsPower, commandParameters);
|
||||
}
|
||||
|
||||
public double iBands(string symbol, int timeframe, int period, int deviation, int bandsShift, int appliedPrice, int mode, int shift)
|
||||
public double iBands(string symbol, int timeframe, int period, int deviation, int bands_shift, int applied_price, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, deviation, bandsShift, appliedPrice, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, deviation, bands_shift, applied_price, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iBands, commandParameters);
|
||||
}
|
||||
|
||||
public double iBandsOnArray(double[] array, int total, int period, int deviation, int bandsShift, int mode, int shift)
|
||||
public double iBandsOnArray(double[] array, int total, int period, int deviation, int bands_shift, int mode, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] {});
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(period);
|
||||
commandParameters.Add(deviation);
|
||||
commandParameters.Add(bandsShift);
|
||||
commandParameters.Add(bands_shift);
|
||||
commandParameters.Add(mode);
|
||||
commandParameters.Add(shift);
|
||||
|
||||
return SendCommand<double>(MtCommandType.iBandsOnArray, commandParameters);
|
||||
}
|
||||
|
||||
public double iBullsPower(string symbol, int timeframe, int period, int appliedPrice, int shift)
|
||||
public double iBullsPower(string symbol, int timeframe, int period, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iBullsPower, commandParameters);
|
||||
}
|
||||
|
||||
public double iCCI(string symbol, int timeframe, int period, int appliedPrice, int shift)
|
||||
public double iCCI(string symbol, int timeframe, int period, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iCCI, commandParameters);
|
||||
}
|
||||
|
||||
public double iCCIOnArray(double[] array, int total, int period, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] { });
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(period);
|
||||
commandParameters.Add(shift);
|
||||
@@ -1013,7 +1027,7 @@ namespace MtApi
|
||||
Params = new ArrayList(parameters),
|
||||
ParamsType = ICustomRequest.ParametersType.Int
|
||||
});
|
||||
return response?.Value ?? double.NaN;
|
||||
return response != null ? response.Value : double.NaN;
|
||||
}
|
||||
|
||||
public double iCustom(string symbol, int timeframe, string name, double[] parameters, int mode, int shift)
|
||||
@@ -1028,7 +1042,7 @@ namespace MtApi
|
||||
Params = new ArrayList(parameters),
|
||||
ParamsType = ICustomRequest.ParametersType.Double
|
||||
});
|
||||
return response?.Value ?? double.NaN;
|
||||
return response != null ? response.Value : double.NaN;
|
||||
}
|
||||
|
||||
public double iCustom(string symbol, int timeframe, string name, int mode, int shift)
|
||||
@@ -1041,7 +1055,7 @@ namespace MtApi
|
||||
Mode = mode,
|
||||
Shift = shift
|
||||
});
|
||||
return response?.Value ?? double.NaN;
|
||||
return response != null ? response.Value : double.NaN;
|
||||
}
|
||||
|
||||
public double iDeMarker(string symbol, int timeframe, int period, int shift)
|
||||
@@ -1050,21 +1064,21 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iDeMarker, commandParameters);
|
||||
}
|
||||
|
||||
public double iEnvelopes(string symbol, int timeframe, int maPeriod, int maMethod, int maShift, int appliedPrice, double deviation, int mode, int shift)
|
||||
public double iEnvelopes(string symbol, int timeframe, int ma_period, int ma_method, int ma_shift, int applied_price, double deviation, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, maPeriod, maMethod, maShift, appliedPrice, deviation, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, ma_period, ma_method, ma_shift, applied_price, deviation, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iEnvelopes, commandParameters);
|
||||
}
|
||||
|
||||
public double iEnvelopesOnArray(double[] array, int total, int maPeriod, int maMethod, int maShift, double deviation, int mode, int shift)
|
||||
public double iEnvelopesOnArray(double[] array, int total, int ma_period, int ma_method, int ma_shift, double deviation, int mode, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] {});
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(maPeriod);
|
||||
commandParameters.Add(maMethod);
|
||||
commandParameters.Add(maShift);
|
||||
commandParameters.Add(ma_period);
|
||||
commandParameters.Add(ma_method);
|
||||
commandParameters.Add(ma_shift);
|
||||
commandParameters.Add(deviation);
|
||||
commandParameters.Add(mode);
|
||||
commandParameters.Add(shift);
|
||||
@@ -1072,9 +1086,9 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iEnvelopesOnArray, commandParameters);
|
||||
}
|
||||
|
||||
public double iForce(string symbol, int timeframe, int period, int maMethod, int appliedPrice, int shift)
|
||||
public double iForce(string symbol, int timeframe, int period, int ma_method, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, maMethod, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, ma_method, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iForce, commandParameters);
|
||||
}
|
||||
|
||||
@@ -1084,15 +1098,15 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iFractals, commandParameters);
|
||||
}
|
||||
|
||||
public double iGator(string symbol, int timeframe, int jawPeriod, int jawShift, int teethPeriod, int teethShift, int lipsPeriod, int lipsShift, int maMethod, int appliedPrice, int mode, int shift)
|
||||
public double iGator(string symbol, int timeframe, int jaw_period, int jaw_shift, int teeth_period, int teeth_shift, int lips_period, int lips_shift, int ma_method, int applied_price, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, jawPeriod, jawShift, teethPeriod, teethShift, lipsPeriod, lipsShift, maMethod, appliedPrice, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, jaw_period, jaw_shift, teeth_period, teeth_shift, lips_period, lips_shift, ma_method, applied_price, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iGator, commandParameters);
|
||||
}
|
||||
|
||||
public double iIchimoku(string symbol, int timeframe, int tenkanSen, int kijunSen, int senkouSpanB, int mode, int shift)
|
||||
public double iIchimoku(string symbol, int timeframe, int tenkan_sen, int kijun_sen, int senkou_span_b, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, tenkanSen, kijunSen, senkouSpanB, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, tenkan_sen, kijun_sen, senkou_span_b, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iIchimoku, commandParameters);
|
||||
}
|
||||
|
||||
@@ -1102,17 +1116,17 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iBWMFI, commandParameters);
|
||||
}
|
||||
|
||||
public double iMomentum(string symbol, int timeframe, int period, int appliedPrice, int shift)
|
||||
public double iMomentum(string symbol, int timeframe, int period, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iMomentum, commandParameters);
|
||||
}
|
||||
|
||||
public double iMomentumOnArray(double[] array, int total, int period, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] {});
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(period);
|
||||
commandParameters.Add(shift);
|
||||
@@ -1126,41 +1140,41 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iMFI, commandParameters);
|
||||
}
|
||||
|
||||
public double iMA(string symbol, int timeframe, int period, int maShift, int maMethod, int appliedPrice, int shift)
|
||||
public double iMA(string symbol, int timeframe, int period, int ma_shift, int ma_method, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, maShift, maMethod, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, ma_shift, ma_method, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iMA, commandParameters);
|
||||
}
|
||||
|
||||
public double iMAOnArray(double[] array, int total, int period, int maShift, int maMethod, int shift)
|
||||
double iMAOnArray(double[] array, int total, int period, int ma_shift, int ma_method, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] {});
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(period);
|
||||
commandParameters.Add(maShift);
|
||||
commandParameters.Add(maMethod);
|
||||
commandParameters.Add(ma_shift);
|
||||
commandParameters.Add(ma_method);
|
||||
commandParameters.Add(shift);
|
||||
|
||||
return SendCommand<double>(MtCommandType.iMAOnArray, commandParameters);
|
||||
}
|
||||
|
||||
public double iOsMA(string symbol, int timeframe, int fastEmaPeriod, int slowEmaPeriod, int signalPeriod, int appliedPrice, int shift)
|
||||
public double iOsMA(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, fastEmaPeriod, slowEmaPeriod, signalPeriod, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iOsMA, commandParameters);
|
||||
}
|
||||
|
||||
public double iMACD(string symbol, int timeframe, int fastEmaPeriod, int slowEmaPeriod, int signalPeriod, int appliedPrice, int mode, int shift)
|
||||
public double iMACD(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, fastEmaPeriod, slowEmaPeriod, signalPeriod, appliedPrice, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iMACD, commandParameters);
|
||||
}
|
||||
|
||||
public double iOBV(string symbol, int timeframe, int appliedPrice, int shift)
|
||||
public double iOBV(string symbol, int timeframe, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iOBV, commandParameters);
|
||||
}
|
||||
|
||||
@@ -1170,17 +1184,17 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iSAR, commandParameters);
|
||||
}
|
||||
|
||||
public double iRSI( string symbol, int timeframe, int period, int appliedPrice, int shift)
|
||||
public double iRSI( string symbol, int timeframe, int period, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, period, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iRSI, commandParameters);
|
||||
}
|
||||
|
||||
public double iRSIOnArray(double[] array, int total, int period, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] {});
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(period);
|
||||
commandParameters.Add(shift);
|
||||
@@ -1194,29 +1208,29 @@ namespace MtApi
|
||||
return SendCommand<double>(MtCommandType.iRVI, commandParameters);
|
||||
}
|
||||
|
||||
public double iStdDev(string symbol, int timeframe, int maPeriod, int maShift, int maMethod, int appliedPrice, int shift)
|
||||
public double iStdDev(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, maPeriod, maShift, maMethod, appliedPrice, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift };
|
||||
return SendCommand<double>(MtCommandType.iStdDev, commandParameters);
|
||||
}
|
||||
|
||||
public double iStdDevOnArray(double[] array, int total, int maPeriod, int maShift, int maMethod, int shift)
|
||||
public double iStdDevOnArray(double[] array, int total, int ma_period, int ma_shift, int ma_method, int shift)
|
||||
{
|
||||
var arraySize = array?.Length ?? 0;
|
||||
int arraySize = array != null ? array.Length : 0;
|
||||
var commandParameters = new ArrayList { arraySize };
|
||||
commandParameters.AddRange(array ?? new double[] {});
|
||||
commandParameters.AddRange(array);
|
||||
commandParameters.Add(total);
|
||||
commandParameters.Add(maPeriod);
|
||||
commandParameters.Add(maShift);
|
||||
commandParameters.Add(maMethod);
|
||||
commandParameters.Add(ma_period);
|
||||
commandParameters.Add(ma_shift);
|
||||
commandParameters.Add(ma_method);
|
||||
commandParameters.Add(shift);
|
||||
|
||||
return SendCommand<double>(MtCommandType.iStdDevOnArray, commandParameters);
|
||||
}
|
||||
|
||||
public double iStochastic(string symbol, int timeframe, int pKperiod, int pDperiod, int slowing, int method, int priceField, int mode, int shift)
|
||||
public double iStochastic(string symbol, int timeframe, int pKperiod, int pDperiod, int slowing, int method, int price_field, int mode, int shift)
|
||||
{
|
||||
var commandParameters = new ArrayList { symbol, timeframe, pKperiod, pDperiod, slowing, method, priceField, mode, shift };
|
||||
var commandParameters = new ArrayList { symbol, timeframe, pKperiod, pDperiod, slowing, method, price_field, mode, shift };
|
||||
return SendCommand<double>(MtCommandType.iStochastic, commandParameters);
|
||||
}
|
||||
|
||||
@@ -1359,7 +1373,7 @@ namespace MtApi
|
||||
{
|
||||
result = new DateTime[response.Length];
|
||||
|
||||
for(var i = 0; i < response.Length; i++)
|
||||
for(int i = 0; i < response.Length; i++)
|
||||
{
|
||||
result[i] = MtApiTimeConverter.ConvertFromMtTime(response[i]);
|
||||
}
|
||||
@@ -1373,54 +1387,59 @@ namespace MtApi
|
||||
return SendCommand<bool>(MtCommandType.RefreshRates, null);
|
||||
}
|
||||
|
||||
public List<MqlRates> CopyRates(string symbolName, ENUM_TIMEFRAMES timeframe, int startPos, int count)
|
||||
public List<MqlRates> CopyRates(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count)
|
||||
{
|
||||
var response = SendRequest<CopyRatesResponse>(new CopyRates1Request
|
||||
{
|
||||
SymbolName = symbolName,
|
||||
SymbolName = symbol_name,
|
||||
Timeframe = timeframe,
|
||||
StartPos = startPos,
|
||||
StartPos = start_pos,
|
||||
Count = count
|
||||
});
|
||||
return response?.Rates;
|
||||
return response != null ? response.Rates : null;
|
||||
}
|
||||
|
||||
public List<MqlRates> CopyRates(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, int count)
|
||||
public List<MqlRates> CopyRates(string symbol_name, ENUM_TIMEFRAMES timeframe, DateTime start_time, int count)
|
||||
{
|
||||
var response = SendRequest<CopyRatesResponse>(new CopyRates2Request
|
||||
{
|
||||
SymbolName = symbolName,
|
||||
SymbolName = symbol_name,
|
||||
Timeframe = timeframe,
|
||||
StartTime = MtApiTimeConverter.ConvertToMtTime(startTime),
|
||||
StartTime = MtApiTimeConverter.ConvertToMtTime(start_time),
|
||||
Count = count
|
||||
});
|
||||
return response?.Rates;
|
||||
return response != null ? response.Rates : null;
|
||||
}
|
||||
|
||||
public List<MqlRates> CopyRates(string symbolName, ENUM_TIMEFRAMES timeframe, DateTime startTime, DateTime stopTime)
|
||||
public List<MqlRates> CopyRates(string symbol_name, ENUM_TIMEFRAMES timeframe, DateTime start_time, DateTime stop_time)
|
||||
{
|
||||
var response = SendRequest<CopyRatesResponse>(new CopyRates3Request
|
||||
{
|
||||
SymbolName = symbolName,
|
||||
SymbolName = symbol_name,
|
||||
Timeframe = timeframe,
|
||||
StartTime = MtApiTimeConverter.ConvertToMtTime(startTime),
|
||||
StopTime = MtApiTimeConverter.ConvertToMtTime(stopTime)
|
||||
StartTime = MtApiTimeConverter.ConvertToMtTime(start_time),
|
||||
StopTime = MtApiTimeConverter.ConvertToMtTime(stop_time)
|
||||
});
|
||||
return response?.Rates;
|
||||
return response != null ? response.Rates : null;
|
||||
}
|
||||
|
||||
private void BaBacktestingReady()
|
||||
{
|
||||
SendCommand<object>(MtCommandType.BacktestingReady, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Checkup
|
||||
public string TerminalInfoString(ENUM_TERMINAL_INFO_STRING propertyId)
|
||||
public string TerminalInfoString(ENUM_TERMINAL_INFO_STRING property_id)
|
||||
{
|
||||
var commandParameters = new ArrayList { (int)propertyId };
|
||||
var commandParameters = new ArrayList { (int)property_id };
|
||||
return SendCommand<string>(MtCommandType.TerminalInfoString, commandParameters);
|
||||
}
|
||||
|
||||
public string SymbolInfoString(string name, ENUM_SYMBOL_INFO_STRING propId)
|
||||
public string SymbolInfoString(string name, ENUM_SYMBOL_INFO_STRING prop_id)
|
||||
{
|
||||
var commandParameters = new ArrayList { name, (int)propId };
|
||||
var commandParameters = new ArrayList { name, (int)prop_id };
|
||||
return SendCommand<string>(MtCommandType.SymbolInfoString, commandParameters); ;
|
||||
}
|
||||
#endregion
|
||||
@@ -1428,60 +1447,51 @@ namespace MtApi
|
||||
#region Private Methods
|
||||
private void Connect(string host, int port)
|
||||
{
|
||||
UpdateConnectionState(MtConnectionState.Connecting, $"Connecting to {host}:{port}");
|
||||
UpdateConnectionState(MtConnectionState.Connecting, string.Format("Connecting to {0}:{1}", host, port));
|
||||
try
|
||||
{
|
||||
lock (_client)
|
||||
{
|
||||
_client.Open(host, port);
|
||||
_client.Connect();
|
||||
}
|
||||
_client.Open(host, port);
|
||||
_client.Connect();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UpdateConnectionState(MtConnectionState.Failed, $"Failed connection to {host}:{port}. {e.Message}");
|
||||
UpdateConnectionState(MtConnectionState.Failed, string.Format("Failed connection to {0}:{1}. {2}", host, port, e.Message));
|
||||
return;
|
||||
}
|
||||
UpdateConnectionState(MtConnectionState.Connected, $"Connected to {host}:{port}");
|
||||
UpdateConnectionState(MtConnectionState.Connected, string.Format("Connected to {0}:{1}", host, port));
|
||||
OnConnected();
|
||||
}
|
||||
|
||||
private void Connect(int port)
|
||||
{
|
||||
UpdateConnectionState(MtConnectionState.Connecting, $"Connecting to 'localhost':{port}");
|
||||
UpdateConnectionState(MtConnectionState.Connecting, string.Format("Connecting to 'localhost':{0}", port));
|
||||
try
|
||||
{
|
||||
lock (_client)
|
||||
{
|
||||
_client.Open(port);
|
||||
_client.Connect();
|
||||
}
|
||||
_client.Open(port);
|
||||
_client.Connect();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UpdateConnectionState(MtConnectionState.Failed, $"Failed connection to 'localhost':{port}. {e.Message}");
|
||||
UpdateConnectionState(MtConnectionState.Failed, string.Format("Failed connection to 'localhost':{0}. {1}", port, e.Message));
|
||||
return;
|
||||
}
|
||||
UpdateConnectionState(MtConnectionState.Connected, $"Connected to 'localhost':{port}");
|
||||
UpdateConnectionState(MtConnectionState.Connected, string.Format("Connected to 'localhost':{0}", port));
|
||||
OnConnected();
|
||||
}
|
||||
|
||||
private void OnConnected()
|
||||
{
|
||||
_isBacktestingMode = IsTesting();
|
||||
if (_isBacktestingMode)
|
||||
{
|
||||
BacktestingReady();
|
||||
IsBacktestingMode = IsTesting();
|
||||
if (IsBacktestingMode)
|
||||
{
|
||||
BaBacktestingReady();
|
||||
}
|
||||
}
|
||||
|
||||
private void Disconnect()
|
||||
{
|
||||
lock (_client)
|
||||
{
|
||||
_client.Disconnect();
|
||||
_client.Close();
|
||||
}
|
||||
_client.Disconnect();
|
||||
_client.Close();
|
||||
|
||||
UpdateConnectionState(MtConnectionState.Disconnected, "Disconnected");
|
||||
}
|
||||
@@ -1509,18 +1519,37 @@ namespace MtApi
|
||||
MtResponse response;
|
||||
try
|
||||
{
|
||||
lock (_client)
|
||||
{
|
||||
response = _client.SendCommand((int)commandType, commandParameters);
|
||||
}
|
||||
response = _client.SendCommand((int)commandType, commandParameters);
|
||||
}
|
||||
catch (CommunicationException ex)
|
||||
{
|
||||
throw new MtConnectionException(ex.Message, ex);
|
||||
}
|
||||
|
||||
var responseValue = response.GetValue();
|
||||
return responseValue != null ? (T)responseValue : default(T);
|
||||
T result = default(T);
|
||||
|
||||
if (response is MtResponseDouble)
|
||||
result = (T)Convert.ChangeType(((MtResponseDouble)response).Value, typeof(T));
|
||||
|
||||
if (response is MtResponseInt)
|
||||
result = (T)Convert.ChangeType(((MtResponseInt)response).Value, typeof(T));
|
||||
|
||||
if (response is MtResponseBool)
|
||||
result = (T)Convert.ChangeType(((MtResponseBool)response).Value, typeof(T));
|
||||
|
||||
if (response is MtResponseString)
|
||||
result = (T)Convert.ChangeType(((MtResponseString)response).Value, typeof(T));
|
||||
|
||||
if (response is MtResponseDoubleArray)
|
||||
result = (T)Convert.ChangeType(((MtResponseDoubleArray)response).Value, typeof(T));
|
||||
|
||||
if (response is MtResponseIntArray)
|
||||
result = (T)Convert.ChangeType(((MtResponseIntArray)response).Value, typeof(T));
|
||||
|
||||
if (response is MtResponseArrayList)
|
||||
result = (T)Convert.ChangeType(((MtResponseArrayList)response).Value, typeof(T));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private T SendRequest<T>(RequestBase request) where T : ResponseBase, new()
|
||||
@@ -1528,20 +1557,17 @@ namespace MtApi
|
||||
if (request == null)
|
||||
return default(T);
|
||||
|
||||
var serializer = JsonConvert.SerializeObject(request, Formatting.None,
|
||||
var serializer = JsonConvert.SerializeObject(request, Newtonsoft.Json.Formatting.None,
|
||||
new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
});
|
||||
});
|
||||
var commandParameters = new ArrayList { serializer };
|
||||
|
||||
MtResponseString res;
|
||||
try
|
||||
{
|
||||
lock (_client)
|
||||
{
|
||||
res = (MtResponseString)_client.SendCommand((int)MtCommandType.MtRequest, commandParameters);
|
||||
}
|
||||
res = (MtResponseString)_client.SendCommand((int)MtCommandType.MtRequest, commandParameters);
|
||||
}
|
||||
catch (CommunicationException ex)
|
||||
{
|
||||
@@ -1562,44 +1588,44 @@ namespace MtApi
|
||||
return response;
|
||||
}
|
||||
|
||||
private void _client_QuoteUpdated(MTApiService.MtQuote quote)
|
||||
private void mClient_QuoteUpdated(MTApiService.MtQuote quote)
|
||||
{
|
||||
if (quote != null)
|
||||
{
|
||||
if (_isBacktestingMode)
|
||||
if (IsBacktestingMode)
|
||||
{
|
||||
QuoteUpdated?.Invoke(this, quote.Instrument, quote.Bid, quote.Ask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QuoteUpdated.FireEventAsync(this, quote.Instrument, quote.Bid, quote.Ask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _client_ServerDisconnected(object sender, EventArgs e)
|
||||
private void mClient_ServerDisconnected(object sender, EventArgs e)
|
||||
{
|
||||
UpdateConnectionState(MtConnectionState.Disconnected, "MtApi is disconnected");
|
||||
}
|
||||
|
||||
private void _client_ServerFailed(object sender, EventArgs e)
|
||||
private void mClient_ServerFailed(object sender, EventArgs e)
|
||||
{
|
||||
UpdateConnectionState(MtConnectionState.Failed, "Failed connection with MtApi");
|
||||
}
|
||||
|
||||
private void _client_QuoteRemoved(MTApiService.MtQuote quote)
|
||||
private void mClient_QuoteRemoved(MTApiService.MtQuote quote)
|
||||
{
|
||||
QuoteRemoved.FireEventAsync(this, new MtQuoteEventArgs(quote.Convert()));
|
||||
}
|
||||
|
||||
private void _client_QuoteAdded(MTApiService.MtQuote quote)
|
||||
private void mClient_QuoteAdded(MTApiService.MtQuote quote)
|
||||
{
|
||||
QuoteAdded.FireEventAsync(this, new MtQuoteEventArgs(quote.Convert()));
|
||||
}
|
||||
|
||||
private void _client_MtEventReceived(object sender, MtEventArgs e)
|
||||
{
|
||||
var eventType = (MtEventTypes) e.Event.EventType;
|
||||
MtEventTypes eventType = (MtEventTypes) e.Event.EventType;
|
||||
|
||||
switch(eventType)
|
||||
{
|
||||
@@ -1608,8 +1634,6 @@ namespace MtApi
|
||||
FireOnLastTimeBar(JsonConvert.DeserializeObject<MtTimeBar>(e.Event.Payload));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1618,21 +1642,20 @@ namespace MtApi
|
||||
OnLastTimeBar.FireEventAsync(this, new TimeBarArgs(timeBar));
|
||||
}
|
||||
|
||||
private void BacktestingReady()
|
||||
{
|
||||
SendCommand<object>(MtCommandType.BacktestingReady, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public event MtApiQuoteHandler QuoteUpdated;
|
||||
public event EventHandler<MtQuoteEventArgs> QuoteAdded;
|
||||
public event EventHandler<MtQuoteEventArgs> QuoteRemoved;
|
||||
public event EventHandler<MtConnectionEventArgs> ConnectionStateChanged;
|
||||
public event EventHandler<TimeBarArgs> OnLastTimeBar;
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private readonly MtClient _client = new MtClient();
|
||||
private readonly object _locker = new object();
|
||||
private MtConnectionState _connectionState = MtConnectionState.Disconnected;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +195,11 @@ namespace MtApi
|
||||
MtRequest = 155,
|
||||
|
||||
//Backtesting
|
||||
BacktestingReady = 156
|
||||
BacktestingReady = 156,
|
||||
|
||||
//Symbols
|
||||
SymbolsTotal = 200,
|
||||
SymbolName = 201,
|
||||
SymbolSelect = 202
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MtApi5
|
||||
{
|
||||
internal static class ExtensionMethods
|
||||
static class ExtensionMethods
|
||||
{
|
||||
#region Event Methods
|
||||
public static void FireEvent(this EventHandler eventHandler, object sender)
|
||||
{
|
||||
eventHandler?.Invoke(sender, EventArgs.Empty);
|
||||
if (eventHandler != null)
|
||||
{
|
||||
eventHandler(sender, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public static void FireEvent<T>(this EventHandler<T> eventHandler, object sender, T e)
|
||||
where T : EventArgs
|
||||
{
|
||||
eventHandler?.Invoke(sender, e);
|
||||
if (eventHandler != null)
|
||||
{
|
||||
eventHandler(sender, e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
+11
-12
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MtApi5
|
||||
{
|
||||
@@ -16,17 +19,13 @@ namespace MtApi5
|
||||
this.real_volume = real_volume;
|
||||
}
|
||||
|
||||
public MqlRates()
|
||||
{
|
||||
}
|
||||
|
||||
public DateTime time { get; set; } // Period start time
|
||||
public double open { get; set; } // Open price
|
||||
public double high { get; set; } // The highest price of the period
|
||||
public double low { get; set; } // The lowest price of the period
|
||||
public double close { get; set; } // Close price
|
||||
public long tick_volume { get; set; } // Tick volume
|
||||
public int spread { get; set; } // Spread
|
||||
public long real_volume { get; set; } // Trade volume
|
||||
public DateTime time { get; private set; } // Period start time
|
||||
public double open { get; private set; } // Open price
|
||||
public double high { get; private set; } // The highest price of the period
|
||||
public double low { get; private set; } // The lowest price of the period
|
||||
public double close { get; private set; } // Close price
|
||||
public long tick_volume { get; private set; } // Tick volume
|
||||
public int spread { get; private set; } // Spread
|
||||
public long real_volume { get; private set; } // Trade volume
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MtApi5
|
||||
{
|
||||
@@ -6,7 +8,7 @@ namespace MtApi5
|
||||
{
|
||||
public ENUM_TRADE_REQUEST_ACTIONS Action { get; set; } // Trade operation type
|
||||
public uint Magic { get; set; } // Expert Advisor ID (magic number)
|
||||
public ulong Order { get; set; } // Order ticket
|
||||
public uint Order { get; set; } // Order ticket
|
||||
public string Symbol { get; set; } // Trade symbol
|
||||
public double Volume { get; set; } // Requested volume for a deal in lots
|
||||
public double Price { get; set; } // Price
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration.Install" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -56,7 +55,7 @@
|
||||
<Compile Include="MqlTradeResult.cs" />
|
||||
<Compile Include="Mt5QuoteEventArgs.cs" />
|
||||
<Compile Include="MtApi5Client.cs" />
|
||||
<Compile Include="Mt5CommandType.cs" />
|
||||
<Compile Include="MtCommandType.cs" />
|
||||
<Compile Include="MtConverters.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Mt5Quote.cs" />
|
||||
|
||||
+493
-533
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ using System.Text;
|
||||
|
||||
namespace MtApi5
|
||||
{
|
||||
internal enum Mt5CommandType
|
||||
enum Mt5CommandType
|
||||
{
|
||||
//NoCommand = 0
|
||||
|
||||
@@ -101,15 +101,6 @@ namespace MtApi5
|
||||
MarketBookRelease = 61,
|
||||
MarketBookGet = 62,
|
||||
OrderCloseAll = 63,
|
||||
|
||||
//CTrade
|
||||
PositionClose = 64,
|
||||
PositionOpen = 65,
|
||||
|
||||
//Backtesting
|
||||
BacktestingReady = 66,
|
||||
IsTesting = 67,
|
||||
|
||||
Print = 68
|
||||
PositionClose = 64
|
||||
}
|
||||
}
|
||||
+33
-30
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MTApiService;
|
||||
using System.Collections;
|
||||
|
||||
namespace MtApi5
|
||||
{
|
||||
internal static class MtConverters
|
||||
static class MtConverters
|
||||
{
|
||||
#region Values Converters
|
||||
public static Mt5Quote Parse(this MtQuote quote)
|
||||
@@ -14,29 +17,29 @@ namespace MtApi5
|
||||
|
||||
public static bool ParseResult(this string inputString, char separator, out MqlTradeResult result)
|
||||
{
|
||||
var retVal = false;
|
||||
bool retVal = false;
|
||||
result = null;
|
||||
|
||||
if (string.IsNullOrEmpty(inputString) == false)
|
||||
{
|
||||
var values = inputString.Split(separator);
|
||||
string[] values = inputString.Split(separator);
|
||||
if (values.Length == 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
retVal = int.Parse(values[0]) != 0;
|
||||
|
||||
var retcode = uint.Parse(values[1]);
|
||||
var deal = ulong.Parse(values[2]);
|
||||
var order = ulong.Parse(values[3]);
|
||||
var volume = double.Parse(values[4]);
|
||||
var price = double.Parse(values[5]);
|
||||
var bid = double.Parse(values[6]);
|
||||
var ask = double.Parse(values[7]);
|
||||
var comment = values[8];
|
||||
var requestId = uint.Parse(values[9]);
|
||||
uint retcode = uint.Parse(values[1]);
|
||||
ulong deal = ulong.Parse(values[2]);
|
||||
ulong order = ulong.Parse(values[3]);
|
||||
double volume = double.Parse(values[4]);
|
||||
double price = double.Parse(values[5]);
|
||||
double bid = double.Parse(values[6]);
|
||||
double ask = double.Parse(values[7]);
|
||||
string comment = values[8];
|
||||
uint request_id = uint.Parse(values[9]);
|
||||
|
||||
result = new MqlTradeResult(retcode, deal, order, volume, price, bid, ask, comment, requestId);
|
||||
result = new MqlTradeResult(retcode, deal, order, volume, price, bid, ask, comment, request_id);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -49,28 +52,28 @@ namespace MtApi5
|
||||
|
||||
public static bool ParseResult(this string inputString, char separator, out MqlTradeCheckResult result)
|
||||
{
|
||||
var retVal = false;
|
||||
bool retVal = false;
|
||||
result = null;
|
||||
|
||||
if (string.IsNullOrEmpty(inputString) == false)
|
||||
{
|
||||
var values = inputString.Split(separator);
|
||||
string[] values = inputString.Split(separator);
|
||||
if (values.Length == 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
retVal = int.Parse(values[0]) != 0;
|
||||
|
||||
var retcode = uint.Parse(values[1]);
|
||||
var balance = double.Parse(values[2]);
|
||||
var equity = double.Parse(values[3]);
|
||||
var profit = double.Parse(values[4]);
|
||||
var margin = double.Parse(values[5]);
|
||||
var marginFree = double.Parse(values[6]);
|
||||
var marginLevel = double.Parse(values[7]);
|
||||
var comment = values[8];
|
||||
uint retcode = uint.Parse(values[1]);
|
||||
double balance = double.Parse(values[2]);
|
||||
double equity = double.Parse(values[3]);
|
||||
double profit = double.Parse(values[4]);
|
||||
double margin = double.Parse(values[5]);
|
||||
double margin_free = double.Parse(values[6]);
|
||||
double margin_level = double.Parse(values[7]);
|
||||
string comment = values[8];
|
||||
|
||||
result = new MqlTradeCheckResult(retcode, balance, equity, profit, margin, marginFree, marginLevel, comment);
|
||||
result = new MqlTradeCheckResult(retcode, balance, equity, profit, margin, margin_free, margin_level, comment);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -84,7 +87,7 @@ namespace MtApi5
|
||||
|
||||
public static bool ParseResult(this string inputString, char separator, out double result)
|
||||
{
|
||||
var retVal = false;
|
||||
bool retVal = false;
|
||||
result = 0;
|
||||
|
||||
if (string.IsNullOrEmpty(inputString) == false)
|
||||
@@ -110,24 +113,24 @@ namespace MtApi5
|
||||
|
||||
public static bool ParseResult(this string inputString, char separator, out DateTime from, out DateTime to)
|
||||
{
|
||||
var retVal = false;
|
||||
bool retVal = false;
|
||||
|
||||
from = new DateTime();
|
||||
to = new DateTime();
|
||||
|
||||
if (string.IsNullOrEmpty(inputString) == false)
|
||||
{
|
||||
var values = inputString.Split(separator);
|
||||
string[] values = inputString.Split(separator);
|
||||
if (values.Length == 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
retVal = int.Parse(values[0]) != 0;
|
||||
|
||||
var iFrom = int.Parse(values[1]);
|
||||
int iFrom = int.Parse(values[1]);
|
||||
from = Mt5TimeConverter.ConvertFromMtTime(iFrom);
|
||||
|
||||
var iTo= int.Parse(values[2]);
|
||||
int iTo= int.Parse(values[2]);
|
||||
to = Mt5TimeConverter.ConvertFromMtTime(iTo);
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -145,7 +148,7 @@ namespace MtApi5
|
||||
if (request == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
var exp = Mt5TimeConverter.ConvertToMtTime(request.Expiration);
|
||||
int exp = Mt5TimeConverter.ConvertToMtTime(request.Expiration);
|
||||
|
||||
return new ArrayList { (int)request.Action, request.Magic, request.Order, request.Symbol, request.Volume
|
||||
, request.Price, request.Stoplimit, request.Sl, request.Tp, request.Deviation, (int)request.Type
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.10.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.10.0")]
|
||||
[assembly: AssemblyVersion("1.0.9.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.9.0")]
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<?define PlatformSystemFolder = "SystemFolder" ?>
|
||||
<?endif ?>
|
||||
|
||||
<?define ProductVersion="1.0.10" ?>
|
||||
<?define ProductVersion="1.0.9" ?>
|
||||
<?define Manufacturer="DW"?>
|
||||
<?define ProductPath="..\build\products\$(var.Configuration)\"?>
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@ MTApiService library should be placed in Windows GAC (Global Assembly Cache). In
|
||||
|
||||
# How to build solution
|
||||
The project is supported by Visual Studio 2015.
|
||||
It also requires WIX Tools (http://wixtoolset.org/).
|
||||
|
||||
To make api for MetaTrader4 use MtApiInstaller and for MetaTrader5 use MtApi5Installer.
|
||||
To build solution you need to update sign key file in MtApiService project:
|
||||
- open properties of MTApiService project;
|
||||
- go to tab Signing and select item MtApiKey.pfx;
|
||||
- input password "MtApiService".
|
||||
To make api for MetaTrader4 use MtApiInstaller and for MetaTrader5 use MtApi5Installer.
|
||||
All installers will be placed in folder "[root]\build\installers\" and all *.dll files will be placed in "[root]\build\products\".
|
||||
MQL files have been build to ex4 and stored into folders "mq4" for MetaTrader and "mq5" for MetaTrader5. They are ready to using in terminals.
|
||||
If you change source code of MQL expert you have to recompile it with MetaEditor. In this case you need to copy files "hash.mqh" and "json.mqh" to MetaEditor include folder.
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace MtApi5TestClient
|
||||
{
|
||||
internal class ListBoxBehavior
|
||||
{
|
||||
static readonly Dictionary<ListBox, Capture> Associations =
|
||||
new Dictionary<ListBox, Capture>();
|
||||
|
||||
public static bool GetScrollOnNewItem(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(ScrollOnNewItemProperty);
|
||||
}
|
||||
|
||||
public static void SetScrollOnNewItem(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(ScrollOnNewItemProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ScrollOnNewItemProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"ScrollOnNewItem",
|
||||
typeof(bool),
|
||||
typeof(ListBoxBehavior),
|
||||
new UIPropertyMetadata(false, OnScrollOnNewItemChanged));
|
||||
|
||||
public static void OnScrollOnNewItemChanged(
|
||||
DependencyObject d,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var listBox = d as ListBox;
|
||||
if (listBox == null) return;
|
||||
bool oldValue = (bool)e.OldValue, newValue = (bool)e.NewValue;
|
||||
if (newValue == oldValue) return;
|
||||
if (newValue)
|
||||
{
|
||||
listBox.Loaded += ListBox_Loaded;
|
||||
listBox.Unloaded += ListBox_Unloaded;
|
||||
var itemsSourcePropertyDescriptor = TypeDescriptor.GetProperties(listBox)["ItemsSource"];
|
||||
itemsSourcePropertyDescriptor.AddValueChanged(listBox, ListBox_ItemsSourceChanged);
|
||||
}
|
||||
else
|
||||
{
|
||||
listBox.Loaded -= ListBox_Loaded;
|
||||
listBox.Unloaded -= ListBox_Unloaded;
|
||||
if (Associations.ContainsKey(listBox))
|
||||
Associations[listBox].Dispose();
|
||||
var itemsSourcePropertyDescriptor = TypeDescriptor.GetProperties(listBox)["ItemsSource"];
|
||||
itemsSourcePropertyDescriptor.RemoveValueChanged(listBox, ListBox_ItemsSourceChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ListBox_ItemsSourceChanged(object sender, EventArgs e)
|
||||
{
|
||||
var listBox = (ListBox)sender;
|
||||
if (Associations.ContainsKey(listBox))
|
||||
Associations[listBox].Dispose();
|
||||
Associations[listBox] = new Capture(listBox);
|
||||
}
|
||||
|
||||
static void ListBox_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var listBox = (ListBox)sender;
|
||||
if (Associations.ContainsKey(listBox))
|
||||
Associations[listBox].Dispose();
|
||||
listBox.Unloaded -= ListBox_Unloaded;
|
||||
}
|
||||
|
||||
static void ListBox_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var listBox = (ListBox)sender;
|
||||
var incc = listBox.Items as INotifyCollectionChanged;
|
||||
if (incc == null) return;
|
||||
listBox.Loaded -= ListBox_Loaded;
|
||||
Associations[listBox] = new Capture(listBox);
|
||||
}
|
||||
|
||||
class Capture : IDisposable
|
||||
{
|
||||
private readonly ListBox listBox;
|
||||
private readonly INotifyCollectionChanged incc;
|
||||
|
||||
public Capture(ListBox listBox)
|
||||
{
|
||||
this.listBox = listBox;
|
||||
incc = listBox.ItemsSource as INotifyCollectionChanged;
|
||||
if (incc != null)
|
||||
{
|
||||
incc.CollectionChanged += incc_CollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
void incc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
listBox.ScrollIntoView(e.NewItems[0]);
|
||||
listBox.SelectedItem = e.NewItems[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (incc != null)
|
||||
incc.CollectionChanged -= incc_CollectionChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Executable → Regular
+15
-38
@@ -3,7 +3,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mtapi5="clr-namespace:MtApi5;assembly=MtApi5"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:mtApi5TestClient="clr-namespace:MtApi5TestClient"
|
||||
Title="MainWindow" Height="700" Width="650"
|
||||
Closing="Window_Closing">
|
||||
<Window.Resources>
|
||||
@@ -263,52 +262,36 @@
|
||||
</TabItem>
|
||||
<TabItem Header="Account Information">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.4*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="0.4*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ComboBox Grid.Column="0" Grid.Row="0"
|
||||
<ComboBox Grid.Column="0" Grid.Row="0"
|
||||
SelectedItem="{Binding AccountInfoDoublePropertyId}"
|
||||
ItemsSource="{Binding Source={StaticResource ENUM_ACCOUNT_INFO_DOUBLE_Key}}"/>
|
||||
<Button Grid.Column="1" Grid.Row="0" Margin="10,0,0,0"
|
||||
<Button Grid.Column="1" Grid.Row="0" Margin="10,0,0,0"
|
||||
Command="{Binding AccountInfoDoubleCommand}"
|
||||
Content="AccountInfoDouble" HorizontalAlignment="Left" />
|
||||
|
||||
<ComboBox Grid.Column="0" Grid.Row="1"
|
||||
<ComboBox Grid.Column="0" Grid.Row="1"
|
||||
SelectedItem="{Binding AccountInfoIntegerPropertyId}"
|
||||
ItemsSource="{Binding Source={StaticResource ENUM_ACCOUNT_INFO_INTEGER_Key}}"/>
|
||||
<Button Grid.Column="1" Grid.Row="1" Margin="10,0,0,0"
|
||||
<Button Grid.Column="1" Grid.Row="1" Margin="10,0,0,0"
|
||||
Command="{Binding AccountInfoIntegerCommand}"
|
||||
Content="AccountInfoInteger" HorizontalAlignment="Left" />
|
||||
|
||||
<ComboBox Grid.Column="0" Grid.Row="2"
|
||||
<ComboBox Grid.Column="0" Grid.Row="2"
|
||||
SelectedItem="{Binding AccountInfoStringPropertyId}"
|
||||
ItemsSource="{Binding Source={StaticResource ENUM_ACCOUNT_INFO_STRING_Key}}"/>
|
||||
<Button Grid.Column="1" Grid.Row="2" Margin="10,0,0,0"
|
||||
<Button Grid.Column="1" Grid.Row="2" Margin="10,0,0,0"
|
||||
Command="{Binding AccountInfoStringCommand}"
|
||||
Content="AccountInfoString" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid Margin="10" Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Grid.Column="0" Text="{Binding MessageText}" Margin="5"/>
|
||||
<Button Grid.Column="1" Content="Print" Command="{Binding PrintCommand}" Margin="5"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
@@ -333,9 +316,9 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Grid.Row="0" Text="symbolName"/>
|
||||
<TextBox Grid.Row="0" Text="symbol_name"/>
|
||||
<TextBox Grid.Row="1" Text="timeframe"/>
|
||||
<TextBox Grid.Row="2" Text="startPos"/>
|
||||
<TextBox Grid.Row="2" Text="start_pos"/>
|
||||
<TextBox Grid.Row="3" Text="count"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TimeSeriesValues.SymbolValue}"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1"
|
||||
@@ -372,7 +355,7 @@
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="Market Info">
|
||||
<TabItem Header=" Market Info">
|
||||
<WrapPanel VerticalAlignment="Top" Margin="5">
|
||||
<Button Command="{Binding SymbolsTotalCommand}" Content="SymbolsTotal" Margin="2"/>
|
||||
<Button Command="{Binding SymbolNameCommand}" Content="SymbolName" Margin="2"/>
|
||||
@@ -389,16 +372,10 @@
|
||||
<Button Command="{Binding MarketBookGetCommand}" Content="MarketBookGet" Margin="2"/>
|
||||
</WrapPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="CTrade">
|
||||
<WrapPanel VerticalAlignment="Top" Margin="5">
|
||||
<Button Command="{Binding PositionOpenCommand}" Content="PositionOpen" Margin="2"/>
|
||||
</WrapPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<Expander Grid.Row="2" Header="History" IsExpanded="True">
|
||||
<ListBox mtApi5TestClient:ListBoxBehavior.ScrollOnNewItem="true" Height="200" ItemsSource="{Binding History}"/>
|
||||
<ListBox Height="200" ItemsSource="{Binding History}"/>
|
||||
</Expander>
|
||||
|
||||
<StatusBar Grid.Row="3">
|
||||
|
||||
Executable → Regular
Executable → Regular
+1
-1
@@ -39,7 +39,7 @@ namespace MtApi5TestClient
|
||||
}
|
||||
}
|
||||
|
||||
public ulong Order
|
||||
public uint Order
|
||||
{
|
||||
get { return TradeRequest.Order; }
|
||||
set
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
@@ -10,9 +10,8 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MtApi5TestClient</RootNamespace>
|
||||
<AssemblyName>MtApi5TestClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@@ -26,7 +25,6 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
@@ -36,7 +34,6 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -53,7 +50,6 @@
|
||||
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
|
||||
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
|
||||
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
@@ -71,7 +67,6 @@
|
||||
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
|
||||
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
|
||||
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -102,7 +97,6 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="DelegateCommand.cs" />
|
||||
<Compile Include="ListBoxBehavior.cs" />
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -130,7 +124,6 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
||||
+26
-18
@@ -1,17 +1,17 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
// Runtime Version:4.0.30319.18034
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MtApi5TestClient.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
namespace MtApi5TestClient.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
@@ -22,40 +22,48 @@ namespace MtApi5TestClient.Properties {
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MtApi5TestClient.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-10
@@ -1,24 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
// Runtime Version:4.0.30319.18034
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace MtApi5TestClient.Properties {
|
||||
|
||||
|
||||
namespace MtApi5TestClient.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+356
-515
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup></configuration>
|
||||
@@ -837,7 +837,7 @@ namespace TestApiClientUI
|
||||
}
|
||||
|
||||
//OrderSend
|
||||
private async void button1_Click(object sender, EventArgs e)
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
var symbol = textBoxOrderSymbol.Text;
|
||||
|
||||
@@ -878,7 +878,7 @@ namespace TestApiClientUI
|
||||
break;
|
||||
}
|
||||
|
||||
var ticket = await Execute(() => _apiClient.OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrowColor));
|
||||
var ticket = Execute(() => _apiClient.OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrowColor));
|
||||
|
||||
AddToLog(string.Format("Sended order result: ticket = {0}", ticket));
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+49
-142
@@ -3,8 +3,6 @@
|
||||
|
||||
#include <Trade\SymbolInfo.mqh>
|
||||
#include <trade/trade.mqh>
|
||||
#property version "1.1"
|
||||
#property description "MtApi (MT5) connection expert"
|
||||
|
||||
#import "MT5Connector.dll"
|
||||
bool initExpert(int expertHandle, int port, string symbol, double bid, double ask, string& err);
|
||||
@@ -34,6 +32,8 @@
|
||||
bool getDoubleValue(int expertHandle, int paramIndex, double& res);
|
||||
bool getStringValue(int expertHandle, int paramIndex, string& res);
|
||||
bool getBooleanValue(int expertHandle, int paramIndex, bool& res);
|
||||
|
||||
// void verify(bool isDemo, string accountName, long accountNumber);
|
||||
#import
|
||||
|
||||
input int Port = 8228;
|
||||
@@ -43,11 +43,12 @@ int ExpertHandle;
|
||||
string message;
|
||||
bool isCrashed = false;
|
||||
|
||||
bool IsRemoteReadyForTesting = false;
|
||||
|
||||
string symbolValue;
|
||||
string commentValue;
|
||||
|
||||
double myBid;
|
||||
double myAsk;
|
||||
|
||||
string PARAM_SEPARATOR = ";";
|
||||
|
||||
int OnInit()
|
||||
@@ -56,12 +57,6 @@ int OnInit()
|
||||
return (result);
|
||||
}
|
||||
|
||||
double OnTester()
|
||||
{
|
||||
Print("OnTester");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
deinit();
|
||||
@@ -74,9 +69,9 @@ void OnTick()
|
||||
|
||||
int preinit()
|
||||
{
|
||||
StringInit(message, 1000, 0);
|
||||
StringInit(symbolValue, 1000, 0);
|
||||
StringInit(commentValue, 1000, 0);
|
||||
message = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + "";
|
||||
symbolValue = "222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222" + "";
|
||||
commentValue = "333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333" + "";
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -89,15 +84,11 @@ bool IsDemo()
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool IsTesting()
|
||||
{
|
||||
bool isTesting = MQLInfoInteger(MQL_TESTER);
|
||||
return isTesting;
|
||||
}
|
||||
|
||||
int init()
|
||||
{
|
||||
preinit();
|
||||
preinit();
|
||||
|
||||
// verify(IsDemo(), AccountInfoString(ACCOUNT_NAME), AccountInfoInteger(ACCOUNT_LOGIN));
|
||||
|
||||
if (TerminalInfoInteger(TERMINAL_DLLS_ALLOWED) == false)
|
||||
{
|
||||
@@ -119,14 +110,17 @@ int init()
|
||||
return (1);
|
||||
}
|
||||
|
||||
long chartID = ChartID();
|
||||
ExpertHandle = (int) ChartGetInteger(chartID, CHART_WINDOW_HANDLE);
|
||||
long chartID= ChartID();
|
||||
ExpertHandle = ChartGetInteger(chartID, CHART_WINDOW_HANDLE);
|
||||
|
||||
MqlTick last_tick;
|
||||
SymbolInfoTick(Symbol(),last_tick);
|
||||
double Bid = last_tick.bid;
|
||||
double Ask = last_tick.ask;
|
||||
|
||||
myBid = Bid;
|
||||
myAsk = Ask;
|
||||
|
||||
if (!initExpert(ExpertHandle, Port, Symbol(), Bid, Ask, message))
|
||||
{
|
||||
MessageBox(message, "MtApi", 0);
|
||||
@@ -139,30 +133,6 @@ int init()
|
||||
isCrashed = true;
|
||||
return (1);
|
||||
}
|
||||
|
||||
PrintFormat("Expert Handle = %d", ExpertHandle);
|
||||
|
||||
//--- Backtesting mode
|
||||
if (false)
|
||||
{
|
||||
if (IsTesting())
|
||||
{
|
||||
Print("Waiting on remote client...");
|
||||
//wait for command (BacktestingReady) from remote side to be ready for work
|
||||
while(!IsRemoteReadyForTesting)
|
||||
{
|
||||
executeCommand();
|
||||
|
||||
//This section uses a while loop to simulate Sleep() during Backtest.
|
||||
unsigned int viSleepUntilTick = GetTickCount() + 100; //100 milliseconds
|
||||
while(GetTickCount() < viSleepUntilTick)
|
||||
{
|
||||
//Do absolutely nothing. Just loop until the desired tick is reached.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//---
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -177,7 +147,6 @@ int deinit()
|
||||
isCrashed = true;
|
||||
return (1);
|
||||
}
|
||||
Print("Expert was deinitialized.");
|
||||
}
|
||||
|
||||
return (0);
|
||||
@@ -185,46 +154,50 @@ int deinit()
|
||||
|
||||
int start()
|
||||
{
|
||||
MqlTick last_tick;
|
||||
SymbolInfoTick(Symbol(),last_tick);
|
||||
double Bid = last_tick.bid;
|
||||
double Ask = last_tick.ask;
|
||||
if (isCrashed == 0)
|
||||
{
|
||||
MqlTick last_tick;
|
||||
SymbolInfoTick(Symbol(),last_tick);
|
||||
double Bid = last_tick.bid;
|
||||
double Ask = last_tick.ask;
|
||||
|
||||
if (!updateQuote(ExpertHandle, Symbol(), Bid, Ask, message))
|
||||
{
|
||||
Print("updateQuote: [ERROR] ", message);
|
||||
if (executeCommand() != 0)
|
||||
{
|
||||
CSymbolInfo mysymbol;
|
||||
mysymbol.Name (_Symbol);
|
||||
mysymbol.RefreshRates();
|
||||
|
||||
Bid = mysymbol.Bid();
|
||||
Ask = mysymbol.Ask();
|
||||
|
||||
if (myBid == Bid && myAsk == Ask)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!updateQuote(ExpertHandle, Symbol(), Bid, Ask, message))
|
||||
{
|
||||
MessageBox(message, "MtApi", 0);
|
||||
isCrashed = true;
|
||||
return (1);
|
||||
}
|
||||
|
||||
myBid = Bid;
|
||||
myAsk = Ask;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void OnTimer()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
int executedCommand = executeCommand();
|
||||
if (executedCommand == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int executeCommand()
|
||||
{
|
||||
int commandType = 0;
|
||||
|
||||
if (!getCommandType(ExpertHandle, commandType))
|
||||
{
|
||||
Print("[ERROR] getCommandType");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (commandType > 0)
|
||||
{
|
||||
Print("executeCommand: commnad type = ", commandType);
|
||||
}
|
||||
}
|
||||
|
||||
switch (commandType)
|
||||
{
|
||||
@@ -254,7 +227,6 @@ int executeCommand()
|
||||
sendBooleanResponse(ExpertHandle, retVal);
|
||||
}
|
||||
break;
|
||||
|
||||
case 64: //PositionClose
|
||||
{
|
||||
int ticket;
|
||||
@@ -265,7 +237,7 @@ int executeCommand()
|
||||
sendBooleanResponse(ExpertHandle, trade.PositionClose(ticket));
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 2: // OrderCalcMargin
|
||||
{
|
||||
ENUM_ORDER_TYPE action;
|
||||
@@ -1638,72 +1610,7 @@ int executeCommand()
|
||||
sendVoidResponse(ExpertHandle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 65: //PositionOpen
|
||||
{
|
||||
string symbol;
|
||||
StringInit(symbol, 50, 0);
|
||||
ENUM_ORDER_TYPE order_type;
|
||||
double volume;
|
||||
double price;
|
||||
double sl;
|
||||
double tp;
|
||||
string comment;
|
||||
StringInit(comment, 1000, 0);
|
||||
|
||||
getStringValue(ExpertHandle, 0, symbol);
|
||||
int order_type_int = 0;
|
||||
getIntValue(ExpertHandle, 1, order_type_int);
|
||||
order_type = (ENUM_ORDER_TYPE) order_type_int;
|
||||
getDoubleValue(ExpertHandle, 2, volume);
|
||||
getDoubleValue(ExpertHandle, 3, price);
|
||||
getDoubleValue(ExpertHandle, 4, sl);
|
||||
getDoubleValue(ExpertHandle, 5, tp);
|
||||
getStringValue(ExpertHandle, 6, comment);
|
||||
|
||||
PrintFormat("command PositionOpen: symbol = %s, order_type = %d, volume = %f, price = %f, sl = %f, tp = %f, comment = %s",
|
||||
symbol, order_type, volume, price, sl, tp, comment);
|
||||
|
||||
CTrade trade;
|
||||
bool result = trade.PositionOpen(symbol, order_type, volume, price, sl, tp, comment);
|
||||
sendBooleanResponse(ExpertHandle, result);
|
||||
Print("command PositionOpen: result = ", result);
|
||||
}
|
||||
break;
|
||||
|
||||
case 66: //BacktestingReady
|
||||
{
|
||||
if (IsTesting())
|
||||
{
|
||||
Print("Remote client is ready for backteting");
|
||||
IsRemoteReadyForTesting = true;
|
||||
sendBooleanResponse(ExpertHandle, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendBooleanResponse(ExpertHandle, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 67: //IsTesting
|
||||
{
|
||||
sendBooleanResponse(ExpertHandle, IsTesting());
|
||||
}
|
||||
break;
|
||||
|
||||
case 68: //Print
|
||||
{
|
||||
string printMsg;
|
||||
StringInit(printMsg, 1000, 0);
|
||||
|
||||
getStringValue(ExpertHandle, 0, printMsg);
|
||||
|
||||
Print(printMsg);
|
||||
sendBooleanResponse(ExpertHandle, true);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
Print("Unknown command type = ", commandType);
|
||||
|
||||
Reference in New Issue
Block a user