Организация бесперебойной торговли в терминале МТ5
Михаил | 25 февраля, 2015 | Вложения (1)
В статье рассматривается организация бесперебойной торговли в случае отключения электричества или интернета, а так же удалённое управление процессом торговли.
Введение
Коль скоро Вы решили использовать в торговле экспертов и советников,
чтобы ограничить своё времяпровождение за компьютером, то, вероятно,
необходимо позаботится и о том, чтобы советники нормально работали и
в аварийных ситуациях, таких как отключение электроэнергии и интернета.
А также необходимо получить удалённый доступ к компьютеру
из любого места, где есть интернет.
Итак...
Электропитание
Всем известно об источниках бесперебойного питания (ИП).
Но как же правильно выбрать его?
Самым главным параметром для ИП является скорость
переключения из штатного режима в аварийный.
И очень желательно, чтобы ИП имел USB связь с Вашим компьютером,
тогда Вы сможете составлять сценарии работы и выключения компьютера
в аварийном режиме (отключение электричества).


Следует также уделить внимание блоку питания (БП) Вашего
компьютера. Мощность потребления складывается и мощности потребления всех
компонентов, входящих в состав ПК, плюс запас в 20-30%.
Не следует покупать БП в два-три раза превышающий суммарную
мощность потребления ПК.
Но не только мощностью потребления характеризуются БП,
но и качеством. Наивысшим качеством исполнения
обладают БП c сертификатом 80 Plus Platinum

