半顶在途,永不止步。

分类: CSharp|C#

分类
Algorithm|算法 CSharp|C#

使用集合和高级查询计算指数或个股相关度

前言

近年来,各种互联网金融机构和基金公司一直都在教育散户投资者进行基金定时定额投资或定时不定额投资。关于基金定投的收益和风险不在本文的讨论之列,读者可自行在网上搜索。下面仅谈谈我个人关于基金定投(以下简称“定投”)的看法。

无论互金们怎么把定投吹上天都不要相信,最重要的是自己掌握复盘的方法。对历史行情复盘后发现,按照定投的方法,无论在何时买入,到某个时间点总能实现盈利。所谓Any time is the best time——只要市场行情的整体趋势是向上的即可。因此定投是比较适合没时间盯行情,又打算拿出一笔钱来进行长期投资的职场人士。

基金类型又分为很多种,依据定投的天然属性,越是波动剧烈的基金越是适合进行定投。所以,偏股类基金或者以某个指数作为投资标的的基金是最好的选择。同时,为了分散风险,即鸡蛋不放在同一个篮子里,可以同时选择多支指数/偏股基金进行定投。

要做,就要做到最好。为了最大程度的分摊风险,所选的基金行情走向应该呈现不相关甚至是负相关的关系。因为,若是选择了两只相关的基金,同时大涨固然好。若是同时大跌,又选择了定期不定额的“慧定投”模式,可能在几天之内就会把“子弹”(计划用于投资的资金)打光。所以,当选择了两只不相关的基金,在一只赚钱到达止盈线之后可以进行收割,也有更充足的“弹药”应对另一只走低的基金。

指定的两只基金的相关性还算是容易计算。抓取K线后复权的收盘价之后,用EXCEL里面的CORREL函数即可计算出来。几只基金两两之间的收盘价,辛苦一点也是可以扒拉出来的。但是几十只基金之间的呢?以及如何从中选择出相关性比较低的一种组合呢?

目标

我个人从去年就开始了第一笔定投,当时主要是结合股市常识选择了5个指数,哪些基金追踪的这些指数就不说了。上证50,代表大型公司。中证500,代表中型公司。创业板指,代表创业型公司。恒生国企指数,代表港股。纳斯达克指数,代表美股。它们之间很明显的没有互相包含关系,所以即使不用算也知道它们的平均相关性很低。但是现在正值股灾,我想在此基础上再多定投几只指数(基金),以此来调整个人的资产配置比例。适逢我人生哲学的其中一个信条就是:

“重复的事情交给机器去做,解放出劳动力来进行更有意义的创造。”

因而我编写了一个程序,专门用来计算多项卡塔尔世界杯ray雷竞技在线平台之间的平均相关性,并从中挑选出相关性最低的组合。是的,它不仅仅可以用来计算指数或股票走势的相关性。任何多项卡塔尔世界杯ray雷竞技在线平台都可以,只要每项卡塔尔世界杯ray雷竞技在线平台的卡塔尔世界杯ray雷竞技在线平台元素个数一致即可。因为本来计算相关性的公式就要求如此。

步骤

第一步,准备好卡塔尔世界杯ray雷竞技在线平台源。

我从沪深(中证)、上证、深证、港股、美股中挑选出了21个指数作为备选项。挑选的条件是能够从蚂蚁财富中买到相应的跟踪基金,并且可选的基金个数不少于两个。主题指数不参与计算,有兴趣的读者可以自行实现。然后从行情软件中下载好2017年10月16日到2018年10月16日的每日收盘价。

 

第二步,进行卡塔尔世界杯ray雷竞技在线平台清洗。

按日期(按列)码齐每个指数是最基本的。然后就会发现A股(大陆)指数、港股指数、美股指数都会出现不连续的空隙。这是由于各个证交所放假导致交易日不同而导致的。对于这些卡塔尔世界杯ray雷竞技在线平台,我采用了手工进行线性插值的方法处理。这部分卡塔尔世界杯ray雷竞技在线平台对整体的影响不大。为了避免后面涉及到对XLS文件的繁琐编程,把该sheet卡塔尔世界杯ray雷竞技在线平台单独保存为一个CSV文件。这样即可在编程的时候使用普通的文件流读取方法把卡塔尔世界杯ray雷竞技在线平台载入内存中。

