Monday, June 20, 2022

Day 7/100 Point and Figure chart

 Day 7/100 Point and Figure chart

Look at all the Xs and Os!


So, I followed Elon Musk bid for Twitter. I think he's fine, so naturally, I joined Twitter and started this 100 Days of Code. Well, if we're talking about Elon Musk, we're talking about Tesla, and with the recent grape-vine rumors about the price of $TSLA, I'm curious enough to see if now is a good time to buy the stock. Usually I just go by the Bollinger Band price chart, but since I'm in the middle of programming project, why not? Let's just do it myself!


I'll probably do a bar/line chart later, but right now, the one I want to concentrate is the Point and Figure chart, also known as the XO chart. If the price rises, you put in X. If the price lowers, you put in O. Time is irrelevant.


Well, I have trouble with that. I think the value of time is significant, so I decided to just do one with time stamp. And it's not too difficult. It's simply an increment of counter, and the way I set it up, it's just a simple integer. If you want to show date, though, you only need to change one line. Here's the diff:


73c73
<   printf("%d\t",tstamp);
---
>   printf("%s\t",Date);


And running the program will yield this output:


2022-01-04                      XXXXXXXX   
2022-01-10                     OOOOOOOOO   
2022-01-13                     XXXXX       
2022-01-14                     OOOOO       
2022-01-18                     XX          
2022-01-26                OOOOOOO          
2022-01-27                XX               
2022-01-28            OOOOOO               
2022-02-02            XXXXXX               
2022-02-04               OOO               
2022-02-10               XXX               
2022-02-14             OOOOO               
2022-02-17             XXXX                
2022-02-24         OOOOOOOO                
2022-03-03         XXXXXX                  
2022-03-08           OOOO                  
2022-03-10           XXX                   
2022-03-15         OOOOO                   
2022-03-31         XXXXXXXXXXXXXXXX        
2022-04-01                       OO        
2022-04-05                       XXXX      
2022-04-13                   OOOOOOOO      
2022-04-14                   XXX           
2022-04-18                   OOO           
2022-04-20                   XXX           
2022-04-21                   OOO           
2022-04-26                   XX            
2022-05-02              OOOOOOO            
2022-05-05              XXXXX              
2022-05-10          OOOOOOOOO              
2022-05-11          XX                     
2022-05-13       OOOOO                     
2022-05-16       XXX                       
2022-05-17       OOO                       
2022-05-18       XXX                       
2022-05-23    OOOOOO                       
2022-05-24    XX                           
2022-05-25   OOO                           
2022-06-01   XXXXXXX                       
2022-06-02        OO                       
2022-06-03        XXX                      
2022-06-06      OOOOO                      
2022-06-10      XX                         
2022-06-15    OOOO                         
2022-06-16    XXX                          
2022-06-17   OOOO    


So, there you go. But what is the core of the program? What makes Point and Figure program what it is? Well, there's the XO chart:


void mark(int n) {
  char c;
  for (n=lslot;n>=slot;n--) {
    if (dir<0)  c='O';
    if (dir==0) c='=';
    if (dir>0)  c='X';
    if (n<=0) { c='|'; n=0; }
    if (n>=sca-1) { c='+'; n=sca-1; }
    scan[n]=c;
  }
  for (n=lslot;n<=slot;n++) {
    if (dir<0)  c='O';
    if (dir==0) c='=';
    if (dir>0)  c='X';
    if (n<=0) { c='|'; n=0; }
    if (n>=sca-1) { c='+'; n=sca-1; }
    scan[n]=c;
  }
}


Doing it that way annoys me to no end. Isn't there a simpler way to do it? Yes, I'm sure of it. But this is just something I do at the end of the day for one hour at a time. There's not a whole lot that I can experiment with. I did experiment a bit, but the charting process got messed up. Even now, there's a little extra character on the chart, which I'm sure you notice if you look at traditional charts. However, it's sufficient for now.


There are three other characters added, as compared to the traditional chart. They are '=' to denote non changing price. '|' to denote lower bound of the chart. '+' to denote upper bound of the chart. This is because the chart is non-self adjusting. It has the benefit of zooming in to the section you're interested in, as opposed to having to take everything in. 


