Простая визуалиция фондового рынка

Блог 06 сентября 2019

Создаем в Visual Studio WPF проект, назовем его Collector.

В файл MainWindow.xaml копипастим следующий код:
<Window x:Class="Collector.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Collector"
        mc:Ignorable="d"
        Title="Collector.exe" Height="720" Width="1380">
    <Grid Margin="0,0,0,0" Height="700" Width="1380">
        <Button x:Name="button1" Content="Download" HorizontalAlignment="Left" Height="32.699" Margin="603.267,646,0,0" VerticalAlignment="Top" Width="102.768"/>
        <Button x:Name="button2" Content="Open file" HorizontalAlignment="Left" Height="32.699" Margin="816.589,646,0,0" VerticalAlignment="Top" Width="102.768"/>
        <Label x:Name="label1" Content="Symbol" HorizontalAlignment="Left" Height="32.699" Margin="30.256,646,0,0" VerticalAlignment="Top" Width="59.17"/>
        <Label x:Name="label2" Content="Date" HorizontalAlignment="Left" Height="32.699" Margin="277.833,646,0,0" VerticalAlignment="Top" Width="63.841"/>
        <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="24.913" Margin="117.453,646,0,0" TextWrapping="Wrap" Text="SBER" VerticalAlignment="Top" Width="94.983"/>
        <TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="24.913" Margin="359.131,646,0,0" TextWrapping="Wrap" Text="2019.08.06" VerticalAlignment="Top" Width="94.983"/>
        <WebBrowser x:Name="web1" HorizontalAlignment="Left" Height="640" VerticalAlignment="Top" Width="1380"/>

    </Grid>
</Window>
А в файл MainWindow.xaml.cs :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Text.RegularExpressions;
using System.Xml;
using System.IO;
using System.Configuration;
using System.Web;
using System.Net;
using Microsoft.Win32;

namespace Collector
{
    public partial class MainWindow : Window
    {
        static string sLogFile = "collector.log";

	//загружаем хтмл-визуализатор в веб-браузер контрол
        public MainWindow()
        {
            InitializeComponent();

            button1.Click += btn1_Click;
            button2.Click += btn2_Click;

            string sDir = AppDomain.CurrentDomain.BaseDirectory;
            web1.Navigate("file:///" + sDir + "test_graph.htm");
        }

	//загружаем веб-страницу с котировками с сайта kyptrader.ru, меняем расположение колонок, сохраняем в файл
        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            string sym = textBox1.Text;
            string dat = textBox2.Text;

            string url = "http://kyptrader.ru/Quotes/Look?Code=" + sym + "&Date=" + dat;
            string data = RestGet(url);
            if (string.IsNullOrEmpty(data))
            {
                log("error reading " + url);
                MessageBox.Show("error reading " + url);
                return;
            }

            string sFile = sym + "_" + dat + ".csv";
            StreamWriter sw = new StreamWriter(sFile, false, Encoding.GetEncoding(1251));

            string ord = @"<tr><td>(.*?)<\/td><td>(.*?)<\/td><td>(.*?)<\/td><\/tr>";
            Regex reg = new Regex(ord, RegexOptions.Singleline);
            var cols = reg.Matches(data);
            double dStep = 0, dMax = 0, dMin = 0, dStart = 0, dEnd = 0, d, dPrev = 0, dif;
            int i = 0;
            foreach (Match m in cols)
            {
                if (m.Groups.Count == 4)
                {
                    sw.WriteLine(string.Format("{0};{1}", m.Groups[2].Value, m.Groups[1].Value));
                    bool bSuc = double.TryParse(m.Groups[2].Value, out d);
                    if (!bSuc) bSuc = double.TryParse(m.Groups[2].Value.Replace(".", ","), out d);
                    if (bSuc)
                    {
                        if (i == 0)
                        {
                            dStart = d;
                            dMax = d;
                            dMin = d;
                        }
                        else
                        {
                            if (dMax < d) dMax = d;
                            if (dMin > d) dMin = d;
                            dif = Math.Abs(d - dPrev);
                            if (dStep < dif) dStep = dif;
                        }
                        dEnd = d;
                        dPrev = d;
                        i++;
                    }
                }
            }
            sw.Close();

            string res = string.Format("{6}: n={0} dStart={1} dEnd={2} dStepMax={3} dMax={4} dMin={5}", i, dStart, dEnd, dStep, dMax, dMin, sFile);
            log(res);
            MessageBox.Show(res);
        }

	//загружаем файл в визуализатор
        private void btn2_Click(object sender, RoutedEventArgs e)
        {
            string res, data;
            OpenFileDialog openFileDialog = new OpenFileDialog();
            if (openFileDialog.ShowDialog() == true)
            {
                data = File.ReadAllText(openFileDialog.FileName);
                web1.InvokeScript("ext_load", data);
                res = Analyze(data, 15);
                web1.InvokeScript("ext_alert", res);
            }
        }