第三步,建立验证卡塔尔世界杯ray雷竞技在线平台。

由于是第一次进行该类编程,还需要有一个参考标准来对比验证程序的计算结果。因此我又在EXCEL中利用CORREL公式计算了出所有21个指数两两之间的相关度。

第四步,编程。

4.1读取CSV文件,并格式化地保存进原始集合。由于文件是存储在卡塔尔世界杯雷竞技raybetapp安卓上的,而卡塔尔世界杯雷竞技raybetapp安卓的读写速度远比内存低。因此计算前先将卡塔尔世界杯ray雷竞技在线平台读入到原始集合,然后按一定的格式(类或结构体)来存储每条卡塔尔世界杯ray雷竞技在线平台是以后计算的基础。

4.2单独抽出指卡塔尔世界杯ray雷竞技在线平台标志(指数名称)保存进名称集合。后面对指数进行组合时,依据的是指数的唯一标志,即指数的名称。而带着几百条收盘价一起进行组合是没有必要且浪费资源的。输出所有读取到的指数(名称)给用户进行检查。

4.3对卡塔尔世界杯ray雷竞技在线平台标志进行两两组合。这里建立了一个递归函数,实现对输入N个元素中抽K个进行组合保存进配对集合。每种组合只出现一次,组合中无重复的元素,组合内元素无顺序区别。这样才能符合实际需求。该函数主要使用了高级的Linq查询技巧,但可能并不是时间和空间上的最优解,是一个可接受的解。

4.4求配对集合中每个组合的相关度。建立一个与CORREL函数计算方法一样的代数计算函数。遍历组合,用每个组合中元素1和2的名称在原始集合中找到对应的收盘价数组,并一同放入计算函数中计算。这里就得到了与第三步中两两指数相关度一样的结果,并可以对结果进行检验,以验证组合函数和计算函数的正确性。

4.5对卡塔尔世界杯ray雷竞技在线平台标志进行K个元素的组合。按照用户的需求,从N个元素中每次抽取进行K个元素的组合,并存放进一个新的结果集合中。

4.6遍历结果集合,组合出在每个组合(A组合)中元素的两两组合,然后从配对集合中查询出一样的组合并取出相关度放入A组合中。当查询完成时,A组合中就同时包含了K个元素和K个元素两两之间的所有相关度。这里的逻辑嵌套层次较多,文字描述不清楚可直接看代码。

4.7对结果集合中的A组合进行排序,排序依据为每个A组合的平均相关度。按用户需求数量输出A组合的内容。

4.8对用户输入的卡塔尔世界杯ray雷竞技在线平台标志(指数名称)字符串进行分割。如输入了M个指数名称则利用循环进行M次查询。每次查询寻找出所有包含当前卡塔尔世界杯ray雷竞技在线平台标志的A组合形成一个新的筛选集合,抛弃其他组合。然后下一个卡塔尔世界杯ray雷竞技在线平台标志从刚刚得到的筛选集合中查询。经过M次比较后即可得出满足用户输入最终筛选集合。然后输出给用户检验。

用法

对我而然,首先将准备好的CSV文件和编译好的IndexCorrelation.exe放在同一目录下。然后打开EXE,输入CSV的文件名。

如我想在原来已有的5个指数基础上再增加1个指数,则按6个指数一组进行组合。

这时程序会给出一共可能产生的组合个数。之后我想阅览相关性最小的10个组合。

程序会按平均相关性从小到大罗列。最后,我根据我现有的投资条件进行查询。

根据我现在的投资条件,选择添加标普500进入我的指数定投序列会是平均相关性最低的选择,但不一定是最好的选择。这是显然的,因为标普500和A股指数、港股指数都是负相关的,只和纳斯达克是正相关的,会严重拉低整个平均相关性。

后语

