Программирование - это просто
Advertisement
Главная arrow Уроки программирования arrow Создаем биржевого робота уроки, статьи, идеи arrow Урок 17. Биржевой симулятор на Delphi: доработка класса TESBAccount (акции, покупка, продажа).
27.10.2021 г.
Главное меню
Главная
Интернет магазин
Программные продукты
Биржевые роботы
Искусственный интеллект
Математика и информатика
1С:Предприятие
Уроки C#
Уроки Delphi
Уроки программирования
Web-программирование
Дизайн и графика
Компьютер для блондинок
Исходники
Статьи
Платный раздел
Рассказы про компьютеры
Хитрости и секреты
Системный подход
Размышления
Наука для чайников
Друзья сайта
Excel-это не сложно
Все о финансах
.
Урок 17. Биржевой симулятор на Delphi: доработка класса TESBAccount (акции, покупка, продажа). Печать E-mail
Автор megabax   
25.03.2010 г.
New Page 1

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

Все статьи по данной теме.

Исходники к уроку можно скачать здесь.

Это последний урок из серии "Создаем биржевого робота на Delphi", публикуемый в бесплатном разделе. Начиная со следующего, публикация уроков будет продолжена в платном разделе. В бесплатном же разделе будут публиковать некоторые статьи, посвященные идеям технического анализа и их автоматизации.

Анонсы платного раздела уроков по биржевому роботу находятся здесь.

Мы уже разработали заготовку класса для симуляции биржевого счета и симуляции покупки (продажи) акций. Теперь пришло время соединить их. Сначала вспомним материалы предыдущих уроков (урок 14, урок 15, урок 16), либо скачаем пример, созданный на прошлом уроке. Теперь приступим к программированию. На этом уроке мы внесем изменения в класс TESBAccount. Вот как его новое объявление:

//класс симуляции состояния биржевого счета
TESBAccount=class(TESBBaseClass)
protected
   FCash:double;
   FExceptionCash:boolean;
   FInstruments:TList; //инструменты
   FTechCosts:double; //технические расходы (проскальзывание+коммиссия), %
   function Get(index:integer):TESBInstrument;
   function GetCount:integer;
public
   property Cash:double read FCash; //состояние счета можно изменить только методами
   property ExceptionCash:boolean read FExceptionCash write FExceptionCash;
   property Instruments[index:integer]:TESBInstrument read Get; default;
   property TechCosts:double read FTechCosts write FTechCosts;
   property InstrumetnsCount:integer read GetCount;
   constructor Create;
   procedure Replenish(ACash:double); //пополнить
   procedure Withdraw(ACash:double); //снять
   procedure Serialize(AStream:TStream); override;
   procedure Unserialize(AStream:TStream); override;
   procedure AddInstrument(item:TESBInstrument);
   procedure DeleteInstrument(index:integer);
   procedure Buy(index,count:integer);
   procedure Sell(index,count:integer);
   function GetCashLimit:double; 
   destructor Destroy; virtual;
end;

Как видите, у нас добавляется новое свойство Instruments, в связи с чем в секцию private так же добавляем поле FInstruments и функцию Get для чтения значения свойства. Оно у нас read only, поэтому реализовывать метод записи не нужно.

Свойство Instruments у нас является списком, поэтому на необходим метод добавления AddInstrument и удаления DeleteInstrument. Для определения количества доступных ценных бумаг добавляем к классу свойство InstrumetnsCount, так же read only и функцию для чтения этого свойства GetCount.

Еще у класса появляться новые методы Buy и Sell для симуляции покупки и продажу ценных бумаг соответственно. В качестве параметров этих методов номер ценной бумаги в списке и количество.

Ну и наконец, для более грамотной симулции, приближенной к реальным условием, вводим такое понятие как технические расходы (свойство TechCosts, его поле в секции private FTechCosts).

Теперь займемся реализацией. пойдем по порядку. Функции Get и GetCount реализуются довольно элементарно, мы просто обращаемся к соответствующим свойствам FInstruments:

