本程序基于C#控制台应用开发,二进制文件(文末附下载地址)需求支持库.NET Framework 4.6.1。主要实现了从HTTPS的JSON数据源获取结构化的股票数据,然后对数据进行分析处理,给出分析结论的功能。
先放上代码,后面再对代码进行解释。
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("输入格式有误"); } } } } }
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(); } } }
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; } } } }
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只互相关度最低指数型基金进行投资,关于股市指数的相关度自动计算程序可能以后会开发。
慧定投官方给出的跟踪标的并没有我需要的指数,而每个投资周期都去手动计算投资额又过于繁琐。所以本着“重复性的劳动交给程序处理,……”这一人生哲学信条,开发了本程序以解放劳动,同时得以回馈社区。
最后再次声明:本程序不代表任何投资建议,入市自负盈亏。
“基于C#的股票数据获取并进行基础分析的程序”上的一条回复
[…] 基于C#的股票数据获取并进行基础分析的程序 […]