老读者可能会发现,在准备原始集合的部分,完全可以参照《基于C#的股票卡塔尔世界杯ray雷竞技在线平台获取并进行基础分析的程序》一文中的程序,从网上直接下载指数卡塔尔世界杯ray雷竞技在线平台。是的,如果只是用于分析证券市场卡塔尔世界杯ray雷竞技在线平台的相关性的确可以这样做。我目前使用文件导入的做法是为了方便后面可以对其他类型的卡塔尔世界杯ray雷竞技在线平台进行分析。有心的读者可以自行拼接这两个程序。

鉴于本文中的程序大量地使用了集合、泛型、Linq查询等技术。即使不用于进行相关性分析的读者也可以参考其中的编程技巧。再次声明,程序中的所有解法不一定是时间度量和空间度量上的最优解,只是我可以接受的解。

集合(数组)在使用过程中,一定要注意越界访问的问题。我作为编程人员和使用者,会自然而然地只输入合法的条件进入程序。感兴趣的读者可以自行检查所有可能会发生越界访问的地方。

IndexCorrelation

分类
CSharp|C#

基于C#的股票卡塔尔世界杯ray雷竞技在线平台获取并进行基础分析的程序

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

先放上代码,后面再对代码进行解释。

using System;
using System.Collections.Generic;

namespace FundsInvestment
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("!!!免责声明!!!");
            Console.WriteLine("本程序仅用于演示如何从JSON卡塔尔世界杯ray雷竞技在线平台源获取卡塔尔世界杯ray雷竞技在线平台,并进行基本的分析");
            Console.WriteLine("演示卡塔尔世界杯ray雷竞技在线平台源:雪球 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+"拉取卡塔尔世界杯ray雷竞技在线平台成功");
                    Console.WriteLine("最近一日收盘价" + item.Close);
                    Console.WriteLine(item.GetAntFortuneAlgrithmAdvice());
                }
                else
                {
                    Console.WriteLine("拉取卡塔尔世界杯ray雷竞技在线平台失败");
                }
                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("--------卡塔尔世界杯ray雷竞技在线平台拉取中--------");

                    Index myIndex = new Index(symbol, endTime, dayCount);
                    myIndex.BaseLine = baseLine;
                    if (myIndex.FetchData() == true)
                    {
                        Console.WriteLine(myIndex.Symbol + "拉取卡塔尔世界杯ray雷竞技在线平台成功");
                        Console.WriteLine("最近一日收盘价" + myIndex.Close);
                        Console.WriteLine(myIndex.GetAntFortuneAlgrithmAdvice());
                    }
                    else
                    {
                        Console.WriteLine("拉取卡塔尔世界杯ray雷竞技在线平台失败");
                    }
                    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>
        /// 卡塔尔世界杯ray雷竞技在线平台储存对象
        /// </summary>
        private Rootobject DataArray { get; set; }

        /// <summary>
        /// 卡塔尔世界杯ray雷竞技在线平台结束日期时间戳
        /// </summary>
        private string EndTimeStamp { get; set; }

        /// <summary>
        /// 卡塔尔世界杯ray雷竞技在线平台起始日期时间戳
        /// </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;
            //超量请求卡塔尔世界杯ray雷竞技在线平台,填充非交易日
            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;
            //超量请求卡塔尔世界杯ray雷竞技在线平台,填充非交易日
            DateTime beginDay = new DateTime(endDay.Ticks - new TimeSpan(DayCount * 2, 0, 0, 0).Ticks);
            BeginTimeStamp = GetTimeStamp(beginDay);
            EndTimeStamp = GetTimeStamp(endDay);
            ExchangeDayCount = DayCount;
        }

        /// <summary>
        /// 拉取卡塔尔世界杯ray雷竞技在线平台
        /// </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 "无可供计算的卡塔尔世界杯ray雷竞技在线平台";
            }
            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卡塔尔世界杯ray雷竞技在线平台源请求地址
        /// </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类的对象集合,处理例子卡塔尔世界杯ray雷竞技在线平台。3.通过无限循环读取用户输入的值构造Index对象,处理特定卡塔尔世界杯ray雷竞技在线平台。

