Доброго времени суток!
На нашем последнем уроке мы рассмотрим свойства и метода отвечающие за отображение информации в программе FinaLab.MTS.
Начнем с заполнения свойств TargetPriceBuy и TargetPriceSell. Эти методы показывают текущую цену по которой вы будете выставлять заявку(конечно же вы можете вывести в эти поля что захотите, хоть загружать результаты последнего матча любимой футбольной команды). В данном примере мы выставляем заявку по ценам Bid и Ask соответственно, поэтому мы можем напрямую их выводить. Или же если наша программа рассчитывает цену которая будет в будущем, то мы можем сделать так: создать переменные, например PriceBuy и PriceSell и присвоить им рассчитанные цены, а потом вывести их через рассматриваемые сейчас свойства(TargetPriceBuy и TargetPriceSell) чтобы вы могли контролировать работу программы.
1. На этом шаге мы сделаем так чтобы в ячейках программы TargetPriceSell и TargetPriceBuy выводились цены по которым мы собираемся выставлять заявки. В данном примере это, как я уже сказал, цена Bid и цена Ask(Рис1).
2. Далее мы рассмотрим заполнение метода, который по умолчанию выводит среднюю цену в стакане(напоминаю, использовать мы его можем для вывода любой необходимой нам информации)(Рис2).
3. В следующих методах следует указать количество лотов необходимые для открытия или закрытия позиции(Рис3).
4. Теперь мы подошли к рассмотрению, на мой взгляд, самого полезного инструмента вывода информации через системы FinLab.MTS - инструмент который может выводить практически любое количество переменных.
Для начала мы переопределим метода CreateInformer(), в котором через экземпляр конструктора следует указать количество создаваемых ячеек и их заголовки, в виде массива строк(Рис4, Рис5).
5. Переопределим метод OnUpdateStakan, который вызыается при каждом обновлении стакана(первой ноги или второй, если таковая имеется) и передает нам интерфейс IStakan для каждой ноги через который можно получить нужную нам информацию, в том числе Bid И Ask(Рис 6).
6. Создадим метод, в котором будем задавать цвет ячеек Informer'a и собственно передавать сами значения(Рис7).
7. По указанному ниже примеру зададим цвета наших ячеек(Рис8).
8. Зададим значения, которые будут выводиться в ячейках(Рис9).
9. Добавляем созданный нами метод Info в OnUpdateStakan, так как на м нужно чтобы каждое обновление стакана вызывался метод Info(Рис10).
Вот собственно и все. На этом я позволю себе закончить. Успехов вам в написание СВОИХ торговых роботов, а ГЛАВНОЕ чтобы заложенные в них стратегии были прибыльными! Весь исходный код нашей программы выглядит так.
Код программы:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; using FinLab.MTS.Infinity; using FinLab.TradeBase; using System.Drawing; using System.Windows.Forms; namespace ClassLibrary1 { public class Class1:Algorithm { public Class1() { } private enum Regim { Buy, Sell, Close, No } private Regim _Regim = Regim.No; public int Lot_Size { get; set; } private void CreateOrder() { if (Futures.Ask > Futures.PrevAsk)//Если текущий Ask больше предыдущего, то даем сигнал на покупку _Regim = Regim.Buy; if (Futures.Bid < Futures.PrevBid)//Если текущий Bid меньше предыдущего, то даем сигнал на продажу _Regim = Regim.Sell; } public override AddCommand CheckBuyDirection(IStakan futures, IStakan spot) { double res = AverageOpenedSpread - futures.Bid; if (OpenedPosition < 0) if (res < 0 && Math.Abs(res) > 250) return new AddCommand(futures.SecBoard, futures.SecCode, "", "B", "L", -OpenedPosition, futures.GetBasisBidPrice(-OpenedPosition, 3)); if (OpenedPosition>=0) { if (_Regim == Regim.Buy) { _Regim = Regim.No; return new AddCommand(futures.SecBoard, futures.SecCode, "", "B", "L", Lot_Size, futures.Bid); } } else { if (AverageOpenedSpread - futures.Bid >= 100) { return new AddCommand(futures.SecBoard, futures.SecCode, "", "B", "L", Math.Min(Lot_Size, -OpenedPosition), futures.Bid); } } return null; } public override AddCommand CheckSellDirection(IStakan futures, IStakan spot) { double res = futures.Ask - AverageOpenedSpread; if (OpenedPosition < 0) if (res < 0 && Math.Abs(res) > 250) return new AddCommand(futures.SecBoard, futures.SecCode, "", "S", "L", OpenedPosition, futures.GetBasisAskPrice(OpenedPosition, 3)); if (OpenedPosition <= 0) { if (_Regim == Regim.Sell) { _Regim = Regim.No; return new AddCommand(futures.SecBoard, futures.SecCode, "", "S", "L", Lot_Size, futures.Ask); } } else { if (futures.Ask - AverageOpenedSpread >= 100) { return new AddCommand(futures.SecBoard, futures.SecCode, "", "S", "L", Math.Min(Lot_Size, OpenedPosition), futures.Ask); } } return null; } public override bool DeleteOrderBuy(AddCommand addCommand, IStakan futures, IStakan spot) { if (OpenedPosition>0) { //В данном примеры здесь ничего не делаем } else { double res = AverageOpenedSpread - futures.Bid; if (res < 0 && Math.Abs(res) > 250) return true; } return false; } public override bool DeleteOrderSell(AddCommand addCommand, IStakan futures, IStakan spot) { if (OpenedPosition < 0) { //В данном примеры здесь ничего не делаем } else { double res = futures.Ask - AverageOpenedSpread; if (res < 0 && Math.Abs(res) > 250) return true; } return false; } public override bool Initialize() { return true; } public override void Dispose() { } public override ObjectAssociatedControl CreateControl() { UserControl1 usc = new UserControl1(this); return usc; } public override double TargetPriceBuy { get { return Futures.Bid;} } public override double TargetPriceSell { get { return Futures.Ask;} } public override double AveragePrice { get { return RoundPrice((Futures.Ask + Futures.Bid) / 2); } } public override int CurrentLotSizeBuy { get { return OpenedPosition >= 0 ? Lot_Size : Math.Min(Lot_Size, -this.OpenedPosition); } } public override int CurrentLotSizeSell { get { return this.OpenedPosition <= 0 ? Lot_Size : Math.Min(Lot_Size, this.OpenedPosition); } } protected override Informer CreateInformer() { return new Informer(2,new string[]{"Продажа","Покупка"}); } public override void OnTrade(Trade trade) { /* Здесь можно получить информацию о сделке, но пока нам это не нужно, но так как это abstract метод, мы обязаны его определить. */ } public override void OnUpdateStakan(IStakan futures, IStakan spot) { Info(); } public void Info() { this.Informer.Colors = new System.Drawing.Color[] { System.Drawing.Color.IndianRed, System.Drawing.Color.GreenYellow }; this.Informer.Values = new object[] { Futures.Ask, Futures.Bid}; } } } public partial class UserControl1 : ObjectAssociatedControl { private Class1 Cla; public UserControl1(Class1 state) { Cla = state; InitializeComponent(); numericUpDown1.Value = (decimal)Cla.Lot_Size; } public override void ApplyChanges() { Cla.Lot_Size = (int)numericUpDown1.Value; } } partial class UserControl1 { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); this.label1 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); this.SuspendLayout(); // // numericUpDown1 // this.numericUpDown1.Location = new System.Drawing.Point(85, 8); this.numericUpDown1.Name = "numericUpDown1"; this.numericUpDown1.Size = new System.Drawing.Size(45, 20); this.numericUpDown1.TabIndex = 0; // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(3, 10); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(76, 13); this.label1.TabIndex = 1; this.label1.Text = "Кол-ва лотов:"; // // groupBox1 // this.groupBox1.Location = new System.Drawing.Point(3, 34); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(229, 186); this.groupBox1.TabIndex = 2; this.groupBox1.TabStop = false; this.groupBox1.Text = "Другие настройки:"; // // UserControl1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.groupBox1); this.Controls.Add(this.label1); this.Controls.Add(this.numericUpDown1); this.Name = "UserControl1"; this.Size = new System.Drawing.Size(235, 234); ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.NumericUpDown numericUpDown1; private System.Windows.Forms.Label label1; private System.Windows.Forms.GroupBox groupBox1; }
P.S. Напоминаю описание API для FinLab.MTS можно скачать здесь! Так же вы можете посмотреть предыдущие 3 урока:
При компиляции пишет: “Проект, создающий библиотеку классов, не может быть непосредственно запущен.
Для отладки данного проекта добавьте к решению проект создающий приложение и ссылающийся на эту библиотеку и сделайте его запускаемым.”
Поясните, пожалуйста, по шагам, что здесь сделать надо…
Доброе утро!
Все правильно он пишет. Нужно нажимать построить (F6), а не запустить (F5). Так как это dll библиотека и сама она не может быть запущена. Она может использоваться другим приложением, например WindowsForm, а вот WindowsForm сам может быть запущен. В нашем примере он будет запускаться FinLab.PairTrade, нажав добавить пользовательскую задачу и выбрав свой проект(если он лежит не в корне программы, то нужно будет указать где dll-ка лежит)запустить его.
Продолжение будет? Как связать, например, пользовательскую форму с параметрами бота, которые нужно регулировать.
Это было на втором уроке. /2010/09/1192/
Правильно ли я понимаю:
1) Такой робот запускается на моей Windows машине с .NET, обращается к брокеру, при этом между мной и брокером будет довольно большая задержка (секунды).
2) От брокера до биржи будет еще задержка сколько-то секунд или милисекунд.
Если я все так – можно ли таким роботом скальпировать?
3) Можно ли располагать роботов максимально близко к бирже, например, у брокеров?
Не пинайте ногами, я новичек, только разбираюсь с вопросом
Юрий,добрый день.
Схему вы описали правильно(там еще можно добавить время на обработку вашей заявки ПО биржи). Такая задержка про которую вы пишете бывает, но только на очень загруженных серверах брокера, при плохом соединении и при слабом компьютере, который будет долго обрабатывать ваши запросы.
На самом же деле заявка появляется в стакане в течении секунды(а на плазе еще быстрее). Да, конечно можно делать и скальперских роботов, и таковых не мало участвует в ЛЧИ.
Располагать то можно, если конечно брокер будет не против и выделит вам место))
Приветствую!
Очень хотелось бы увидеть пример написания “метода” для “заготовок”, хотя бы простейшего, и желательно “на пальцах” что бы понять где и на какие кнопки нажимать. На мой взгляд, существующих методов маловато.
С уважением, Роман.
на строке: return new AddCommand(futures.SecBoard, futures.SecCode, “”, “B”, “L”, -OpenedPosition, futures.GetBasisBidPrice(-OpenedPosition, 3));
Ошибка: “FinLab.TradeBase.AddCommand” не содержит конструктор, который принимает аргументы “7” ClassLibrary1
Как ее устранить?
и Не хватает 5 -го урока, где этот код подключаем в Фин лаб Паир трейд и его там запускаем и настраиваем.
Как связать робота с данными от индикаторов, поступающих на графики Алор-Трейда ? Хорошо бы прописать в C# пример получения информации о 2 -х ЕМА с изменяемым периодом для дальнейшего анализа в алгоритме торговли.По аналогии можно будет увязать и с другими “индюками”.
После проделанного при открытии конструктора( построить F6) вылетает ошибка : Ошибка – Не удалось найти имя типа или пространства имен “Class1″ (пропущена директива using или ссылка на сборку?). Подскажите где чего искать . Пытался просто сохранить проект. Потом хотел открыть библиотеку ClassLibrary1.dll из FinLab.PairTrade – он её не видит в упор и не добавляет в окно. Полскажите ПЛИЗ ,где соьака зарыта?
«Спасибо», что никто не ответил , т.к. это заставило самому во всём разобраться – «Class1.» выдавал ошибку т.к. эта часть кода пишется на другой странице кода (UserContrul1.cs) , а поначалу я всё в Class1.cs прописывал. А насчет того что FinLab.PairTrade не видит библиотеки – вот тут я помучился . Оказалось всё просто – я создавал библиотеку с использованием 4 .NET. а не 3.5.NET.( о чём написано в 1 уроке). Как всегда – ВСЁ ИМЕЕТ ЗНАЧЕНИЕ ! Так что будьте внимательны !!!
А можно эти статьи оформить для скачивания в виде нормального файла как пример создания стратегии на этом продукте?