Monday, June 27, 2022

Day 13/100 Stock Trader

 Day 13/100 Stock Trader

3 White Soldiers and 3 Black Crows


Trading stock can be fun and profitable, but you do need to know what you're doing, or else, you will lose all hopes to achieving dreams beyond your avarice. I suppose you know about hi-lo charts as used in the stock market. I use them, too. However, that's not very interesting. Much more interesting, from learning to code point of view, is the candlestick chart.


The wick/tail ends indicates high/low of the day, and the bar indicates the open and close prices of the day. White means closing is higher than open. Black means open is higher than closing. Perfectly simple concept that is really suitable for sightings.


The hi-lo chart is really a single line with 2 branches on either side of the line. It takes just as much space as candlestick, but much, much less visible. Take a look at a sample of the candlestick chart:





Looks like $NFLX is having a bad time lately! Such a shame with all the new shows, too. Anyway, you can easily see the rising prices and the declining prices. 3 white bars in a row are white soldiers, indicating future prosperity. 3 black bars in a row are the black crows, indicating bad times ahead. Unfortunately, I see multiple crows on the chart.


The code to draw the candlestick chart is rather involved, as compared to the previous effort. Fortunately, it's rather easy to do, just time consuming due to the amount of data being processed.


void SVGCandleStick(int n, float o, float h, float l, float c) {
  int by=20;
  float b,t;
  int ay;
  float r;

  o=map(tmin,o,tmax,35,110);
  h=map(tmin,h,tmax,35,110);
  l=map(tmin,l,tmax,35,110);
  c=map(tmin,c,tmax,35,110);

  ay=by+(n*3);
  b=(o>c)?c:o;
  t=(o>c)?o:c;

  SVGDrawLine(30,ay+1,33,ay+1);

  SVGDrawLine(l,ay+1,b,ay+1);
  SVGDrawLine(t,ay+1,h,ay+1);
  SVGDrawLine(b,ay,t,ay);
  SVGDrawLine(b,ay+2,t,ay+2);
  SVGDrawLine(b,ay,b,ay+2);
  SVGDrawLine(t,ay,t,ay+2);
  if (o>c)
    for (r=0.0;r<=2.0;r+=0.25) {
      SVGDrawLine(b,ay+r,t,ay+r);
    }

}


The first part of the function is to scale the chart appropriately. I simply use millimeters for measuring since it's such a convenient scale. Using inches will be even more time consuming!


Then I draw the marks on the horizontal axis. This is followed by the candlestick drawing itself. 2 lines for top and bottom and 4 lines for the candlestick itself. Finally, if open is greater than closing, fill up the box with black.


It's more complicated than just drawing a rectangle because the direction of the line drawn matters. The output isn't the screen. Well, it does go to the screen, but I also want to make the output to be compatible with a plotter. That's why I purposely set the direction to draw to the higher X axis direction, never to the opposite direction.


This will be more obvious on the next project. However, I will stop here for now. As it is, I simply didn't bother cleaning up the program. Most likely, I will need to visit this program later. Once I set up graphical user interface, that is.



#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define MAXSTR 256
#define MAXENTRY 10000

int Debug=0;
float min=5.0;
float max=20000.0;
int sca=20;
char scan[MAXSTR];
int tstamp=0;
int dir=0;
float val=-1;
int slot,lslot;

char Date[MAXENTRY][MAXSTR];
float Open[MAXENTRY];
float High[MAXENTRY];
float Low[MAXENTRY];
float Close[MAXENTRY];
float Adj[MAXENTRY];
float Volume[MAXENTRY];
float tmin=20000.0;
float tmax=0.0;
int numentry=0;

