
本程序基于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只互相关度最低指数型基金进行投资,关于股市指数的相关度自动计算程序可能以后会开发。
慧定投官方给出的跟踪标的并没有我需要的指数,而每个投资周期都去手动计算投资额又过于繁琐。所以本着“重复性的劳动交给程序处理,……”这一人生哲学信条,开发了本程序以解放劳动,同时得以回馈社区。
最后再次声明:本程序不代表任何投资建议,入市自负盈亏。