Becoming really rich with C# - Luca Bolognese

Becoming really rich with C#

Luca -

☕ 6 min. read

Or maybe not, please do not hold me re­spon­si­ble if you lose money fol­low­ing this sys­tem. Having said that, it is my opin­ion that there are very few con­cepts that are im­por­tant in in­vest­ing. Three big ones are value, di­ver­si­fi­ca­tion and mo­men­tum. This post is about the lat­ter two and how to use C# to cre­ate a sim­ple trad­ing sys­tem that uses both.

Diversification is not put all your eggs in one bas­ket’ (contrary to put all of them in one bas­ket and watch that bas­ket’). I don’t be­lieve you can watch’ very much in fi­nan­cial mar­kets, so I tend to pre­fer di­ver­si­fi­ca­tion.

Momentum is a mys­te­ri­ous ten­dency of fi­nan­cial prices that have risen the most in the re­cent past, to con­tinue out­per­form­ing in the close fu­ture. In essence, buy­ing the top stocks/​sec­tors/​as­set classes tends to out­per­form buy­ing the bot­tom ones over hori­zons from three months to one year.

The idea then is to rank some as­sets (i.e. ETFs) by how fast they have risen in the past, go long the top ones and short the bot­tom ones. There are hun­dreds of vari­a­tions of this ba­sic strat­egy, we’ll add the rule that we won’t buy as­sets that are be­low their 200 days mov­ing av­er­age or sell short as­sets that are above it.

I’m writ­ing this code with VS 2010 Beta 2 (which has­n’t shipped yet). It should be triv­ial to mod­ify it to run on B1 (or maybe it does run on it al­ready). I at­tach the code and data files to this post.