Это совсем не значит, что Вы должны купить именно такой,
но лучше приобрести БП с сертификатом (они гораздо надёжнее).
Интернет соединения
Вот тут и начинаются проблемы, которые и побудили меня написать эту статью.
Казалось чего проще?
Взял двух независимых провайдеров, подключил провода к компьютеру (или к маршрутизатору ), расставил метрики адаптеров и...
Но не тут-то было!
А не переключаются автоматически адаптеры ни в Windows, ни в маршрутизаторах, если кабель физически подключен и есть напряжение
на общем маршрутизаторе провайдера в вашем доме. А самое главное, сам Терминал МТ5 должен сообщить нам о потере связи.
Важно отметить, что ADSL соединение не зависит от электричества, и если у Вас в городе есть провайдер, который
предоставляет услуги интернета по телефонной линии, то очень рекомендую воспользоваться им в качестве резервного канала интернета.
Если нет, то можно воспользоваться "воздушными" соединениями сотовых операторов (значительно дороже),
но ОБЯЗАТЕЛЬНО резервное соединение никак не должно быть связано с поставщиком основного
канала интернета.
Приведённый ниже код библиотеки ( DLL ) написан в Delphi XE4.
Эта DLL позволяет осуществлять проверку состояния сетевых адаптеров в Вашей системе, а
также отключать и включать их.
ВАЖНО! Для нормальной работы библиотеки Терминал МТ5 необходимо запускать
от имени администратора.
//+------------------------------------------------------------------+
//| netswitch.dll |
//| Copyright 2015, Mikalas |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
library netswitch;
uses
Winapi.Windows, System.SysUtils, Winapi.ActiveX, System.Win.ComObj,
Winapi.UrlMon, System.Variants;
const
wbemFlagForwardOnly = $00000020;
//---Коды возврата инициализации DLL
INIT_DLL_FAILED = -1;
INIT_DLL_SUCCES = 0;
INIT_DLL_WRONG_NAME_ONE = 1;
INIT_DLL_WRONG_NAME_TWO = 2;
//---Коды возврата состояния адаптеров
STATE_UNKNOWN = -1;
STATE_MAIN_SLAVE_DISABLED = 0;
STATE_MAIN_SLAVE_ENABLED = 1;
STATE_MAIN_ENABLED = 2;
STATE_SLAVE_ENABLED = 3;
var
MainName, SlaveName: string;
function GetAdapter( aName: string; ip_enabled: boolean ): boolean;
var
oBindObj: IDispatch;
oNetAdapters, oNetAdapter,
odnsAddr, oWMIService: OleVariant;
i, iValue: longword;
oEnum: IEnumvariant;
oCtx: IBindCtx;
oMk: IMoniker;
sFileObj: WideString;
a_str: string;
k: integer;
begin
Result:= false;
//---Инициализация ActiveX
CoInitialize( nil );
try
sFileObj:= 'winmgmts:\\.\root\cimv2';
//---
OleCheck( CreateBindCtx( 0, oCtx ) );
OleCheck( MkParseDisplayNameEx( oCtx,PWideChar( sFileObj ), i, oMk ) );
OleCheck( oMk.BindToObject( oCtx,nil, IUnknown, oBindObj ) );
oWMIService:= oBindObj;
if ( ip_enabled ) then
oNetAdapters:= oWMIService.ExecQuery( 'Select * from ' +
'Win32_NetworkAdapterConfiguration ' +
'where IPEnabled=TRUE') else
oNetAdapters:= oWMIService.ExecQuery( 'Select * from ' +
'Win32_NetworkAdapterConfiguration ' +
'where IPEnabled=FALSE');
oEnum:= IUnknown( oNetAdapters._NewEnum ) as IEnumVariant;
//---
while ( oEnum.Next( 1, oNetAdapter, iValue ) = 0 ) do
begin
try
a_str:= oNetAdapter.Caption;
k:= Pos( ']', a_str );
if ( k > 0 ) then
begin
Delete( a_str, 1, k + 1) ;
if ( aName = a_str ) then
begin
Result:= true;
oNetAdapter:= Unassigned;
break;
end;
end;
except
end;
oNetAdapter:= Unassigned;
end;
//---
odnsAddr:= Unassigned;
oNetAdapters:= Unassigned;
oWMIService:= Unassigned;
finally
CoInitialize( Nil );
end;
end;
function InitNetSwitch( main_name: PAnsiString; slave_name: PAnsiString ): Integer; stdcall;
var
is_main_found: boolean;
is_slave_found: boolean;
begin
Result:= INIT_DLL_FAILED;
is_main_found:= false;
is_slave_found:= false;
//---
MainName:= string( main_name );
SlaveName:= string( slave_name );
//---Проверка существования основного адаптера с указанным описанием
if ( MainName <> '' ) then
if ( GetAdapter( MainName, false ) ) then is_main_found:= true else
if ( GetAdapter( MainName, true ) ) then is_main_found:= true;
//---Проверка существования запасного адаптера с указанным описанием
if ( SlaveName <> '' ) then
if ( GetAdapter( SlaveName, false ) ) then is_slave_found:= true else
if ( GetAdapter( SlaveName, true ) ) then is_slave_found:= true;
//---Результаты проверки
if ( is_main_found and is_slave_found ) then Result:= INIT_DLL_SUCCES else
if ( is_main_found and ( not is_slave_found ) ) then Result:= INIT_DLL_WRONG_NAME_TWO else
if ( ( not is_main_found ) and is_slave_found ) then Result:= INIT_DLL_WRONG_NAME_ONE;
end;
function GetAdaptersState(): Integer; stdcall;
begin
Result:= STATE_UNKNOWN;
//---Проверка состояния адаптеров
if ( ( MainName <> '' ) and ( SlaveName <> '' ) ) then
begin
if ( GetAdapter( MainName, true ) ) then
begin
if ( GetAdapter( SlaveName, true ) ) then Result:= STATE_MAIN_SLAVE_ENABLED else
Result:= STATE_MAIN_ENABLED;
end else
begin
if ( GetAdapter( SlaveName, true ) ) then Result:= STATE_SLAVE_ENABLED else
Result:= STATE_MAIN_SLAVE_DISABLED;
end;
end;
end;
function EnableDisableAdapter( a_name: string; disable_enable: boolean ): boolean;
var
FSWbemLocator: OLEVariant;
FWMIService: OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject: OLEVariant;
oEnum: IEnumvariant;
iValue: LongWord;
a_str: string;
k: integer;
begin
Result:= false;
//---Инициализация ActiveX
CoInitialize( nil );
try
if ( a_name <> '' ) then
begin
FSWbemLocator:= CreateOleObject( 'WbemScripting.SWbemLocator' );
FWMIService:= FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '' );
if ( disable_enable ) then
FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_NetworkAdapter Where NetEnabled=False',
'WQL', wbemFlagForwardOnly ) else
FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_NetworkAdapter Where NetEnabled=True',
'WQL', wbemFlagForwardOnly );
oEnum:= IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue ) = 0 do
begin
a_str:= FWbemObject.Caption;
k:= Pos( ']', a_str );
if ( k > 0 ) then
begin
Delete( a_str, 1, k + 1 );
if ( a_name = a_str ) then
begin
if ( disable_enable ) then
FWbemObject.Enable() else
FWbemObject.Disable();
Result:= true;
end;
end;
FWbemObject:= Unassigned;
end;
end;
finally
CoInitialize( nil );
end;
end;
function DisableMain(): Boolean; stdcall;
begin
Result:= EnableDisableAdapter( MainName, false );
end;
function EnableMain(): Boolean; stdcall;
begin
Result:= EnableDisableAdapter( MainName, true );
end;
function DisableSlave(): Boolean; stdcall;
begin
Result:= EnableDisableAdapter( SlaveName, false );
end;
function EnableSlave(): Boolean; stdcall;
begin
Result:= EnableDisableAdapter( SlaveName, true );
end;
exports
InitNetSwitch,
GetAdaptersState,
DisableMain,
EnableMain,
DisableSlave,
EnableSlave;
begin
end.
Библиотека должна находится в папке
C:\Users\ИМЯ_ПОЛЬЗОВАТЕЛЯ\AppData\Roaming\MetaQuotes\Terminal\НОМЕР_ТЕРМИНАЛА\MQL5\Libraries
Теперь рассмотрим как работает эксперт Net_switcher:
//+------------------------------------------------------------------+
//| Net_switcher.mq5 |
//| Copyright 2015, Mikalas |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Mikalas"
#property link "http://www.mql5.com"
#property version "1.00"
//
enum ENUM_INIT_DLL
{
INIT_DLL_FAILED = -1,
INIT_DLL_SUCCES = 0,
INIT_DLL_WRONG_NAME_ONE = 1,
INIT_DLL_WRONG_NAME_TWO = 2
};
enum ENUM_NET_STATE
{
STATE_UNKNOWN = -1,
STATE_MAIN_SLAVE_DISABLED = 0,
STATE_MAIN_SLAVE_ENABLED = 1,
STATE_MAIN_ENABLED = 2,
STATE_SLAVE_ENABLED = 3
};
//
#import "netswitch.dll"
ENUM_INIT_DLL InitNetSwitch( const string NameOne, const string NameTwo );
ENUM_NET_STATE GetAdaptersState();
bool DisableMain();
bool EnableMain();
bool DisableSlave();
bool EnableSlave();
#import
//
input string p_expert = "=== Параметры эксперта ==="; //
input uint TimerTime = 500; //Период таймера (мсек)
input string AdaptNameOne = "Intel(R) 82579V Gigabit Network Connection"; //Описание основного адаптера
input string AdaptNameTwo = "Realtek PCIe GBE Family Controller"; //Описание запасного адаптера
input string p_chart = "=== Параметры графика ==="; //
input color ButtDown = clrMagenta; //Цвет нажатой кнопки
input color ButtUp = clrMediumSeaGreen; //Цвет отжатой кнопки
input uint FontSize = 10; //Размер фонта
input uint StrSpace = 13; //Расстояние между строками
input color FontColor = clrWhite; //Цвет фонта
input ENUM_CHART_MODE Chart_mode = CHART_CANDLES; //Режим графика
input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT; //Период графика
input color Candle_bull = clrGreen; //Цвет Бычьей свечи
input color Candle_bear = clrRed; //Цвет Медвежьей свечи
input color BackGround = clrGray; //Цвет фона
input color Color_last = clrWhite; //Цвет последней цены
input color Chart_up = clrBlack; //Цвет свечи вверх
input color Chart_down = clrBlack; //Цвет свечи вниз
input color Chart_grid = clrDarkGray; //Цвет сетки
//
bool h_res;
bool not_first;
bool is_connected;
MqlDateTime tick_time;
ENUM_NET_STATE net_state;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
not_first = false;
//---Инициализация DLL
ENUM_INIT_DLL init_dll = InitNetSwitch( AdaptNameOne, AdaptNameTwo );
switch( init_dll )
{
case INIT_DLL_FAILED: MessageBox( "Ошибка инициализации netswitch.dll!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
break;
case INIT_DLL_WRONG_NAME_ONE: MessageBox( "Не найден сетевой адаптер с описанием " +
AdaptNameOne + " .", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
break;
case INIT_DLL_WRONG_NAME_TWO: MessageBox( "Не найден сетевой адаптер с описанием " +
AdaptNameTwo + " .", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
break;
}
//--- Проверка состояния сетевых адаптеров
net_state = GetAdaptersState();
//---
switch( net_state )
{
case STATE_UNKNOWN: MessageBox( "Ошибка проверки адаптеров!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
break;
case STATE_MAIN_SLAVE_DISABLED: h_res = EnableMain(); //Подключаем адаптеры. Первым - основной
if ( h_res )
{
EnableSlave();
}
break;
case STATE_MAIN_ENABLED: EnableSlave(); //Подключаем запасной адаптер
break;
case STATE_SLAVE_ENABLED: h_res = DisableSlave(); //Отключаем запасной, включаем основной, а затем, опять включаем запасной
if ( h_res )
{
h_res = EnableMain();
if ( h_res )
{
EnableSlave();
}
}
break;
case STATE_MAIN_SLAVE_ENABLED: h_res = DisableSlave(); //Так как мы не знаем какой адаптер используется, мы делаем рабочим основной адаптер
if ( h_res )
{
EnableSlave();
}
break;
}
//---
//---
if( !ObjectCreate( 0, "reset_button", OBJ_BUTTON, 0, 0, 0 ) )
{
MessageBox( "Кнопка 'Reset' не создана!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
else
{
ObjectSetInteger( 0, "reset_button", OBJPROP_CORNER, CORNER_RIGHT_LOWER );
ObjectSetInteger( 0, "reset_button", OBJPROP_XDISTANCE, 40 );
ObjectSetInteger( 0, "reset_button", OBJPROP_YDISTANCE, 18 );
ObjectSetInteger( 0, "reset_button", OBJPROP_XSIZE, 40 );
ObjectSetInteger( 0, "reset_button", OBJPROP_YSIZE, 18 );
ObjectSetInteger( 0, "reset_button", OBJPROP_BGCOLOR, ButtUp );
ObjectSetInteger( 0, "reset_button", OBJPROP_STATE, false );
ObjectSetString( 0, "reset_button", OBJPROP_TEXT, "Reset" );
}
//---инфострока
if( !ObjectCreate( 0, "info_label_1", OBJ_LABEL, 0, 0, 0 ) )
{
MessageBox( "Инфострока 1 не создана!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
else
{
ObjectSetInteger( 0, "info_label_1", OBJPROP_CORNER, CORNER_LEFT_UPPER );
ObjectSetInteger( 0, "info_label_1", OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER );
ObjectSetInteger( 0, "info_label_1", OBJPROP_XDISTANCE, 5 );
ObjectSetInteger( 0, "info_label_1", OBJPROP_YDISTANCE, 15 );
ObjectSetInteger( 0, "info_label_1", OBJPROP_FONTSIZE, FontSize );
ObjectSetInteger( 0, "info_label_1", OBJPROP_COLOR, FontColor );
ObjectSetInteger( 0, "info_label_1",OBJPROP_BACK, false );
ObjectSetString( 0, "info_label_1", OBJPROP_TEXT, "Инициализация..." );
}
//--- Set chart in candles
if ( !ChartSetInteger(0, CHART_MODE, Chart_mode ) )
{
MessageBox( "Режим свечей не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set Time Frame H1
if ( !ChartSetSymbolPeriod( 0, NULL, TimeFrame ) )
{
MessageBox( "Период графика не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set candles color
if ( !ChartSetInteger( 0, CHART_COLOR_CANDLE_BULL, Candle_bull ) )
{
MessageBox( "Цвет бычьих свечей не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//---
if ( !ChartSetInteger( 0, CHART_COLOR_CANDLE_BEAR, Candle_bear ) )
{
MessageBox( "Цвет медвежьих свечей не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set fon color
if ( !ChartSetInteger( 0, CHART_COLOR_BACKGROUND, BackGround ) )
{
MessageBox( "Цвет фона не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set hide line bid
if ( !ChartSetInteger( 0, CHART_SHOW_BID_LINE, false ) )
{
MessageBox( "Не скрыта линия BID!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set show line last
if ( !ChartSetInteger(0, CHART_SHOW_LAST_LINE, true ) )
{
MessageBox( "Линия последней цены не установлена!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set line bid color
if ( !ChartSetInteger(0, CHART_COLOR_LAST, Color_last ) )
{
MessageBox( "Цвет линии последней цены не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set color bid up
if ( !ChartSetInteger( 0, CHART_COLOR_CHART_UP, Chart_up ) )
{
MessageBox( "Цвет свечи вверх не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Set color bid up
if ( !ChartSetInteger( 0, CHART_COLOR_CHART_DOWN, Chart_down ) )
{
MessageBox( "Цвет свечи вниз не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//--- Color grid
if ( !ChartSetInteger( 0, CHART_COLOR_GRID, Chart_grid ) )
{
MessageBox( "Не установлен цвет сетки!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
//---Проверка подключения терминала к торговому серверу
if ( TerminalInfoInteger( TERMINAL_CONNECTED ) )
{
is_connected = true;
}
else
{
is_connected = false;
}
ObjectSetString( 0, "info_label_1", OBJPROP_TEXT, "Соединение через основной адаптер." );
ChartRedraw();
//--- Установка таймера
if ( !EventSetMillisecondTimer( TimerTime ) )
{
MessageBox( "Таймер не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
return( INIT_FAILED );
}
return( INIT_SUCCEEDED );
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit( const int reason )
{
//--- удаление таймера
EventKillTimer();
//---
ObjectDelete( 0, "reset_button" );
ObjectDelete( 0, "info_label_1" );
}
//+------------------------------------------------------------------+
//| Expert Switch To Main adapter function |
//+------------------------------------------------------------------+
void SwitchToMain( const ENUM_NET_STATE a_state )
{
switch( a_state )
{
case STATE_UNKNOWN:
case STATE_MAIN_SLAVE_DISABLED: h_res = EnableMain();
if ( h_res )
{
EnableSlave();
}
break;
case STATE_MAIN_SLAVE_ENABLED: h_res = DisableSlave();
if ( h_res )
{
EnableSlave();
}
break;
case STATE_MAIN_ENABLED: EnableSlave();
break;
case STATE_SLAVE_ENABLED: h_res = DisableSlave();
if ( h_res )
{
h_res = EnableMain();
if ( h_res )
{
EnableSlave();
}
}
break;
}
}
//+------------------------------------------------------------------+
//| Expert timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
TimeTradeServer( tick_time );
//---
if ( !TerminalInfoInteger( TERMINAL_CONNECTED ) )
{
if ( !not_first )
{
not_first = true;
is_connected = false;
Print( "OnTimer: Соединение потеряно!" );
SendMail( "Lost connection", "Соединение потеряно " + string( tick_time.hour ) +
":" + string( tick_time.min ) + ":" + string( tick_time.sec ) );
//---
net_state = GetAdaptersState();
//---
switch( net_state ) //Влючаем резервный канал
{
case STATE_UNKNOWN:
case STATE_MAIN_SLAVE_DISABLED: h_res = EnableSlave();
if ( h_res )
{
EnableMain();
}
break;
case STATE_MAIN_SLAVE_ENABLED: h_res = DisableMain();
if ( h_res )
{
EnableMain();
}
break;
case STATE_MAIN_ENABLED: h_res = DisableMain();
if ( h_res )
{
h_res = EnableSlave();
if ( h_res )
{
EnableMain();
}
}
break;
case STATE_SLAVE_ENABLED: EnableMain();
break;
}
}
}
else
{ //Соединение восстановлено
if ( !is_connected )
{
not_first = false;
is_connected = true;
Print( "OnTimer: Соединение восстановлено!" );
ObjectSetString( 0, "info_label_1", OBJPROP_TEXT, "Соединение через запасной адаптер." );
ChartRedraw();
}
}
}
//+------------------------------------------------------------------+
//| Expert Chart event function |
//+------------------------------------------------------------------+
void OnChartEvent( const int id, const long& lparam, const double& dparam, const string& sparam )
{
long b_state;
if ( id == CHARTEVENT_OBJECT_CLICK )
{
if ( sparam == "reset_button" )
{
if ( ObjectGetInteger( 0, "reset_button", OBJPROP_STATE, 0, b_state ) )
{
if ( b_state == 1 )
{
ObjectSetInteger( 0, "reset_button", OBJPROP_BGCOLOR, ButtDown );
ObjectSetString( 0, "reset_button", OBJPROP_TEXT, "Reset" );
ChartRedraw();
//---
net_state = GetAdaptersState();
SwitchToMain( net_state );
ObjectSetString( 0, "info_label_1", OBJPROP_TEXT, "Соединение через основной адаптер." );
ObjectSetInteger( 0, "reset_button", OBJPROP_STATE, false );
ObjectSetInteger( 0, "reset_button", OBJPROP_BGCOLOR, ButtUp );
ObjectSetString( 0, "reset_button", OBJPROP_TEXT, "Reset" );
ChartRedraw();
}
}
}
}
}
//+------------------------------------------------------------------+
//| The END |
//+------------------------------------------------------------------+
Библиотека использует описания (не имена в Windows) сетевых адаптеров ( см. рис)
которые необходимо ввести в настройках эксперта, другие настройки интуитивно понятны.
При инициализации эксперта, выключая и выключая адаптеры (мы не знаем через который установлено
соединение), эксперт устанавливает соединение через основной (1 в настройках эксперта) адаптер.
Далее запускается таймер, который с периодом 0,5 сек. проверяет состояние сети.
Логика проверки несложная.
При отсутствии соединения эксперт переключает соединение на запасной адаптер.
Нет смысла автоматически пытаться (потом) переключится на основной адаптер, так как
мы не знаем причины разрыва соединения ("упал" торговый сервер или нет интернета).
Кнопка "Reset" позволяет установить эксперта в исходное состояние (работа через основной адаптер).
Эксперт, при потере соединения, может отсылать e-mail на
указанный в настройках терминала адрес.
На www.mail.ru можно настроить почтовый ящик таким образом, чтобы в папку
"Входящие" помещались письма "от самого себя", а все остальные помещаются в
папку "СПАМ". Также, можно настроить отправку СМС, при появлении в папке
"Входящие" нового письма. Рекомендую придумать "навороченное" имя
н-р: jsdg!lzsnfdh486skldjg9824@mail.ru, чтобы имя ящика было как можно
более уникальным. Тогда Вы точно будете получать письма и СМС только от терминала.
Удалённое управление
В качестве инструмента удалённого управления успешно использую TeamViewer
(для личного пользования - бесплатный).

http://www.teamviewer.com/ru/index.aspx
Преимущество TeamViewer:
1. Не "привязан" к IP адресу компьютера
2. При его использовании происходит двойная проверка доступа к ПК.
( сам TeamViewer требует ID, пароль и пароль на Вашем ПК )
3. Суперпростой.
Заключение
Предпринятые меры по организации бесперебойной торговли позволят Вам
с невысокой долей беспокойства за процесс торговли отлучаться на недельку из дома ( н-р на рыбалку :) )
Надеюсь, что статья будет полезна не только начинающим трейдерам.
С уважением, и удачной торговли!
P/S Исходные и откомпилированные файлы в ZIP-архиве,
предоставляются для личного пользования.