Of course, chart legends is only the presentation aspect of it. How about the logic? The following logic is more complicated than it needs to be. That's because I'm still figuring out as I go. I'm not really satisfied with it, but like I said, I ran out of time. And I will probably use the knowledge of it for the future. 


In particular, I would move the sscanf() line to its own function. There's also a whole lot of calculation about ranges, scale, and direction. Those can be simplified further.


int pnf() {
  char line[MAXSTR];
  while (gets(line)!=NULL) {
    sscanf(line,"%s\t%f\t%f\t%f\t%f\t%f\t%f\n"
      ,Date,&Open,&High,&Low,&Close,&Adj,&Volume);
    if (tmin>Adj) tmin=Adj; if (tmax<Adj) tmax=Adj;
    slot=(int)(((Adj-min)*(float)sca/(max-min)))+1;
    slot=(slot<1)?0:(slot>sca-2)?sca-1:slot;
    if (val<0) { val=Adj; lslot=slot; clrscan(); }
    if (dir>0 && slot<lslot) { showScan(1); dir=-1; }
    if (dir<0 && slot>lslot) { showScan(1); dir=1; }
    if (dir==0 && slot<lslot) { dir=-1; }
    if (dir==0 && slot>lslot) { dir=1;  }
    mark(slot); val=Adj; lslot=slot; tstamp++;
  } return 0;
}


Looking at the forest point of view, it looks like I deal with a lot of different states of variables. So, I'd do better by setting up flags, and perhaps, setting them up in an array. That way I can just do a simple lookup function and clean up the code that way.


The way it is now, it works. Not pretty, but it works. All in all, I'm satisfied with what I have. 


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAXSTR 256
 
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[MAXSTR];
float Open;
float High;
float Low;
float Close;
float Adj;
float Volume;
float tmin=20000.0;
float tmax=0.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;
}


void clrscan(void) {
  int i;
  for (i=MAXSTR;i>0;) scan[--i]=' ';
}

void showScan(int mode) {
  int i;
  printf("%d\t",tstamp);
  for (i=0;i<sca;i++) putchar(scan[i]);
  putchar('\n');
  if (mode) { clrscan(); }
}

void mark(int n) {
  char c;
  for (n=lslot;n>=slot;n--) {
    if (dir<0)  c='O';
    if (dir==0) c='=';
    if (dir>0)  c='X';
    if (n<=0) { c='|'; n=0; }
    if (n>=sca-1) { c='+'; n=sca-1; }
    scan[n]=c;
  }
  for (n=lslot;n<=slot;n++) {
    if (dir<0)  c='O';
    if (dir==0) c='=';
    if (dir>0)  c='X';
    if (n<=0) { c='|'; n=0; }
    if (n>=sca-1) { c='+'; n=sca-1; }
    scan[n]=c;
  }
}

int pnf() {
  char line[MAXSTR];

  while (gets(line)!=NULL) {
    sscanf(line,"%s\t%f\t%f\t%f\t%f\t%f\t%f\n"
      ,Date,&Open,&High,&Low,&Close,&Adj,&Volume);
    tmin=(tmin<Adj)?tmin:Adj;
    tmax=(tmax>Adj)?tmax:Adj;
    slot=(int)(((Adj-min)*(float)sca/(max-min)))+1;
    slot=(slot<1)?0:(slot>sca-2)?sca-1:slot;
    if (val<0) { val=Adj; lslot=slot; clrscan(); }

    if (Debug)  printf("%s\t%0.2f (%d) \tMin=%.2f\tMax=%.2f\n",Date,Adj,slot,tmin,tmax);
    if (Debug) {
      printf("(%d)\t",slot);
    }

    if (dir>0 && slot<lslot) { showScan(1); dir=-1; }
    if (dir<0 && slot>lslot) { showScan(1); dir=1; }
    if (dir==0 && slot<lslot) { dir=-1; }
    if (dir==0 && slot>lslot) { dir=1;  }
    mark(slot);
    val=Adj; lslot=slot; tstamp++;
  }


  return 0;
}

int main (int argc, char *argv[] ) {
  int e=0;
  char line[MAXSTR];
  GetOpt(argc, argv);
  if (gets(line)!=NULL) e=pnf(); //Remove header
  return e;
}


One more thing: (spoiler!)


Yes, now is a good time to buy Tesla stock! I'd wait for an uptick, though.


No comments:

Post a Comment