Sunday, 30 September 2012

30. Japanese candlestiscks and C# - Two dimensional array

How to calculate RSI (relative strength index)?

Now, application analyses Japanese candlesticks, volumes and RSI to advise trading action. 

We'll use 2D array to calculate RSI value. If you are interested in theory of RSI please read this

http://en.wikipedia.org/wiki/Relative_strength_index

and related

http://en.wikipedia.org/wiki/Moving_average_(finance)#Simple_moving_average (SMA chapter)

Under RSI button is code which uses  values of these Excel calculation example

http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi

It is worth to have a look how it works in Excel, first.

So, now you can easier follow code. 2D table does not use all 8 columns but I did it so to be more easier to follow Excel example. Number of array rows is variable and type of data is double.

Under commented lines is code which is used for daily live trading analysis. Variable noDays is set to 14 as in Excel example. On your form you will need one button (any name) and text field rsItext. Of course, you can use string variable and change code to

string rsIstring== rsI.ToString(); // fill last value to string

and you'll need debugger to see result or you can use line such as this

 MessageBox.Show("RSI value", rsIstring)

Also, if you are interested in RSI and how it changes with different number of days (traders use different values according to their trading goals for example 2,..9,14,20)  then you can add text filed rsidayS to form and delete in bold line code( // also). With rsidayS filed change RSI will change, also.

noDays = 14; // noDays = Convert.ToInt16(rsidayS.Text);

Great example for debugger usage. :-)





And code:

    private void rsI_Click(object sender, EventArgs e)
        {   // how to calculate RSI - Relative strength index
            int noRows = 44;                            // number or days to look back
            double[,] rsiTable=new double[noRows,9];    // two dimensional array declaration with noRows rows
            rsiTable[1, 1] = 43.13; // 1 means today - table filled with test data from
            rsiTable[2, 1] = 42.66; // http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi
            rsiTable[3, 1] = 43.42;
            rsiTable[4, 1] = 44.57;
            rsiTable[5, 1] = 44.22;
            rsiTable[6, 1] = 44.18;
            rsiTable[7, 1] = 44.03;
            rsiTable[8, 1] = 45.35;
            rsiTable[9, 1] = 45.78;
            rsiTable[10, 1] = 46.45;
            rsiTable[11, 1] = 45.71;
            rsiTable[12, 1] = 46.25;
            rsiTable[13, 1] = 46.21;
            rsiTable[14, 1] = 45.64;
            rsiTable[15, 1] = 46.22;
            rsiTable[16, 1] = 46.41;
            rsiTable[17, 1] = 46.03;
            rsiTable[18, 1] = 46.00;
            rsiTable[19, 1] = 46.28;
            rsiTable[20, 1] = 46.28;
            rsiTable[21, 1] = 45.61;
            rsiTable[22, 1] = 46.03;
            rsiTable[23, 1] = 45.89;
            rsiTable[24, 1] = 46.08;
            rsiTable[25, 1] = 45.84;
            rsiTable[26, 1] = 45.42;
            rsiTable[27, 1] = 45.10;
            rsiTable[28, 1] = 44.83;
            rsiTable[29, 1] = 44.33;
            rsiTable[30, 1] = 43.61;
            rsiTable[31, 1] = 44.15;
            rsiTable[32, 1] = 44.09;
            rsiTable[33, 1] = 44.34;
     /*       for (int m = 0; m < noRows-1; m++)              // load from live data table for number of days
            {
                rsiTable[m + 1, 1] = historyArrayL[m, 2];
            }       */
            int noDays = 0;
            int firstDayForAverage = 19;
            int lastDayForAverage = 0;
            double averageGainSum=0;
            double averageLossSum=0;
            double gainAverage=0;
            double lossAverage=0;
            double rS=0;
            double rsI=0;
            double deltA = 0;
            noDays = 14; // noDays = Convert.ToInt16(rsidayS.Text);
            if (noDays * 2 + 2 > noRows) { MessageBox.Show("Too many days", "Maximum is 20"); goto kraj; }  // we have 44 days to examine
            for (int k=gloB.rowSelected+1;k<noRows-1;k++)   // calclulate loss
            {
                deltA=Math.Round(rsiTable[k,1]-rsiTable[k+1,1],2);    // close yesterday - close today
                if (deltA > 0) { rsiTable[k,3]=deltA; } // delta gain fill column 3
                if (deltA < 0) { rsiTable[k, 4] =  Math.Abs(deltA); }   // delta loss fill column for as positive value
            }
            firstDayForAverage=firstDayForAverage+gloB.rowSelected; // calculate first average day index
            lastDayForAverage=firstDayForAverage+noDays-1;      // calculate last average day index
            if (lastDayForAverage >= noRows) { MessageBox.Show("Too far in the past", "Maximum is 20"); goto kraj; } // if we are not in range
           
            for (int k = firstDayForAverage; k <= lastDayForAverage; k++)
            {
                averageGainSum = averageGainSum + rsiTable[k, 3]; averageLossSum = averageLossSum + rsiTable[k, 4]; // for numebr of days
            }
            gainAverage = Math.Round(averageGainSum / noDays,3);    //
            lossAverage = Math.Round(averageLossSum / noDays,3); // average of 20th day is calculated
            rsiTable[firstDayForAverage,5]=gainAverage;   // average gain column 5
            rsiTable[firstDayForAverage,6]=lossAverage; // average loss column 6
            if (lossAverage > 0) { rS = gainAverage / lossAverage; } else { rS = 100; }     // calc. loss avarege - value 100 is by definiton
                rsiTable[firstDayForAverage, 7] = Math.Round(rS,2);   // RS column 7
                if (rsiTable[firstDayForAverage, 6] == 0) { rsiTable[firstDayForAverage, 8] = 100; }  // calc. of first RSI value (column 8 of nth day)- value 100 is by definiton
                else{rsiTable[firstDayForAverage, 8] = Math.Round(100-(100/(1+rsiTable[firstDayForAverage, 7])) ,2);} // RSI column 8
           
            for (int k = firstDayForAverage -1; k > 0; k--)     // calculte other RSI valuse
            {
                gainAverage = Math.Round((rsiTable[k + 1, 5] * (noDays - 1) + rsiTable[k, 3]) / noDays, 3);  // previous and today  day
                lossAverage = Math.Round((rsiTable[k + 1, 6] * (noDays - 1) + rsiTable[k, 4]) / noDays,3);
                rsiTable[k, 5] = gainAverage;       // fill column 5
                rsiTable[k, 6] = lossAverage;
                rS = rsiTable[k, 5] / rsiTable[k, 6];
                if (rsiTable[k, 6] == 0) { rsI = 100; } else { rsI = Math.Round(100 - 100 / (1 + rS), 2); rsiTable[k, 8] = rsI; }   // calclulate RSI
            }

            rsItext.Text = rsI.ToString(); // fill last value to field rsIText
        kraj: ;
        }