void ShowMsg() {
puts("
Usage: pnf [OPTION]...
Display Point and Figure chart given a stock.csv file.
Min and Max values are not automatically adjusted!
Default values are:
      -nN      minimum value. Default N0
      -xN      maximum value. Default N200
      -sN      scales. Default N20
      --help     display this help and exit
      --debug    debug info
");
}

int GetOpt(int argc, char *argv[]) {
int i;
  for (i=1;i<argc;i++) {
    if (!strncmp("-n",argv[i],2)) min=atof(argv[i]+2);
    if (!strncmp("-x",argv[i],2)) max=atof(argv[i]+2);
    if (!strncmp("-s",argv[i],2)) sca=atoi(argv[i]+2);
    if (!strncmp("--help",argv[i],6)) {
      ShowMsg(); return 0;
    }
    if (!strncmp("--debug",argv[i],7)) Debug=1;
  }

  if (Debug) {
    puts("Debug...");
    printf("Min: %0.2f\n",min);
    printf("Max: %0.2f\n",max);
    printf("Scale: %d\n",sca);
  }
  return 0;
}


float map(float x0,float x1, float x2,float y0, float y2) {
  return y0+((x1-x0)*(y2-y0)/(x2-x0)); //y1
}

void SVGDrawLine(float x0,float y0,float x1,float y1) {
  int t;
  if (y0>y1) { t=y0; y0=y1; y1=t;
               t=x0; x0=x1; x1=t; }
  printf("<line x1=\"%.2f\" y1=\"%.2f\" x2=\"%.2f\" y2=\"%.2f\" />\n",
         x0,y0,x1,y1);
}


void SVGDrawHeader() {
  SVGDrawLine(30,16,114,16);
  SVGDrawLine(30,16,30,177);
}

void SVGCandleStick(int n, float o, float h, float l, float c) {
  int by=20;
  float b,t;
  int ay;
  float r;

  o=map(tmin,o,tmax,35,110);
  h=map(tmin,h,tmax,35,110);
  l=map(tmin,l,tmax,35,110);
  c=map(tmin,c,tmax,35,110);

  ay=by+(n*3);
  b=(o>c)?c:o;
  t=(o>c)?o:c;

  SVGDrawLine(30,ay+1,33,ay+1);

  SVGDrawLine(l,ay+1,b,ay+1);
  SVGDrawLine(t,ay+1,h,ay+1);
  SVGDrawLine(b,ay,t,ay);
  SVGDrawLine(b,ay+2,t,ay+2);
  SVGDrawLine(b,ay,b,ay+2);
  SVGDrawLine(t,ay,t,ay+2);
  if (o>c)
    for (r=0.0;r<=2.0;r+=0.25) {
      SVGDrawLine(b,ay+r,t,ay+r);
    }
}



char *CSV2TSV(char *in) {
  for (;*in;in++) if (*in==',') *in=' ';
  return in;
}

int LoadData() {
  char line[MAXSTR];

  numentry=0;
  while (gets(line)!=NULL) {
    CSV2TSV(line);
    sscanf(line,"%s %f %f %f %f %f %f"
      ,Date[numentry],&Open[numentry],&High[numentry]
      ,&Low[numentry],&Close[numentry],&Adj[numentry]
      ,&Volume[numentry]);

    if (tmin>Low[numentry]) tmin=Low[numentry];
    if (tmax<High[numentry]) tmax=High[numentry];
    puts(line);
    numentry++;
  }

  return 0;
}

int ShowData() {
  int i,j;

  SVGDrawHeader();

  for (i=numentry-50,j=i;i<numentry;i++) {
    printf("%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n"
      ,Date[i],Open[i],High[i]
      ,Low[i],Close[i],Adj[i]
      ,Volume[i]);

    SVGCandleStick(i-j,Open[i],High[i],Low[i],Close[i]);
    if (tmin>Low[i]) puts("Error: Low minimum");
  }
  printf("Min %.2f \t Max %.2f\n",tmin,tmax);
  return 0;
}

int main (int argc, char *argv[] ) {
  int e=0;
  char line[MAXSTR];

  GetOpt(argc, argv);
  if (gets(line)!=NULL) { //Remove header
    e=LoadData();
    if (!e) ShowData();
  }
  return e;
}





No comments:

Post a Comment