Тема: Вывод исторических данных через pipe
Хочу поделиться простой функцией экспорта данных графиков через pipe. Много работал с DDE серверами, но только недавно узнал про возможность такого простого экспорта данных через pipe. Открываем экспорт данных - данные для технического анализа, там выбираем инструмент, интервал и обязательно систему ТА - Amibroker. В общем-то все, после этого появится пайп с именем вида AmiBroker2QUIK_SBER@EQBR_1_1MINUTES, где SBER@EQBR_1 заданное мной имя. Теперь функция для чтения этого пайпа:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.ComponentModel;
using System.Timers;
using System.Linq;
namespace TestPipe
{
/// <summary>
/// Логика взаимодействия для MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
protected override void OnClosing(CancelEventArgs e)
{
if (pipe != null)
{
pipe.Dispose();
}
}
System.Timers.Timer _Timer = new System.Timers.Timer();
NamedPipeClientStream pipe;
public MainWindow()
{
InitializeComponent();
string pipeName = "AmiBroker2QUIK_SBER@EQBR_1_1MINUTES";
if (System.IO.Directory.GetFiles(@"\\.\pipe\").FirstOrDefault(p => p == "\\\\.\\pipe\\" + pipeName) != null)
{
pipe = new NamedPipeClientStream(pipeName);
bool cr = pipe.CanRead;
pipe.Connect();
_Timer.Elapsed += UpdateChart;
}
else
{
pipe = null;
}
}
public void WriteLine(string Line)
{
if ((Line.Length < 3) && (Line != Environment.NewLine))
{ Line = "0" + Line; }
Dispatcher.BeginInvoke(new Action(() =>
{
this.textBox1.Text = this.textBox1.Text + Line;
}));
}
private byte[] ReadPipe(NamedPipeClientStream NamedPipe, int size)
{
int bc = 0;
int bc2 = 0;
byte[] outByte = new byte[size];
try
{
if (size > 1024)
{
do
{
bc = NamedPipe.Read(outByte, bc2, size - bc2);
bc2 = bc + bc2;
}
while (bc2 < size);
}
else
{
bc = NamedPipe.Read(outByte, 0, size);
bc2 = bc;
}
}
catch { }
return outByte.Take(bc2).ToArray();
}
int i = 0;
byte[] CandleBytes = new byte[48];
bool IsStream = false;
bool IsFirstRead = true;
int BarCount = 0;
int cs = 0;
private void UpdateChart(object sender, ElapsedEventArgs args)
{
UpdateChart();
}
int size = 1024;
private void UpdateChart()
{
if (pipe != null)
{
byte[] bytes;
if (IsFirstRead)
{
bytes = ReadPipe(pipe, size);
int _cb = 0;
foreach (var b in bytes)
{
if (_cb > 3)
{
if ((bytes[_cb - 3] == 7) && (bytes[_cb - 2] == 0))
{
byte[] BarCountB = bytes.Skip(_cb - 1).Take(2).ToArray();
BarCount = BitConverter.ToInt16(BarCountB, 0);
size = (BarCount + 36) * 49;
break;
}
}
_cb++;
}
}
else
{
bytes = ReadPipe(pipe, size);
size = 1024;
}
int cb = 0;
string outStr = "";
foreach (var b in bytes)
{
if (cb > 2)
{
if ((bytes[cb - 2] == 8) && (b == 0) && (!IsStream))
{
IsStream = true;
}
}
if (IsStream)
{
if ((i >= 48) && (IsStream))
{
i = 0;
byte[] CandleBytes2 = CandleBytes;
CandleBytes = new byte[48];
IsStream = false;
byte[] dateB = CandleBytes2.Take(8).ToArray();
long dDate = BitConverter.ToInt64(dateB, 0);
if (dDate != 0)
{
DateTime pDate = (new DateTime(1970, 1, 1, 4, 0, 0, 0)).AddSeconds(Convert.ToInt64(dDate.ToString().Substring(0, 11)) - 11644488000);
byte[] OpenB = CandleBytes2.Skip(8).Take(8).ToArray();
double Open = BitConverter.ToDouble(OpenB, 0);
byte[] HighB = CandleBytes2.Skip(16).Take(8).ToArray();
double High = BitConverter.ToDouble(HighB, 0);
byte[] LowB = CandleBytes2.Skip(24).Take(8).ToArray();
double Low = BitConverter.ToDouble(LowB, 0);
byte[] CloseB = CandleBytes2.Skip(32).Take(8).ToArray();
double Close = BitConverter.ToDouble(CloseB, 0);
byte[] VolumeB = CandleBytes2.Skip(40).Take(8).ToArray();
double Volume = BitConverter.ToDouble(VolumeB, 0);
outStr += cs.ToString() + "; ";
outStr += pDate.ToString() + "; ";
outStr += Open.ToString() + "; ";
outStr += High.ToString() + "; ";
outStr += Low.ToString() + "; ";
outStr += Close.ToString() + "; ";
outStr += Volume.ToString();
outStr += Environment.NewLine;
cs++;
}
}
else
{
CandleBytes[i] = b;
++i;
}
}
++cb;
}
if (outStr != "")
{
WriteLine(outStr);
}
if ((!IsFirstRead)&&(_Timer.Interval != 200))
{
_Timer.Interval = 200;
_Timer.Start();
}
if (IsFirstRead)
{
IsFirstRead = false;
UpdateChart();
}
}
}
private void button2_Click(object sender, RoutedEventArgs e)
{
UpdateChart();
}
}
}
С разбором даты я не совсем до конца разобрался, но в таком виде корректно отображает с точностью до секунд. Ну и чтобы уж совсем автоматизировать выгрузку, можно самому формировать файлик metastok.dat - в нем содержатся параметры для выгрузки.