function TESBAccount.Get(index:integer):TESBInstrument;
begin
      Result:=FInstruments[index];
end;

function TESBAccount.GetCount:integer;
begin
       Result:=FInstruments.Count;
end;

Нам нужно обязательно внести изменение в конструктор Crate, так как у нас появилось новое приватное поле FInstruments, требующее создание объекта:

constructor TESBAccount.Create;
begin
    inherited Create;
    FCash:=0;
    FExceptionCash:=true;
    FInstruments:=TList.Create;
end;

Методы Serialize и Unserialize пока не будем реализовывать, оставим их без изменения, для начала мы состряпаем симулятор "на коленке", а потом будем его улучшать, добавлять функционал и делать в программе разные "красивости".

Перейдем к следующим  методам: AddInstrument и DeleteInstrument, они тоже программируются довольно просто:

procedure TESBAccount.AddInstrument(item:TESBInstrument);
begin
     FInstruments.Add(item);
end;

procedure TESBAccount.DeleteInstrument(index:integer);
begin
    FInstruments.Delete(index);
end;

Для симуляции покупки мы реализуем метод Buy:

procedure TESBAccount.Buy(index,count:integer);
var ACash,CashLimit:double;
begin
     CashLimit:=GetCashLimit;
     ACash:=TESBInstrument(FInstruments[index]).CurrentPrice*Count*(1+FTechCosts/100);
     if FCash-ACash<CashLimit then raise Exception.Create('TESBAccount.Buy - недостаточно средств для совершения операции');
     TESBInstrument(FInstruments[index]).Buy(count);
     FCash:=FCash-ACash;
end;

Как видим, и тут ничего сложного: запрашиваем лимит денежных средств (может быть нуль, а может и отрицательное число - если есть кредитное плечо. Так же может быть положительным, если денежные средства на счете заблокированы, но это к сведению). Затем мы вычисляем, сколько стоят купленные ацкии и эту сумму вычитаем из наличных средств, предварительно проверив, хватает ли у нас денег для совершения сделки. Ну, и для увеличения числа акций вызываем метод Buy соответствующего объекта класса TESBInstrument, который мы реализовывали на уроке 16.

Теперь перейдем к методу Sell:

procedure TESBAccount.Sell(index,count:integer);
var ACash:double;
begin
     ACash:=TESBInstrument(FInstruments[index]).CurrentPrice*Count*(1-FTechCosts/100);
     TESBInstrument(FInstruments[index]).Sell(count);
     FCash:=FCash+ACash;
end;

Тут еще проще - вычисляем стоимость проданных акций, прибавляем их к нашим наличным и вызываем для соответствующего объекта метод sell. На возможность шортить, как вы помните из урока 16, проверит уже сам этот метод.

У нас остался деструктор и метод GetCashLimit. Во втором ставим пока просто заглушки, пока не будем заморачится с плечами и деривативами:

function TESBAccount.GetCashLimit:double;
begin
      Result:=0;
end;

Вот добрались и до деструктора:

destructor TESBAccount.Destroy;
var i,cn:integer;
begin
    cn:=FInstruments.Count-1;
    for i:=0 to cn do
    begin
        FreeAndNil(TESBInstrument(FInstruments[i]).FPriceSource);
        TESBInstrument(FInstruments[i]).Free;
    end;
    FreeAndNil(FInstruments);
    inherited Destroy;
end;

Несколько комментариев к коду: сначала мы очистим каждый элемент списка FInstruments, включая связанный с ним объект класса TPASSPriceSource, так как мы предполагаем, что каждый раз будем создавать экземпляр данного класса, когда будем добавлять инструмент в список. Затем мы уничтожаем сам объект списка и вызываем родительский деструктор.

Все, теперь пишем тестовый пример. Начнем с того, что немножко преобразуем форму, удалим с нее лишние компоненты и добавим новые. Она должна приобрести такой вид*:

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

Сетку (TStringGrid) в левой части формы мы назовем sgInstrs, этот компонент находиться у нас на закладке Additional*:

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

