标签: JSON

  • 基于C#的股票数据获取并进行基础分析的程序

    基于C#的股票数据获取并进行基础分析的程序

    本程序基于C#控制台应用开发,二进制文件(文末附下载地址)需求支持库.NET Framework 4.6.1。主要实现了从HTTPS的JSON数据源获取结构化的股票数据,然后对数据进行分析处理,给出分析结论的功能。

    先放上代码,后面再对代码进行解释。
    [code lang=”csharp” collapse=”true” title=”program.cs”]
    using System;
    using System.Collections.Generic;

    namespace FundsInvestment
    {
    class Program
    {

    static void Main(string[] args)
    {
    Console.WriteLine("!!!免责声明!!!");
    Console.WriteLine("本程序仅用于演示如何从JSON数据源获取数据,并进行基本的分析");
    Console.WriteLine("演示数据源:雪球 www.xueqiu.com");
    Console.WriteLine("演示分析算法:蚂蚁财富 慧定投");
    Console.WriteLine("自动放弃本程序版权,不收取费用或打赏,也不会对你的投资盈亏负责。");
    Console.WriteLine("PROGRAMMING BY:暂置元帅");
    Console.WriteLine("——————–");
    List<Index> list = new List<Index>(5)
    {
    new Index("SH000016"),
    new Index("SH000905"),
    new Index("SZ399006"),
    new Index("NASDAQ"),
    new Index("HKHSCEI")
    };
    foreach (var item in list)
    {
    if (item.FetchData() == true)
    {
    Console.WriteLine(item.Symbol+"拉取数据成功");
    Console.WriteLine("最近一日收盘价" + item.Close);
    Console.WriteLine(item.GetAntFortuneAlgrithmAdvice());
    }
    else
    {
    Console.WriteLine("拉取数据失败");
    }
    Console.WriteLine("——————–");
    }
    while (true)
    {
    try
    {
    Console.Write("输入股票或指数代码(SH/SZ+六位数字):");
    string symbol = Console.ReadLine();
    Console.Write("输入最后一个查询日(年/月/日):");
    DateTime endTime = DateTime.Parse(Console.ReadLine());
    Console.Write("输入往前查询天数(整数):");
    int dayCount = Int32.Parse(Console.ReadLine());
    Console.Write("基础投资额:");
    double baseLine = double.Parse(Console.ReadLine());
    Console.WriteLine("——–数据拉取中——–");

    Index myIndex = new Index(symbol, endTime, dayCount);
    myIndex.BaseLine = baseLine;
    if (myIndex.FetchData() == true)
    {
    Console.WriteLine(myIndex.Symbol + "拉取数据成功");
    Console.WriteLine("最近一日收盘价" + myIndex.Close);
    Console.WriteLine(myIndex.GetAntFortuneAlgrithmAdvice());
    }
    else
    {
    Console.WriteLine("拉取数据失败");
    }
    Console.WriteLine("——————–");
    }
    catch (Exception)
    {
    Console.WriteLine("输入格式有误");
    }

    }
    }
    }
    }
    [/code]
    [code lang=”csharp” collapse=”true” title=”Index.cs”]
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;

    namespace FundsInvestment
    {
    /// <summary>
    /// 指数类
    /// </summary>
    class Index
    {
    /// <summary>
    /// 指数符号
    /// </summary>
    public string Symbol { get; set; }

    /// <summary>
    /// 数据储存对象
    /// </summary>
    private Rootobject DataArray { get; set; }

    /// <summary>
    /// 数据结束日期时间戳
    /// </summary>
    private string EndTimeStamp { get; set; }

    /// <summary>
    /// 数据起始日期时间戳
    /// </summary>
    private string BeginTimeStamp { get; set; }

    /// <summary>
    /// 交易日数量
    /// </summary>
    private int ExchangeDayCount { get; set; }

    /// <summary>
    /// 均值
    /// </summary>
    public double MA { get { return GetMA(); } }

    /// <summary>
    /// 投资基线(默认值20元)
    /// </summary>
    private double baseLine = 20;

    /// <summary>
    /// 投资基线(默认值20元)
    /// </summary>
    public double BaseLine { get => baseLine; set => baseLine = value; }

    /// <summary>
    /// 最近一日收盘价
    /// </summary>
    public double Close
    {
    get
    {
    if(DataArray != null && DataArray.chartlist.Length != 0)
    {
    return DataArray.chartlist.Last().close;
    }
    return 0;
    }
    }

    /// <summary>
    /// 构造指数查询地址(默认从180个交易日前到今天)
    /// </summary>
    /// <param name="Symbol">指数符号</param>
    public Index(string Symbol)
    {
    this.Symbol = Symbol;
    DateTime endDay = DateTime.Today;
    //超量请求数据,填充非交易日
    DateTime beginDay = new DateTime(endDay.Ticks – new TimeSpan(180 * 2, 0, 0, 0).Ticks);
    BeginTimeStamp = GetTimeStamp(beginDay);
    EndTimeStamp = GetTimeStamp(endDay);
    ExchangeDayCount = 180;
    }

    /// <summary>
    /// 构造指数查询地址
    /// </summary>
    /// <param name="Symbol">指数符号</param>
    /// <param name="EndDay">结束日期</param>
    /// <param name="DayCount">交易日个数</param>
    public Index(string Symbol,DateTime EndDay,int DayCount)
    {
    this.Symbol = Symbol;
    DateTime endDay = EndDay;
    //超量请求数据,填充非交易日
    DateTime beginDay = new DateTime(endDay.Ticks – new TimeSpan(DayCount * 2, 0, 0, 0).Ticks);
    BeginTimeStamp = GetTimeStamp(beginDay);
    EndTimeStamp = GetTimeStamp(endDay);
    ExchangeDayCount = DayCount;
    }

    /// <summary>
    /// 拉取数据
    /// </summary>
    /// <returns>是否拉取成功</returns>
    public bool FetchData()
    {
    string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36";
    CookieContainer container = new CookieContainer();
    try
    {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.xueqiu.com");
    request.UserAgent = UserAgent;
    request.Method = "GET";
    request.CookieContainer = container;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    var jsonRequest = WebRequest.CreateHttp(BuildUri());
    jsonRequest.UserAgent = UserAgent;
    jsonRequest.CookieContainer = container;
    jsonRequest.Method = "GET";
    HttpWebResponse jsonResponse = (HttpWebResponse)jsonRequest.GetResponse();
    var stream = jsonResponse.GetResponseStream();
    var streamReader = new StreamReader(stream);
    var content = streamReader.ReadToEnd();

    DataArray = JsonConvert.DeserializeObject<Rootobject>(content);

    if(DataArray.success == "true")
    {
    return true;
    }
    else
    {
    return false;
    }
    }
    catch (Exception e)
    {
    return false;
    }
    }

    /// <summary>
    /// 获得蚂蚁财富慧定投算法推荐定投额
    /// </summary>
    public string GetAntFortuneAlgrithmAdvice()
    {
    int length = DataArray.chartlist.Length;
    if (length == 0)
    {
    return "无可供计算的数据";
    }
    string advice = string.Empty;
    double ma = GetMA();
    double indexValue = DataArray.chartlist.Last().close;
    if(indexValue > ma)
    {
    double rate = (indexValue – ma) / ma;
    advice += "当前指数值高于均线" + Math.Round((rate * 100),2) + "%,建议本轮投资";
    if (rate < 0.15)
    {
    advice += (BaseLine * 0.9) + "元";
    }
    else if(rate >= 0.15 && rate < 0.5)
    {
    advice += (BaseLine * 0.8) + "元";
    }
    else if (rate >= 0.5 && rate < 1)
    {
    advice += (BaseLine * 0.7) + "元";
    }
    else if (rate >= 1)
    {
    advice += (BaseLine * 0.6) + "元";
    }
    }
    else if(indexValue == ma)
    {
    advice += ("当前指数值等于均线,建议本轮投资" + BaseLine + "元");
    }
    else if(indexValue < ma)
    {
    double rate = (ma – indexValue) / ma;
    advice += "当前指数值低于均线" + Math.Round((rate * 100),2) + "%,";
    List<double> tenDay = new List<double>(10);
    int start = 0;
    //防止数组总长小于10
    if(length >= 10)
    {
    start = length – 10;
    }
    else
    {
    start = 0;
    }
    for (; start < length; start++)
    {
    tenDay.Add(DataArray.chartlist[start].close);
    }
    if ((tenDay.Max() / tenDay.Min()) – 1 > 0.05)
    {
    advice += "过去10日振幅大于5%,建议本轮投资";
    if(rate < 0.05)
    {
    advice += (BaseLine * 0.6) + "元";
    }
    else if(rate >= 0.05 && rate < 0.1)
    {
    advice += (BaseLine * 0.7) + "元";
    }
    else if (rate >= 0.1 && rate < 0.2)
    {
    advice += (BaseLine * 0.8) + "元";
    }
    else if (rate >= 0.2 && rate < 0.3)
    {
    advice += (BaseLine * 0.9) + "元";
    }
    else if (rate >= 0.3 && rate < 0.4)
    {
    advice += BaseLine + "元";
    }
    else if (rate >= 0.4)
    {
    advice += (BaseLine * 1.1) + "元";
    }
    }
    else if ((tenDay.Max() / tenDay.Min()) – 1 <= 0.05)
    {
    advice += "过去10日振幅小于或等于5%,建议本轮投资";
    if (rate < 0.05)
    {
    advice += (BaseLine * 1.6) + "元";
    }
    else if (rate >= 0.05 && rate < 0.1)
    {
    advice += (BaseLine * 1.7) + "元";
    }
    else if (rate >= 0.1 && rate < 0.2)
    {
    advice += (BaseLine * 1.8) + "元";
    }
    else if (rate >= 0.2 && rate < 0.3)
    {
    advice += (BaseLine * 1.9) + "元";
    }
    else if (rate >= 0.3 && rate < 0.4)
    {
    advice += (BaseLine * 2) + "元";
    }
    else if (rate >= 0.4)
    {
    advice += (BaseLine * 2.1) + "元";
    }
    }
    }
    return advice;
    }

    /// <summary>
    /// 获取均值
    /// </summary>
    /// <returns>均值</returns>
    private double GetMA()
    {
    double summary = 0;
    int length = DataArray.chartlist.Length;
    for (int i = length – ExchangeDayCount; i < length; i++)
    {
    summary += DataArray.chartlist[i].close;
    }
    return summary / ExchangeDayCount;
    }

    /// <summary>
    /// 构造指数JSON数据源请求地址
    /// </summary>
    /// <returns>请求地址</returns>
    private string BuildUri()
    {
    string requestUri = string.Empty;
    string headStr = "https://xueqiu.com/stock/forchartk/stocklist.json?";
    requestUri += headStr;
    string symbolStr = "symbol=" + Symbol;
    requestUri += symbolStr;
    requestUri += "&";
    string periodStr = "period=1day";
    requestUri += periodStr;
    requestUri += "&";
    string typeStr = "type=before";
    requestUri += typeStr;
    requestUri += "&";
    string beginStr = "begin=" + BeginTimeStamp;
    requestUri += beginStr;
    requestUri += "&";
    string endStr = "end=" + EndTimeStamp;
    requestUri += endStr;
    return requestUri;
    }

    /// <summary>
    /// 获得时间戳
    /// </summary>
    /// <param name="time">时间</param>
    /// <returns>时间戳</returns>
    private string GetTimeStamp(DateTime time)
    {
    TimeSpan timeSpan = time – new DateTime(1970, 1, 1, 0, 0, 0);
    return Convert.ToInt64(timeSpan.Ticks / 10000).ToString();
    }
    }
    }
    [/code]
    [code lang=”csharp” collapse=”true” title=”Rootobject.cs”]
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace FundsInvestment
    {
    public class Rootobject
    {
    /// <summary>
    /// 股票对象
    /// </summary>
    public Stock stock { get; set; }
    /// <summary>
    /// 查询是否成功
    /// </summary>
    public string success { get; set; }
    public Chartlist[] chartlist { get; set; }
    public class Stock
    {
    /// <summary>
    /// 股票符号
    /// </summary>
    public string symbol { get; set; }
    }
    public class Chartlist
    {
    public long volume { get; set; }
    /// <summary>
    /// 开盘价
    /// </summary>
    public double open { get; set; }
    /// <summary>
    /// 最高价
    /// </summary>
    public double high { get; set; }
    /// <summary>
    /// 收盘价
    /// </summary>
    public double close { get; set; }
    /// <summary>
    /// 最低价
    /// </summary>
    public double low { get; set; }
    /// <summary>
    /// 涨跌额
    /// </summary>
    public double chg { get; set; }
    /// <summary>
    /// 涨跌幅
    /// </summary>
    public double percent { get; set; }
    /// <summary>
    /// 换手率
    /// </summary>
    public double turnrate { get; set; }
    /// <summary>
    /// 5日均值
    /// </summary>
    public double ma5 { get; set; }
    /// <summary>
    /// 10日均值
    /// </summary>
    public double ma10 { get; set; }
    /// <summary>
    /// 20日均值
    /// </summary>
    public double ma20 { get; set; }
    /// <summary>
    /// 30日均值
    /// </summary>
    public double ma30 { get; set; }
    /// <summary>
    /// DIFF值
    /// </summary>
    public double dif { get; set; }
    /// <summary>
    /// DEA值
    /// </summary>
    public double dea { get; set; }
    /// <summary>
    /// MACD值
    /// </summary>
    public double macd { get; set; }
    public long lot_volume { get; set; }
    public long timestamp { get; set; }
    public string time { get; set; }
    }
    }
    }
    [/code]
    Program.cs类是项目自动生成的类。作为程序的入口,并对程序的执行流程进行控制。流程控制主要分为几个部分:1.声明免责信息。2.构造Index类的对象集合,处理例子数据。3.通过无限循环读取用户输入的值构造Index对象,处理特定数据。

    其中使用了Index类的两种构造方法。第一种只需输入股票符号,默认按从180个交易日前到今天进行数据获取。第二种需要输入股票符号、结束日期和交易日个数。

    Rootobject.cs类由JSON字符串通过Visual Studio 2017的“将JSON粘贴为类”功能自动生成,作为反序列化后的模板和DataModel使用。需要注意的是,某些字段的基本变量类型要定义为长整形才由足够的空间存放数据。

    Index.cs类为本程序的业务逻辑类。由构造函数负责获取拼接出股票数据源地址所需的所有参数。

    FetchData方法中使用了HttpWebRequest去获取雪球数据源地址的JSON数据,并把JSON字符串反序列化为Rootobject对象,最后判断是否正确获得数据。这里两次进行GET Request是因为数据源需要先访问主页获取到Cookies权限才能正常访问到数据。

    GetAntFortuneAlgrithmAdvice方法对指定交易日内的数据进行了遍历统计和分析。分析方法参照了蚂蚁财富的慧定投算法。

    编写这个程序的目的是为了按照慧定投的模式对我购买5只互相关度最低指数型基金进行投资,关于股市指数的相关度自动计算程序可能以后会开发。

    慧定投官方给出的跟踪标的并没有我需要的指数,而每个投资周期都去手动计算投资额又过于繁琐。所以本着“重复性的劳动交给程序处理,……”这一人生哲学信条,开发了本程序以解放劳动,同时得以回馈社区。

    最后再次声明:本程序不代表任何投资建议,入市自负盈亏。

    二进制文件