Thursday, 20 September 2012

29. Japanese candlestiscks and C# - RichTextBox

How to have comments and use RichTextBox control? I can enter free text in commenT (control name) RichTextBox and save it for later. It means when form is loaded or activated commneT is filled with text saved in disk.

So, how to save data from RichTextBox to file. Under menu item Comments are Save and Load code.

This code is used to save content:

private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (activeIndice.Text == "") { MessageBox.Show("No indice name", "Saving error - Select indice"); goto end1; } // to save file name I need index name
            makeSaveFileName msfN = new makeSaveFileName(gloB.workingPath, activeIndice.Text, true); // fix and make file name and path
            string fileNameFull = msfN.indexPathName;
            string fileName = msfN.indexName;
            fileNameFull = fileNameFull.Replace(fileName, fileName + "Comment"); // full file name is finished
            File.WriteAllText(fileNameFull, commenT.Text); // save stream to file
        end1: ;
        }


This is code which fills RichTextBox from text file:

 private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {

            if (activeIndice.Text == "") { MessageBox.Show("No indice name", "Loading error - Select indice"); goto end1; } // to read file name I need index name
            makeSaveFileName msfN = new makeSaveFileName(gloB.workingPath, activeIndice.Text, true); // fix and make file name and path
            string fileNameFull = msfN.indexPathName;
            string fileName = msfN.indexName;
            fileNameFull = fileNameFull.Replace(fileName, fileName + "Comment"); // full name is finished
            if (File.Exists(fileNameFull))
            { commenT.Text = File.ReadAllText(fileNameFull); } // load file to form field
          
        end1: ;
        }


These codes could be under buttons, no difference.

Code for class MakeFileSaveName which fixes file name and generates filename and path. from indices's name. You can use absolute string definitions for fileNameFull and FileName and comment class:

 internal class makeSaveFileName // construct file name from global path and selected index
    {
        public makeSaveFileName(string patH, string indeX, Boolean daNe)
        {
            indeX = indeX.Replace(":", "-");
            if (daNe== true) indeX = indeX.Replace("CZ", "HR");
            indexPathName = patH + indeX + ".txt";    // make full path,file name and add .txt extension as it is text file
            indexName=indeX;
        }
        public string indexPathName { get; private set; }
        public string indexName { get; private set;}
    }


And small trick if we want to automate saving process. If we put code under event LostFocus of commenT control text we'll be saved as soon as we leave commenT field. We call the procedure under menu control (in bold).

private void commenT_LostFocus(object sender, EventArgs e)
{ saveToolStripMenuItem.PerformClick(); }