struct Event {
    internal Event(DateTime date, double price) { Date = date; Price = price; }
    internal readonly DateTime Date;
    internal readonly double Price;

We’ll use this sim­ple struc­ture to load the clos­ing price for a par­tic­u­lar date. My use of in­ter­nal is kind of bizarre. Actually the whole code might look strange. It is an in­ter­est­ing (maybe un-el­e­gant) mix of ob­ject ori­en­ta­tion and func­tional pro­gram­ming.

class Summary {
    internal Summary(string ticker, string name, string assetClass,
                    string assetSubClass, double? weekly, double? fourWeeks,
                    double? threeMonths, double? sixMonths, double? oneYear,
                    double? stdDev, double price, double? mav200) {
        Ticker = ticker;
        Name = name;
        AssetClass = assetClass;
        AssetSubClass = assetSubClass;
        // Abracadabra ...
        LRS = (fourWeeks + threeMonths + sixMonths + oneYear) / 4;
        Weekly = weekly;
        FourWeeks = fourWeeks;
        ThreeMonths = threeMonths;
        SixMonths = sixMonths;
        OneYear = oneYear;
        StdDev = stdDev;
        Mav200 = mav200;
        Price = price;
    internal readonly string Ticker;
    internal readonly string Name;
    internal readonly string AssetClass;
    internal readonly string AssetSubClass;
    internal readonly double? LRS;
    internal readonly double? Weekly;
    internal readonly double? FourWeeks;
    internal readonly double? ThreeMonths;
    internal readonly double? SixMonths;
    internal readonly double? OneYear;
    internal readonly double? StdDev;
    internal readonly double? Mav200;
    internal double Price;
    internal static void Banner() {
        Console.Write("{0,-6}", "Ticker");
        Console.Write("{0,-50}", "Name");
        Console.Write("{0,-12}", "Asset Class");
        //Console.Write("{0,-30}t", "Asset SubClass";
        Console.Write("{0,4}", "RS");
        Console.Write("{0,4}", "1Wk");
        Console.Write("{0,4}", "4Wk");
        Console.Write("{0,4}", "3Ms");
        Console.Write("{0,4}", "6Ms");
        Console.Write("{0,4}", "1Yr");
        Console.Write("{0,6}", "Vol");
        Console.WriteLine("{0,2}", "Mv");
        //Console.Write("{0,6}", "Pr");
        //Console.WriteLine("{0,6}", "M200");
    internal void Print() {
        Console.Write("{0,-6}", Ticker);
        Console.Write("{0,-50}", new String(Name.Take(48).ToArray()));
        Console.Write("{0,-12}", new String(AssetClass.Take(10).ToArray()));
        //Console.Write("{0,-30}t", new String(AssetSubClass.Take(28).ToArray()));
        Console.Write("{0,4:N0}", LRS * 100);
        Console.Write("{0,4:N0}", Weekly * 100);
        Console.Write("{0,4:N0}", FourWeeks * 100);
        Console.Write("{0,4:N0}", ThreeMonths * 100);
        Console.Write("{0,4:N0}", SixMonths * 100);
        Console.Write("{0,4:N0}", OneYear * 100);
        Console.Write("{0,6:N0}", StdDev * 100);
        if (Price <= Mav200)
            Console.WriteLine("{0,2}", "X");
        //Console.Write("{0,6:N2}", Price);
        //Console.WriteLine("{0,6:N2}", Mav200);

The class Summary above is how I want to pre­sent my re­sults. A few com­ments on the code. I use Nullable be­cause some of this val­ues can be null (i.e. not enough his­tory), but I still don’t want to worry about it. It ends up work­ing rather neatly.

I also print the re­sults out to Console, which is crazy. I re­ally should be us­ing WPF/Silverlight as the pre­sen­ta­tion layer. Also the {0,4:N0} no­ta­tion might be un­fa­mil­iar to some of you, but this is how mad Console guys like my­self avoid us­ing real UI frame­works. Sometimes we print things in color too.

The real meat is in the fol­low­ing line:

LRS = (fourWeeks + threeMonths + sixMonths + oneYear) / 4;

That is our high­way to rich­ness. It’s a very elab­o­rated quant for­mula, never be­fore shown, that cal­cu­late a mag­ick rel­a­tive strength (aka mo­men­tum) fac­tor as the av­er­age of the per­for­mance of four weeks, three months, six months and one year.

class TimeSeries {
    internal readonly string Ticker;
    readonly DateTime _start;
    readonly Dictionary<DateTime, double> _adjDictionary;
    readonly string _name;
    readonly string _assetClass;
    readonly string _assetSubClass;
    internal TimeSeries(string ticker, string name, string assetClass, string assetSubClass, 
IEnumerable<Event> events) { Ticker = ticker; _name = name; _assetClass = assetClass; _assetSubClass = assetSubClass; _start = events.Last().Date; _adjDictionary = events.ToDictionary(e => e.Date, e => e.Price); }

I then built my­self a lit­tle TimeSeries class that rep­re­sents a se­ries of (date, price). I choose a dic­tio­nary to store it be­cause of my as­sump­tion that I will be ac­cess­ing it by date a lot. In ret­ro­spect, I was kind of right and kind of wrong. It does­n’t re­ally mat­ter much.

bool GetPrice(DateTime when, out double price, out double shift) {
    // To nullify the effect of hours/min/sec/millisec being different from 0
    when = new DateTime(when.Year, when.Month, when.Day);
    var found = false;
    shift = 1;
    double aPrice = ;
    while (when >= _start && !found) {
        if (_adjDictionary.TryGetValue(when, out aPrice)) {
            found = true;
        when = when.AddDays(-1);
        shift -= 1;
    price = aPrice;
    return found;

A TimeSeries can give you back the price at a par­tic­u­lar date. This looks bizarre and com­plex, but there is a rea­son for it. I might ask for a date that does­n’t have a price as­so­ci­ated with it (i.e. hol­i­days, week-ends). In such cases I want to re­turn the pre­vi­ous price which could be N days in the past.

I also want to re­turn how many days in the past I had to go, so that other cal­cu­la­tions (i.e. Return) can mod­ify their end date by the same amount. Also I might not find such a price at all, in which case I don’t want to throw an ex­cep­tion, but in­stead no­tify the caller. In ret­ro­spect, I should have used dou­ble? to sig­nify price not found’.

double? GetReturn(DateTime start, DateTime end) {
    var startPrice = 0.0;
    var endPrice = 0.0;
    var shift = 0.0;
    var foundEnd = GetPrice(end, out endPrice, out shift);
    var foundStart = GetPrice(start.AddDays(shift), out startPrice, out shift);
    if (!foundStart || !foundEnd)
        return null;
        return endPrice / startPrice - 1;

We can now go and cal­cu­late the re­turn be­tween two dates. Also the TimeSeries ob­ject needs to per­form a lit­tle more cal­cu­la­tions.

internal double? LastWeekReturn() {
        return GetReturn(DateTime.Now.AddDays(-7), DateTime.Now);
    internal double? Last4WeeksReturn() {
        return GetReturn(DateTime.Now.AddDays(-28), DateTime.Now);
    internal double? Last3MonthsReturn() {
        return GetReturn(DateTime.Now.AddMonths(-3), DateTime.Now);
    internal double? Last6MonthsReturn() {
        return GetReturn(DateTime.Now.AddMonths(-6), DateTime.Now);
    internal double? LastYearReturn() {
        return GetReturn(DateTime.Now.AddYears(-1), DateTime.Now);
    internal double? StdDev() {
        var now = DateTime.Now;
        now = new DateTime(now.Year, now.Month, now.Day);
        var limit = now.AddYears(-3);
        var rets = new List<double>();
        while (now >= _start.AddDays(12) && now >= limit) {
            var ret = GetReturn(now.AddDays(-7), now);
            now = now.AddDays(-7);
        var mean = rets.Average();
        var variance = rets.Select(r => Math.Pow(r - mean, 2)).Sum();
        var weeklyStdDev = Math.Sqrt(variance / rets.Count);
        return weeklyStdDev * Math.Sqrt(40);
    internal double? MAV200() {
        return _adjDictionary
.OrderByDescending(k => k.Key)
.Average(k => k.Value); } internal double TodayPrice() { var price = 0.0; var shift = 0.0; GetPrice(DateTime.Now, out price, out shift); return price; } internal Summary GetSummary() { return new Summary(Ticker, _name, _assetClass, _assetSubClass,
LastWeekReturn(), Last4WeeksReturn(), Last3MonthsReturn(),
Last6MonthsReturn(), LastYearReturn(), StdDev(), TodayPrice(),
MAV200()); } }

Nothing par­tic­u­larly in­ter­est­ing in this code. Just a bunch of cal­cu­la­tions. The MAV200 is the 200 days mov­ing av­er­age of clos­ing prices. It shows a more func­tional way of do­ing things. The StdDev func­tion is in­stead very im­per­a­tive.

We now can work on down­load­ing the prices. This is how you con­struct the right URL:

static string CreateUrl(string ticker, DateTime start, DateTime end) {
    return @"" + ticker + "&a="
+ (start.Month - 1).ToString() + "&b=" + start.Day.ToString() + "&c="
+ start.Year.ToString() + "&d=" + (end.Month - 1).ToString() + "&e="
+ end.Day.ToString() + "&f=" + end.Year.ToString() + "&g=d&ignore=.csv"; }


And let’s set how many con­cur­rent con­nec­tions we are go­ing to use …

ServicePointManager.DefaultConnectionLimit = 10;

On my ma­chine, set­ting this num­ber too high causes er­rors to be re­turned. I’m not sure on which side of the con­nec­tion the prob­lem lies.

We can then load all the tick­ers we want to load from a file. One of the files has Leveraged ETFs, which I want to fil­ter out be­cause they tend to pop up al­ways at the top.

var tickers =
    .Select(l => l.Split(new[] { ',' }))
    .Where(v => v[2] != "Leveraged")
    .Select(values => Tuple.Create(values[], values[1], values[2], values[3]))
var len = tickers.Length;
var start = DateTime.Now.AddYears(-2);
var end = DateTime.Now;
var cevent = new CountdownEvent(len);
var summaries = new Summary[len];

And then load all of them, mak­ing sure to make an asyn­chro­nous call so not to keep the thread busy.

for(var i = 0; i < len; i++)  {
    var t = tickers[i];
    var url = CreateUrl(t.Item1, start, end);
    using (var webClient = new WebClient()) {
        webClient.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(downloadStringCompleted); webClient.DownloadStringAsync(new Uri(url), Tuple.Create(t, cevent, summaries, i)); } } cevent.Wait();


Notice the use of a Countdown event to wait for all the thread to com­plete be­fore print­ing out the re­sults. Also no­tice the new Tuple class used to pack­age things to send around.

We can then print out the top and bot­tom 15%:

var top15perc =
        .Where(s => s.LRS.HasValue)
        .OrderByDescending(s => s.LRS)
        .Take((int)(len * 0.15));
var bottom15perc =
        .Where(s => s.LRS.HasValue)
        .OrderBy(s => s.LRS)
        .Take((int)(len * 0.15));
Console.WriteLine("TOP 15%");
foreach(var s in top15perc)
Console.WriteLine("Bottom 15%");
foreach (var s in bottom15perc)


Here is what we do when a re­quest comes back with data:

static void downloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
    var bigTuple =
(Tuple<Tuple<string, string, string, string>, CountdownEvent, Summary[], int>)
e.UserState; var tuple = bigTuple.Item1; var cevent = bigTuple.Item2; var summaries = bigTuple.Item3; var i = bigTuple.Item4; var ticker = tuple.Item1; var name = tuple.Item2; var asset = tuple.Item3; var subAsset = tuple.Item4; if (e.Error == null) { var adjustedPrices = e.Result .Split(new[] { 'n' }) .Skip(1) .Select(l => l.Split(new[] { ',' })) .Where(l => l.Length == 7) .Select(v => new Event(DateTime.Parse(v[]), Double.Parse(v[6]))); var timeSeries = new TimeSeries(ticker, name, asset, subAsset, adjustedPrices); summaries[i] = timeSeries.GetSummary(); cevent.Signal(); Console.Write("{0} ", ticker); } else { Console.WriteLine("[{0} ERROR] ", ticker); //Console.WriteLine(e.Error); summaries[i] = new Summary(ticker, name, "ERROR", "ERROR", , , , , , ,,); cevent.Signal(); } }

We first un­pack the Tuple we sent out orig­i­nally, we then ex­tract the Date and Price, cre­ate a Summary ob­ject and store it in the sum­maries ar­ray. It’s im­por­tant to re­mem­ber to Signal to the cevent in the er­ror case as well be­cause we want to print out the re­sults even if some down­load­ing failed.

And here is what you get for your ef­fort:




Barry Kelly


Indeed. This is called momentum investing, and is probably at least partially responsible for the bubbles we've seen over the past few decades.
You can read more about it here - traders at Morgan Stanley described folks who used this approach as "fast money scum":

I'm afraid there is plenty of research on this factor (as there is on value). For a summary of it read here:

You can pull up a very similar set of data points for every ETF in the U.S. Market on my website (also built in .NET)
You then sort by a number of different measures of performance and trend, and also filter the full list of ETFs to just a subset of ETFs that you track. Try it out and let me know what you think.

Lovely, I like the simplicity.
But I still like to be able to customize things even more. Then, consider my beautiful user interface :-)

take everything out and remember this statement "investment is not about timing it is about time"

Or was it the other way around? :-) :-)

Liked the new C# tricks. Thanks for sharing!

Pretty nice, but I would have gone with a scripting language for this job. I think the development speed would have been greater.

@ geo re: Pretty nice, but I would have gone with a scripting language for this job. I think the development speed would have been greater.
Can someone please explain why a scripting language would make development speed better, and any other benefits.  I've heard statements like this and am curious as to why you would choose it over something like the author used, especially when he wrote it in a console without much overhead.

Thanks for this great example on the power of C# .NET4. It has been a real eye opener for me. Amazing stuff!
It all makes sense except the Parallel For. I can see why it ends up working, but it seems less than optimal and or needlessly complex. Maybe I an missing something?
Parallel.For(0, len, i => {
   var t = tickers[i];
   var url = CreateUrl(t.Item1, start, end);
   using (var webClient = new WebClient()) {
       webClient.DownloadStringCompleted +=
                         new DownloadStringCompletedEventHandler(downloadStringCompleted);
       webClient.DownloadStringAsync(new Uri(url), Tuple.Create(t, cevent, summaries, i));
Observation 1: Surely by calling DownloadStringAsync you are handling the work of actually doing the http get to a thread in a thread pool. Doesn't this make the Parallel For redundant? The only thing that it is potentially parallelizing is the creation of the URL string which is pretty minor.
Observation 2: Surely you only need to create one WebClient object if you are going to use DownloadStringAsync as it returns immediately handing off the job to a thread in thread pool.
Observation 3: With a single WebClient you would only need a single DownloadStringCompletedEventHandler. Not a big overhead but still.
Observation 4: The using clause will call the dispose method on each WebClient. But presumably this will block until webClient.isBusy() is false. So these (potential) threads created by the  Parallel For will create a url, hand off the work of actually getting the url to a thread pool (as a result of calling DownloadStringAsync) and then block on the dispose method until the get method. Seems a bit of an overkill.
I have not actually run you code so I am not able to try my theories out! But surely this is all you need?
webClient.DownloadStringCompleted +=
                         new DownloadStringCompletedEventHandler(downloadStringCompleted);
using (var webClient = new WebClient()) {
 for(i = 0; i < len, ++i) {
   var t = tickers[i];
   var url = CreateUrl(t.Item1, start, end);
   webClient.DownloadStringAsync(new Uri(url),
     Tuple.Create(t, cevent, summaries, i));
Apoligies if the code formatting is shot!
Anyway thanks for a superb blog and apologies if I have misunderstood how WebClient.DownloadStringAsync works.

Hi Tim,
You are right. Parallel.For is unnecessary and I could have used just one WebClient.
Thanks for pointing this out.

I shouldn't speak without trying out the code. Now I did and you are half right and half wrong. Parallel.For is somehow unnecessary as you are not doing much work in there, but multiple WebClients are needed.
Something along the line of your code gives:
Unhandled Exception: System.NotSupportedException: WebClient does not support concurrent I/O operations.
  at System.Net.WebClient.ClearWebClientState()
  at System.Net.WebClient.DownloadStringAsync(Uri address, Object userToken)
  at ETFAnalyzer.Program.Main(String[] args) in C:ProjectsETFAnalyzerETFAnalyzerProgram.cs:line 238
I will change the code to use a simple for loop.

I found an explication of why the Parallel For may be useful with WebClient.DownloadStringAsync here: Basically, DownloadStringAsync is not entirely asynchronous. It does the DNS lookup *on*the*calling*thread* first. The comment at the end of the refereced url, explains why it might be still worth using a new thread to call each DownloadStringAsync even though that would appear to double the number of threads required. (There are separate IO and processing threads apparently)

0 Webmentions

These are webmentions via the IndieWeb and