Trading Evolution

Markets are never wrong - opinions often are

RSI (relative strength index) in C#

The RSI (relative strength index) is a momentum indicator that compares the average of recent gains to average of recent losses. It is calculated using the following formula:

RSI = 100 - 100/(1 + RS)

RS = Average of x days' up closes / Average of x days' down closes.

Below is the implementation of the formula in C#:

	public class Rsi
	{
		int		_period;
		int		_valueCount;
		decimal _last;
		decimal _previousValue;
		decimal _averageGain;
		decimal _averageLoss;

		public Rsi(int period)
		{
			if (period <= 1 || 1000 < period)
				throw new ArgumentOutOfRangeException("period");

			_period = period;
		}

		public bool AddValue(decimal value)
		{
			_last = 0;

			if (_previousValue <= 0)
			{
				_previousValue = value;
				return false;
			}

			if (_valueCount < _period - 1)
			{
				if (_previousValue < value)
					_averageGain += value - _previousValue;
				else
					_averageLoss += _previousValue - value;
				_valueCount++;
				_previousValue = value;
				return false;
			}

			if (_valueCount == _period - 1)
			{
				if (_previousValue < value)
					_averageGain += value - _previousValue;
				else
					_averageLoss += _previousValue - value;
				_valueCount++;

				_averageGain   /= _period;
				_averageLoss   /= _period;
			}
			else
			{
				_valueCount++;
				if (_previousValue < value)
				{
					_averageGain = (_averageGain * (_period - 1.0m) + (value - _previousValue))/_period;
					_averageLoss = (_averageLoss * (_period - 1.0m))/_period;
				}
				else
				{
					_averageGain = (_averageGain * (_period - 1.0m))/_period;
					_averageLoss = (_averageLoss * (_period - 1.0m) + (_previousValue - value))/_period;
				}
			}

			if (_averageLoss != 0)
				_last = 100.0m - 100.0m / (1.0m + _averageGain/_averageLoss);
			else
				_last = 100;

			_previousValue = value;

			return true;
		}

		public decimal Last
		{
			get
			{
				return _last;
			}
		}
	}

 

Get latest prices from Yahoo! Finance web service using AngularJS

It is quite easy to get last price, high, low from Yahoo! Finance web service using AngularJS. The web service query looks like this:

//finance.yahoo.com/webservice/v1/symbols/:symbol/quote?format=json&view=detail

All you need to do is to initialize $resource and call 'get' method.

    $scope.getLatestPrices = function () {

        $scope.yahooFinance = $resource('//finance.yahoo.com/webservice/v1/symbols/:symbol/quote?format=json&view=detail',
                                    { callback: 'JSON_CALLBACK' },
                                    { get: { method: 'JSONP', isArray: false } });

        for (var i = 0; i < $scope.stocks.length; i++) {
            var stock = $scope.stocks[i];
            if (!!stock.Symbol) {
                $scope.yahooFinance.get({ symbol: stock.Symbol }, function (data) {

                    for (var i = 0; i < $scope.stocks.length; i++) {
                        var stock = $scope.stocks[i];
                        if (stock.Symbol.toLowerCase() == data.list.resources[0].resource.fields.symbol.toLowerCase()) {
                            stock.Price = Math.round(Number(data.list.resources[0].resource.fields.price) * 100) / 100;
                            break;
                        }
                    }
                });
            }
        }
    }

Working example can be found here: http://www.bowgett.com/Resources/Tools/PortfolioRebalancingTool.aspx

Least Recently Used (LRU) cache

C# implementation of Least Recently Used (LRU) cache with usage counter

/// <summary>
/// Least Recently Used (LRU) cache
/// </summary>
public class LRUCache<T>
{
	class CacheItem
	{
		public T Value;
		public int Count;

		public override string ToString()
		{
			return string.Format("Value:{0} Count:{1}", Value, Count);
		}
	}

	Dictionary<int, CacheItem> _data;
	int _capacity;

	/// <summary>
	/// Default Constructor
	/// </summary>
	public LRUCache(int capacity)
	{
		if (capacity <= 0)
			throw new ArgumentOutOfRangeException("capacity", "capacity must be a positive number");

		_capacity   = capacity;
		_data       = new Dictionary<int, CacheItem>(capacity);
	}

	/// <summary>
	/// Get/set value by key
	/// </summary>
	/// <param name="key"></param>
	/// <returns>default(T) if value is not found</returns>
	public T this [int key]
    {
		get
		{
			CacheItem result;

			// Return default(T) if item it not found
			if (!_data.TryGetValue(key, out result))
				return default(T);

			// Increase usage count if item is found
			result.Count += 1;
			return result.Value;
		}

		set
		{
			CacheItem result;

			// If key already exists then reset usage count and set new value
			if (_data.TryGetValue(key, out result))
			{
				// If setting the same value assume nothing happend and keep usage
				if (value.Equals(result.Value))
					return;

				result.Value = value;
				result.Count = 0;
				return;
			}

			// New key. Check capacity and drop least used key
			if (_capacity <= _data.Count)
			{
				var sortedUsage = _data.ToList();

				sortedUsage.Sort((v1, v2) => v1.Value.Count.CompareTo(v2.Value.Count));

				// Drop least used key
				_data.Remove(sortedUsage[0].Key);
			}

			_data[key] = new CacheItem() { Value = value };
		}
	}
}

 

Getting real-time data from TWS API in C#

Small code snippet to get real-time data using C# TWS API.

Here how it looks like:

Real-time data

  • Lines 13-15: Define contract (stock, futures, forex). In this case it is SPY ETF for S&P 500
  • Line 23: Connect when "Connect" button is clicked
  • Line 28: Request market data after application is connected
  • Lines 33-43: Handle real-time tick data
// Interactive Brokers fields
IBWrapper _ibWrapper;
Contract _ibContract;
int _nextTickerId = 0;

public Main()
{
	InitializeComponent();

	_ibWrapper = new IBWrapper(this);
	_ibContract = new Contract();

	_ibContract.Symbol			= "SPY";
	_ibContract.SecType			= "STK";
	_ibContract.Exchange		= "SMART";
}

private void Connect_Click(object sender, EventArgs e)
{
	_ibWrapper.ClientConnected      += IbWrapper_ClientConnected;
	_ibWrapper.TickPrice            += IbWrapper_TickPrice;

	_ibWrapper.Connect("127.0.0.1", 7496, 0);
}

private void IbWrapper_ClientConnected(object sender, EventArgs e)
{
	_ibWrapper.IBClient.reqMktData(_nextTickerId++, _ibContract, null, false, null);
}

private void IbWrapper_TickPrice(object sender, TickPriceEventArgs e)
{
	switch (e.Field)
	{
		case TickTypeEnum.Bid:
			_bidTextBox.Text = e.Price.ToString("C");
			break;
		case TickTypeEnum.Ask:
			_askTextBox.Text = e.Price.ToString("C");
			break;
		case TickTypeEnum.Last:
			_lastTextBox.Text = e.Price.ToString("C");
			break;
	}
}