其中使用了Index类的两种构造方法。第一种只需输入股票符号,默认按从180个交易日前到今天进行卡塔尔世界杯ray雷竞技在线平台获取。第二种需要输入股票符号、结束日期和交易日个数。

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

Index.cs类为本程序的业务逻辑类。由构造函数负责获取拼接出股票卡塔尔世界杯ray雷竞技在线平台源地址所需的所有参数。

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

GetAntFortuneAlgrithmAdvice方法对指定交易日内的卡塔尔世界杯ray雷竞技在线平台进行了遍历统计和分析。分析方法参照了蚂蚁财富的慧定投算法。

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

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

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

二进制文件

分类
CSharp|C#

dot Net体系命名指引——第二节:选词规则

.net 体系命名指引

第二节 选词规则

原则一:选择易读性强的命名方式。

解释:当名称由多个单词组成时,以可读性最强的方式排列它们。

例子:当需要命名一个表格形式的视图容器成员变量时,使用GridView可以比ViewGrid更清晰的定义这个变量。因为“View”既可以作为名词,也可以作为动词。当作为后者时,容易与函数命名的“动词+名词”模式搞混。

原则二:易读性优于缩略性。

解释:诚然使用较短的名称能够缩短每行代码的长度,但它不应该以牺牲易读性为前提。

例子:理科公式中很多量使用了单个西文字母表示,当需要将这些公式编程为函数时,这些量应该用其本来代表的实际意义来表示,至少也要用其读音来表示希腊字母。例如“ω”在某些公式中代表角度,这个量应该命名为Angle,至少也要命名为Omiga,而不是一个“w”。

原则三:尽量只用“英文字母和数字”的字符。

解释:即使某些语言允许使用除了英文字母和数字之外的字符来命名,也要少用。一定要用也要有统一的规则。

例子:为界面上的控件——“确定”按钮命名时,使用BtnConfirm已经能够清晰地分割“按钮”和“确定”两个语义。但是,有时Btn_Confirm这样的命名方式更快地传达出这是一个UI控件的成员,通常由模板生成的,不能自由删改。

原则四:彻底抛弃匈牙利命名法。

解释:使用帕斯卡命名法和驼峰命名法已经足够对付dot Net体系的程序元素。首先目前宇宙最强大的IDE——Visual Studio 2017已经能够非常娴熟地对付类型不匹配等早期错误。然后匈牙利命名法和帕斯卡命名法是完全冲突的。

例子:虽然不应该严格遵守匈牙利命名法,但是其中某些要素是可以吸收改造的。可以使用Is、Can等含有是否、能否语义的单词来代替b组合一个布尔型变量,如使用IsOpen而不是bOpen

原则五:不使用被各种编程语言广泛作为关键字的单词。

解释:很明显这会和编程语言本身产生语义级别的冲突。需要注意的是,C#的关键字就有一百多个。

例子:readonly是关键字之一,所以表示一个只读的变量时,使用IsReadonly

关于缩略语

不要自定缩略语。尤其是自定的缩略语会和已有的单词产生歧义。

尽量少使用缩略语,即使要使用缩略语,也要用被广泛接受的缩略语。

关于语言特有的命名

关注语义去命名而不是语言特性关键字。

例如GetLengthGetSizeGetCount是不同类里面的方法,返回的是一个整型的变量。这时使用前三者而不是GetInt更好。

使用一些常见的名字,如valueitem,而不是将成员和类型的名字起得一样。除非这个成员没有明显的语义,或者作为函数参数来说它的类型不重要。

分类
CSharp|C#

dot Net体系命名指引——第一节:命名法与分词

.net 体系命名指引

第一节 命名法与分词

帕斯卡命名法

所有单词的首字母大写

PascalCasing

只由一个单词构成

Seed

单词只由一个字母构成

CSharp

由两个单词的首字母缩写的词,都作大写

IPAddress

由大于两个单词的首字母缩写的词,只大写第一个字母

NbaStars

不是由首字母缩写的词,也只大写第一个字母