	//логируем
        static void log(String s)
        {
            try
            {
                StreamWriter sw = new StreamWriter(sLogFile, true, Encoding.GetEncoding(1251));
                sw.WriteLine(string.Format("{0:yyyy-MM-dd HH:mm:ss} {1}", DateTime.Now, s));
                sw.Close();
            }
            catch (Exception se)
            {
                Console.WriteLine(se.Message);
            }
        }

        //считать веб-страницу
        static string RestGet(string url)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            string result = null;
            using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
            {
                StreamReader reader = new StreamReader(resp.GetResponseStream());
                result = reader.ReadToEnd();
            }
            return result;
        }

	//анализируем данные
        private string Analyze(string data, int inGroup)
        {
            string res = "done";
            double dStep = 0, dMax = 0, dMin = 0, dStart = 0, dEnd = 0, d, dPrev = 0, dif;
            string[] arr = data.Split('\n');
            int len = arr.Length / inGroup;
            double[] y = new double[len];


            return res + arr.Length;
        }
    }
}
Компилируем. В папку с выполняемым файлом добавляем страницу test_graph.htm со следующим кодом:
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Files compare</title>
    <style type="text/css">
        body { background-color:#fff; }
        #file1 { width: 45%; height:100px; margin-right:10px; float:left; border:1px solid #ccc; }
        #result  {width: 45%; height: 100px; float:left; border:1px solid #ccc;}
        #canvas1 { border:1px solid #cfc; }
    </style>
    <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
</head>
<body onload="my_onload()">
    <div id="1">Fill a box with data, click "Show".</div>
    <textarea id="file1">219.87;10:00:00
219.91;10:00:02
220.33;10:00:36</textarea>
scale <input id="scale" type="text" />
    <a href="#" onclick="return show();">Show</a>
    <div id="result">results</div>
    <div style="clear:both;"></div>
    <canvas id="canvas1" width="800" height="600"></canvas>

<script type="text/javascript">
    function my_onload() {
        return false;
    }
    function show() {
        var scale = $("#scale").val();
        var s1 = $("#file1").val();
        var arr1 = s1.split("\n");

        var iScale = parseInt(scale, 10);
        if( isNaN(iScale) || iScale < 1 || iScale > 1000 ) iScale = 1;
        var len = parseInt("" + arr1.length / iScale, 10);
        if( len < 1 ) {
            $("#result").html("bad totlen=" + arr1.length);
            return;
        }

        var dd = new Array();
        var y0 = 1, y1 = 1;
        for (var j = 0; j < 100000 && j < arr1.length; j++) {
            var aa = arr1[j].split(";");
if(aa.length <= 1 ) { break; }
            var y = aa[0] * 1;
            if( j == 0 ) {
                y0 = y;
                y1 = y;
            }
            else {
                if( y0 > y ) y0 = y;
                if( y1 < y ) y1 = y;
            }
            dd.push(y);
        }
        var extra = (y1 - y0) * 0.01;
        y0 -= extra;
        y1 += extra;
        $("#result").html("totlen=" + arr1.length + ", scale=" + iScale + ", len=" + len + ", y0=" + y0 + ", y1=" + y1 + ",extra=" + extra);

        //calc sliding average - long
        var dd_2 = new Array();
        var sum = 0, slide = iScale * 20;
        for (var j = 0; j < 100000 && j < dd.length; j++) {
            sum += dd[j];
            if( j >= slide)
                sum -= dd[j - slide];
            dd_2.push(sum / (j < slide ? (j + 1) : slide));
        }

        //calc sliding average - short
        var dd_3 = new Array();
        sum = 0;
        slide = iScale * 5;
        for (var j = 0; j < 100000 && j < dd.length; j++) {
            sum += dd[j];
            if( j >= slide)
                sum -= dd[j - slide];
            dd_3.push(sum / (j < slide ? (j + 1) : slide));
        }

        //prepare canvas
        var cnv = document.getElementById("canvas1");
        cnv.width = 2*len + 1;
        GRAPHIX.AX_CL = "#ffff00";
        GRAPHIX.PADDING = 0;
        GRAPHIX.drawAxes('canvas1');

        //draw our data
        var iDisplay = iScale - 1;
        var opt2 = { "x0": 0, "x1": 2*len, "y0": y0, "y1": y1, "color": "#ff0000", "style": "line" };
        var data2 = new Array();
        for (var j = 0; j < 100000 && j < dd.length; j++) {
            if( j % iScale == iDisplay ) {
                var x = j / iScale;
                var y = dd[j];
                data2.push(new Array(2*x, y));
            }
        }
        GRAPHIX.drawData('canvas1', data2, opt2);
        if( iScale == 1) return false;
        
        //draw average
        var opt3 = { "x0": 0, "x1": 2*len, "y0": y0, "y1": y1, "color": "#ff00ff", "style": "line" };   //average iScale
        var opt4 = { "x0": 0, "x1": 2*len, "y0": y0, "y1": y1, "color": "#ffffff", "style": "line" };   //long slide
        var opt5 = { "x0": 0, "x1": 2*len, "y0": y0, "y1": y1, "color": "#00ff00", "style": "line" };   //short slide
        var data3 = new Array();
        var data4 = new Array();
        var data5 = new Array();
        var yav = 0;
        for (var j = 0; j < 100000 && j < dd.length; j++) {
            yav += dd[j];
            if( j % iScale == iDisplay ) {
                var x = j / iScale;
                data3.push(new Array(2*x, yav / iScale));
                yav = 0;
                data4.push(new Array(2*x, dd_2[j]));
                data5.push(new Array(2*x, dd_3[j]));
            }
        }
        //GRAPHIX.drawData('canvas1', data3, opt3);
        GRAPHIX.drawData('canvas1', data4, opt4);
        GRAPHIX.drawData('canvas1', data5, opt5);
        return false;
    }
    function ext_load(w) {
        //alert(w);
        $("#file1").val(w);
    }
    function ext_alert(w) {
        //alert(w);
        $("#result").html(w);
    }

    //простой модуль для рисования графиков на "холсте" 
    if (typeof GRAPHIX == "undefined") {
        GRAPHIX = {
            PADDING: 20,        //отступ
            AX_BG: "#000000",   //фон
            AX_CL: "#00FF00",   //цвет осей
            //залить фон, нарисовать оси
            drawAxes: function(canvas) {
                var cnv = document.getElementById(canvas);
                var w = cnv.width;
                var h = cnv.height;
                var ctx = cnv.getContext('2d');
 
                ctx.fillStyle = this.AX_BG;
                ctx.fillRect(0, 0, w, h);
                ctx.strokeStyle = this.AX_CL;
                ctx.lineWidth = 1;
                //ctx.beginPath();
                ctx.moveTo(this.PADDING, 0);
                ctx.lineTo(this.PADDING, h);
                ctx.stroke();
                ctx.moveTo(0, h - this.PADDING);
                ctx.lineTo(w, h - this.PADDING);
                ctx.stroke();
            },
            //отобразить данные
            drawData: function(canvas, data, opt) {
                var cnv = document.getElementById(canvas);
                var w = cnv.width - this.PADDING;
                var h = cnv.height - this.PADDING;
                var x0 = opt.x0;
                var x1 = opt.x1;
                var y0 = opt.y0;
                var y1 = opt.y1;
                var dx = (x1 - x0);
                var dy = (y1 - y0);
 
                var ctx = cnv.getContext('2d');
                ctx.lineWidth = 1;
                ctx.strokeStyle = opt.color;
                ctx.fillStyle = opt.color;
                ctx.beginPath();
       
                for (var i = 0; i < data.length; i++) {
                    var r = data[i];
                    var x = r[0];
                    var y = r[1];
                    var l = w * (x - x0) / dx + this.PADDING;
                    var m = h - h * (y - y0) / dy - this.PADDING;
 
                    if (opt.style == "dots") {
                        ctx.fillRect(l, m, 3, 3);
                    }
                    else if (opt.style == "hist") {
                        ctx.moveTo(l, h);
                        ctx.lineTo(l, m);
                        ctx.stroke();
                    }
                    else if (opt.style == "line") {
                        if (i == 0) ctx.moveTo(l, m);
                        else {
                            ctx.lineTo(l, m);
                        }
                    }
                }
                if (opt.style == "line") ctx.stroke();
            },
            //отобразить текст
            drawTile: function(canvas, title, x, y, color, size) {
                var cnv = document.getElementById(canvas);
                var ctx = cnv.getContext('2d');
                ctx.fillStyle = color;
                ctx.font = size + "px Verdana";
                ctx.fillText(title, x, y);
            }
        }
    }

</script>
</body>
</html>
Имея такое приложение, мы можем загружать файлы с котировками с сайта kyptrader.ru , 
а потом делать из них графики


Но предварительно надо настроить отображение html5 в WebBrowser компоненте 
(https://www.codeproject.com/Questions/707214/how-make-my-csharp-web-browser-to-support-html5). 
В регистре 
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
            For 32bit OS

            *******OR*******

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
            For 64bit OS

надо создать DWORD с именем Collector.exe, а потом писвоить значение 11001 decimal 
(если не заработало, то пробуйте 10001). 
Танцы с бубном никто не отменял.

Теги: Visual Studio, WPF, canvas, html5, визуалиция фондового рынка


Комментарии

Комментариев еще нет.
Добавить комментарий могут только авторизованные пользователи. Авторизоваться
Комментарий

Оценка





Авторизоваться через https://www.pvobr.ru
Логин
Пароль
Регистрация

Авторизоваться через соцсети
Наверх