I received a detailed question by email concerning the operation of the algo, I'm providing most of the answer here for those interested.
From Investopedia.com, "Mean reversion is the theory suggesting that prices and returns eventually move back toward the mean or average.". The algo is effectively a mean reversion algo at heart.
EMA = exponential moving average.
RSI = relative strength index.
This dictionary:
Dictionary<string,ExponentialMovingAverage> movingAverages=new Dictionary<string,ExponentialMovingAverage>();
is central to the strategy and holds one exponential moving average indicator for every stock, 500 altogether in the algo posted, one for every stock in the S&P 500. Each Key holds a ticker symbol and the Value of each dictionary entry holds an exponential moving average indicator.
decimal lowerBandRatio=0.9m; indicates that you want to buy when a stock falls below 90% of the EMA for that stock.
decimal upperBandRatio = 1.1m; indicates that you want to sell when a stock hits 110% of the EMA for that stock.
"int maPeriod = 60;" indicates that the algo is to consider the last 60 days when calculating the EMA of each stock.
The rsisBuy and rsisSell dictionaries hold a short term RSI indicator for each stock, in a manner similar to the main moving average indicator. These RSI indicators aren't strictly necessary in a mean reversion algo but I included them to ensure that the stock has stopped falling to some extent when you buy and stopped rising to an extent when you sell. The default value of "int rsiPeriod = 3;" indicates that the RSI indicators are to consider momentum during the last 3 days.
RSI values range from 0 to 100 with 100 being strong positive momentum and 0 being strong negative momentum.
So, a value of 50 for the "decimal rsiBuyCutoff=50;" just indicates that you want to buy when the stock has stopped falling in the short term and looks like it might be turning around. A mean reversion strategy without this short term check will tend to buy stocks that are falling through the floor with no regards for negative momentum.
The "decimal rsiSellCutoff=50;" works just like the "decimal rsiBuyCutoff=50;" except that it lets the stock continue rising if the short term momentum is positive before selling.
The other dictionaries contain copies of the limit orders made, the durations that the limit orders have been in effect, and the prices of the buy orders. You shouldn't have to modify these or adjust them at all to change the strategy of the algo, and in fact you can just leave them as is and change the entire strategy of the algo by changing the dictionaries containing indicators, the code in the buy and sell functions, and the variables concerning strategy. The main purpose of these dictionaries is to hold copies of the orders until they expire, so a count for how long an order has been in existence needs to be stored for each and every order. "barsToHoldBuyOrdersFor" and "barsToHoldSellOrdersFor" indicate how long you want to keep your orders in effect for and are the only things you are likely to want to modify concerning orders.
"ratioOfDollarVolumeForMaxTrade " prevents the algo from attempting to invest too much in low dollar volume stocks. The default value of ".25m / 6.5m / 60m;" for daily resolution indicates that you don't want to invest more than 15 seconds worth of daily dollar volume. The .25 indicates a quarter of a minute, the 6.5 divides the daily dollar volume by the number of trading hours in a day, and the 60 by the number of minutes in an hour. So the average amount traded in 15 seconds of the day becomes the maximum trade size allowed by the algo.
The RoundLot function can be copied and pasted out of the algo into your own algos if you want it. It prevents 'odd lots' from being ordered by rounding off the quantity of stocks being ordered to an acceptable number. Google 'odd lot' if you are unfamiliar with this concept.