IdCard

驼峰命名法

除第一个单词首字母小写外,其余单词首字母大写

camelCasing

只由一个单词构成

value

单词只由一个字母构成

ePay

由两个单词的首字母缩写的词,都作小写

uiFramework

由大于两个单词的首字母缩写的词,都作小写

cssBuilder

不是由首字母缩写的词,都作小写

lvHolding

合成词的处理

计算机科学专业英语中,有很多常见的合成词。即能从一个单词中明显拆分出两个或以上的独立单词。

该合成词已被权威英语词典收录时,按一个单词处理

Password/password

否则按多个单词处理

UserName/userName

至于按哪本权威词典算,由组织内部决定,牛津、柯林斯等都可以。

美式英语偏好

由于编程语言由美国公司或组织发明、维护、贡献较多,且美式英语单词往往比英式英语更短,所以偏好使用美式英语词汇。

color colour

大小写敏感性

不同的语言对大小写敏感的支持不同。因此,不能以大小写的不同来区分不同的内容。

分类
CSharp|C# Web|网页

使用CEF作为桌面应用UI开发框架的分析

在本人编写的几个上位机程序中,程序界面部分多数使用WinForm作为开发框架。WinForm框架的基本容器单位为窗体,即“Form”。每个窗体中包含了若干个不同种类的控件,即“Control”。控件分为卡塔尔世界杯ray雷竞技在线平台类、容器类等。窗体和控件执行了不同的事件,如“单击”、“右击”等,会触发相应的回调函数,以此实现交互功能。创建每个窗体后,按照框架预定义的规则会生成Form.designer.cs及Form.cs两个不同的文件。这两个文件实质上属于同一个类(Class),由partial关键词划分。前者主要包含了该窗体及其中的控件的声明和定义代码,由框架自动生产。后者为使用者实际编码处理具体逻辑区域。

使用WinForm的好处是在界面外观要求不高的情况下,可以十分快速地在所见即所得式的界面编辑器通过拖拽控件的方式实现界面布局。然后在控件属性页中静态地定义每个控件的各项属性,在控件事件页中指定控件能够产生的每个动作对应的回调函数。以上方便之处,得益于WinForm框架预先已对这些控件作出了标准化处理。

当需要实现较为高级的界面功能时,WinForm的弱点就会凸显出来。如当程序运行于不同分辨率屏幕的时候,界面往往不能与在生产环境中保持一致。当某个控件中的文本内容过长时,会超出容器边界或被右方控件遮盖。正确的处理方法应该是将超出部分文本换行,并下移下方控件位置。

还有许多如界面主题、动画效果等高级界面功能在WinForm中较难实现。虽然从编程角度上看,这些功能的确可以通过对WinForm进行底层绘图级别的扩展和补充一一实现,但是解决这些属于框架先天设计的问题往往需要耗费大量的时间和精力。

引入CEF(Chromium Embedded Framework)作为应用程序UI框架。CEF实质上是一个谷歌浏览器的内核。与WinForm框架中自带的WebView控件不同的是,WebView的内核是IE,对HTML特性的支持十分糟糕。而CEF的WebKit内核能够良好地支持HTML 5特性。

得益于互联网尤其是移动互联网的快速发展和社区的力量,以Bootstrap、Foundation和Semantic UI为代表的一系列开源前端框架已经在HTML+CSS+JS的体系中将UI功能开发得十分成熟。其常用控件种类上能够基本满足桌面程序的要求。从美观角度上看,这些标记式的界面框架完全优于一众传统的代码式的界面框架。从运行性能上看,以Web为主要应用场景的UI实现方式天生需要适应不同的软硬件环境,所以在性能优化上已经有了长足的积累,在处理复杂特效时有比同样是标记式界面框架的WPF有更多的优势。

CEF代替Form作为前端界面的容器,界面由WEB技术实现,而事务逻辑仍然由C#实现这种开发方式与移动端的Hybird APP有着很多相似之处,后者已经以WEB+JAVA或WEB+Objectiv-C的实现方式得到了业界的大量运用。