Теперь о кнопках. Кнопки (TButton) у нас на закладке Standard, кстати, там же и метка (TLabel)*:

Биржевой симулятор: доработка класса (акции, покупка, продажа).

Ниже приведена соответствия текса на кнопке (Caption) и их идентификаторов (свойство Name):

Caption Name
Добавить акцию в список btnAdd
Купить btnBuy
Продать btnSell
След. свеча btnNext

поле ввода edCount должно нас остаться с предыдущего примера. Диалоги выбора файлов - тоже. А метку lbPrice мы переименуем в lbCash.

Теперь займемся программированием. Для начала нужно поставить на все пункты меню заглушки, закомментив предыдущий текст*:

Биржевой симулятор: доработка класса Account (акции, покупка, продажа).

изменим немного определение класса формы:

TfrmStockBot = class(TForm)
   MainMenu: TMainMenu;
   itFile: TMenuItem;
   itSave: TMenuItem;
   itOpen: TMenuItem;
   edCount: TEdit;
   btnBuy: TButton;
   btnSell: TButton;
   SaveDialog: TSaveDialog;
   OpenDialog: TOpenDialog;
   btnNext: TButton;
   itOpenPrices: TMenuItem;
   sgInstrs: TStringGrid;
   btnAdd: TBitBtn;
   lbCash: TLabel;
   procedure FormCreate(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
   procedure btnBuyClick(Sender: TObject);
   procedure btnSellClick(Sender: TObject);
   procedure itSaveClick(Sender: TObject);
   procedure itOpenClick(Sender: TObject);
   procedure itOpenPricesClick(Sender: TObject);
   procedure btnNextClick(Sender: TObject);
   procedure btnAddClick(Sender: TObject);
private
  { Private declarations }
  Account:TESBAccount;
  procedure CreateGrid;
  procedure RedrawGrid;
public
  { Public declarations }
end;
 

Реализуем метод CreateGrid:

procedure TfrmStockBot.CreateGrid;
begin
    sgInstrs.Cols[0].Text:='№';
    sgInstrs.Cols[1].Text:='Наименование';
    sgInstrs.Cols[2].Text:='Цена';
    sgInstrs.Cols[3].Text:='Количество';
    sgInstrs.Cols[4].Text:='Стоимость';

    sgInstrs.ColWidths[1]:=140;
end;

В ней мы настраиваем вид таблицы - заголовки и ширину столбцов.

Для того, что бы обновлять таблицу при изменении данных реализуем метод RedrawGrid:

procedure TfrmStockBot.RedrawGrid;
var i,cn:integer;
begin
     cn:=Account.InstrumetnsCount;
     sgInstrs.RowCount:=cn+1;
     for i:=1 to cn do
     begin
            sgInstrs.Cells[0,i]:=IntToStr(i);
            sgInstrs.Cells[1,i]:=Account.Instruments[i-1].Name;
            sgInstrs.Cells[2,i]:=FloatToStr(Account.Instruments[i-1].CurrentPrice);
            sgInstrs.Cells[3,i]:=IntToStr(Account.Instruments[i-1].Count);
            sgInstrs.Cells[4,i]:=FloatToStr(Account.Instruments[i-1].Count*Account.Instruments[i-1].CurrentPrice);
     end;
     lbCash.Caption:='Деньги '+FloatToStr(Account.Cash);
end;

Данный метод устанавливает у компонента TStringGrid столько строк, сколько у нас в таблице и выводит в эти строки сведения о количестве и ценах акций. Так же он обновляет информации о наличных деньгах.

Теперь перейдем к кнопочкам. Обработчик события OnClick кнопки btnAdd - "Добавить акцию в список":

procedure TfrmStockBot.btnAddClick(Sender: TObject);
var frm:TfrmInstrumEdit;
      instr:TESBInstrument;
      PriceSource:TPASSPriceSource;
begin
      frm:=TfrmInstrumEdit.Create(self);
      if frm.ShowModal=mrOk then
      begin
         instr:=TESBInstrument.Create;
         PriceSource:=TPASSPriceSource.Create('',false);
         PriceSource.LoadDataFromTextFile(frm.OpenDialog.FileName);
         PriceSource.First;
         instr.PriceSource:=PriceSource;
         instr.Name:=frm.edName.Text;
         instr.CanShort:=frm.chbCanShort.Checked;
         Account.AddInstrument(instr);
         RedrawGrid;
     end;
end;

Данный обработчик вызывает диалог выбора файла для открытия, если в этом диалоге пользователь нажал ОК, то загружаем из выбранного файла котировки (котировки должны храниться в файле в текстовой формате, их можно скачать с Интернета,  например, с финама). Загруженные котировки хранятся в объекте класса TPASSPRiceSource, ссылка на который добавляется в объект класса TESBInstrument, который у нас, в свою очередь, добавляется в Account. После этого перерисовывем таблицу методом RedrawGrid.

Что бы работал данный обработчик, нам понадобиться еще создать класс TfrmInstrumEdit - это диалоговая форма. Для того, что бы создать ее, войдем в меню "File" -> "New" -> "Form"*:

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

созданную форму сохраним в файле под именем InstrumEdit, значение поле Name у формы так же установим в InstrumEdit*

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

Теперь придадим полученной форме вот такой вид*:

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

Элементам диалога установим следующие имена (свойство Name)

Назначение элемента Имя
Поле ввода названия инструмента, компонент TEdit edName
Поле ввода имени файла, компонент TEdit edFileName
Диалог выбора файла, компонент TOpenDialog OpenDialog
Кнопка с тремя точками btnFileDilaog
Флажок "можно ли вставать в шорт" chbCanShort
Кнопочка "ОК" btnOK

Так же к основному модулю подключим модуль созданной нами формы*:

http://easyprog.ru/index.php?option=com_content&task=view&id=241&Itemid=29

Все, с добавлением акций закончили, переходим к следующим кнопкам.

Кнопка "Купить". Вот ее обработчик OnClick

procedure TfrmStockBot.btnBuyClick(Sender: TObject);
begin
     Account.Buy(sgInstrs.Row-1,StrToInt(edCount.Text));
     RedrawGrid;
end;

Как видим, данный обработчик просто вызывает уже написанный нами метод Buy класса TESBAccount и процедуру обновления таблицы.

Кнопка "Продать". Аналогично:

procedure TfrmStockBot.btnSellClick(Sender: TObject);
begin
     Account.Sell(sgInstrs.Row-1,StrToInt(edCount.Text));
     RedrawGrid;
end;

Кнопка "След. свеча". Так же вызываем уже написанный метод:

procedure TfrmStockBot.btnNextClick(Sender: TObject);
begin
     Account.Instruments[sgInstrs.Row-1].Next;
      RedrawGrid;
end;

Все, теперь нам осталось запустить программу и протестировать ее. Тестируем по следующей схеме:

1. Добавляем акцию в список, лучше несколько и с разными вариантами галочки "Можно ли вставать в шорт".

2. Тестируем кнопки "Купить", "Продать" и "След свеча":

Биржевой симулятор: доработка класса TESBAccount (акции, покупка, продажа).

Если при покупке (продаже) у вас соответственно меняется количество акций и денежных средств, при чем с учетом технических расходов, а при нажатии на кнопку "След. свеча" в таблицу встает цена следующего интервала, то класс TESBAccount работает правильно.

Исходники к уроку можно скачать здесь.


Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями  программного продукта "Delphi", авторское право на который принадлежит "Borland Software Corporation, (a Micro Focus Company). 

 

 

Последнее обновление ( 17.07.2013 г. )
 
« След.   Пред. »
 
© 2021 Программирование - это просто
Joomla! - свободное программное обеспечение, распространяемое по лицензии GNU/GPL.
Русская локализация © 2005-2008 Joom.Ru - Русский Дом Joomla!
Design by Mamboteam.com | Powered by Mambobanner.de
Я принимаю Яндекс.Деньги