program chartGenerator_2;

//*********************************************************************
// chart example for analyzing random walk & graphic patterns loc's=301  
// you have to set the iteration var i (in main) for density
// experiment with random(clblue) and (random(15) for effects 
//*********************************************************************

(*
 RRRRR    EEEEEE   AAAA   DDDDD    MM     MM   EEEEEE 
 RR  RR   EE       AA AA  DD  DD   MMMM MMMM   EE    
 RRRRR    EEEE    AAAAAA  DD   DD  MM MMM MM   EEEE
 RR  RR   EE      AA   AA DD   DD  MM  M  MM   EE
 RR   RR  EEEEEE AA    AA DDDDD    MM  M  MM   EEEEEE
*)

const
//values for generator and view
  DAT = 1465;
  CHDAT = 1460;  
  CHHEIGHT = 650;
  MA_SHORT = 33; 
  MA_LONG = 200; 
  BUYSYM = 1;
  SELLSYM = 2;
  DISTMIN = 15;
  DAYMIN = 10;
         

type
  TMemor= array[1..DAT] of double;
  TMAverage = array[1..DAT] of double;
  //EOptMovingAverage = class (Exception) end;
  TPerfMem = array[1..DAT] of integer;
var
  cFrm: TForm;
  chartData: TMemor;
  maData2, maData3: TMAverage;
  perfMem: TPerfMem;
  perfAmount, perfAmountTot, transCount, ma_cycle: Integer;
 // myGen: TChartGen;

//scaleX1, scaleX2, scaleY1, scaleY2: double;
{procedure scaleResults(const X, Y :double; 
         var intX, intY: integer; width, height: integer);
 var 
  scaledX, scaledY: double; 
  begin
   scaledX:= (X-scaleX1)/(scaleX2-scaleX1);
    scaledY:= (Y-scaleY2)/(scaleY1-scaleY2);
     intX:= round(scaledX * width);
      intY:= round(scaledY * height);
  end;} 

 
procedure PaintBox1Paint(sender: TObject);
var
  origx, origy: integer;
  xRngPixs, yRngPixs: Integer;
begin
  with cFrm.Canvas do begin
    {Fill background}
    Brush.Color:= clBtnFace;
    Brush.Style:= bsSolid;
    {Paint a coordinate cross }
    origx:= (cfrm.Width div 2);
    origy:= (cfrm.Height div 2);
    Pen.Color:= clwhite;
    Pen.Style:= psSolid;
    Pen.Width:= 1;
    MoveTo(1, origy);
    LineTo(cfrm.Width - 1, origy);
    MoveTo(origx, 1);
    LineTo(origx, cFrm.Height - 1);

    { Paint some tickmarks and label the axis }
    Font.Name:= 'Times';
    Font.Size:= 26;
    Font.Color:= clblue;
    xRngPixs:= (cFrm.Width - 20) div 4; { pixels in Pi }
    yRngPixs:= (cFrm.Height - 20) div 2; { pixels in 1 }
    TextOut(origx -2 * xRngPixs +2, origy -310, ' ChartGenerator2 ');
    font.Size:= 12;
    { X axis }
    MoveTo(origx -2 * xRngPixs, origy -4);
    LineTo(origx -2 * xRngPixs, origy +4);
    TextOut(origx -2 * xRngPixs +2, origy +2, '2009');
    MoveTo(origx -xRngPixs, origy -4);
    LineTo(origx -xRngPixs, origy +4);
    TextOut(origx -xRngPixs +2, origy +2, '2010');
    MoveTo(origx +xRngPixs, origy -4);
    LineTo(origx +xRngPixs, origy +4);
    TextOut(origx +xRngPixs -2 -TextWidth('2012'), origy +2, '2012');
    MoveTo(origx +2 * xRngPixs, origy -4);
    LineTo(origx +2 * xRngPixs, origy +4);
    TextOut(origx +2 * xRngPixs -2 -TextWidth('2013'), origy +2, '2013');

    { Y axis }
    MoveTo(origx -4, origy - yRngPixs);
    LineTo(origx +4, origy - yRngPixs);
    TextOut(origx +4, origy - yRngPixs, inttostr(CHHEIGHT));
    MoveTo(origx -4, origy - yRngPixs div 2);
    LineTo(origx +4, origy - yRngPixs div 2);
    TextOut(origx +4, origy - (yRngPixs + TextHeight('1')) 
                                      div 2, inttostr(CHHEIGHT div 4 *3));
    TextOut(origx +4, origy + (yRngPixs - TextHeight('1')) 
                                      div 50, inttostr(CHHEIGHT div 2));
    MoveTo(origx -4, origy + yRngPixs div 2);
    LineTo(origx +4, origy + yRngPixs div 2);
    TextOut(origx +4, origy + (yRngPixs - TextHeight('1')) 
                                      div 2, inttostr(CHHEIGHT div 4 *1));

    Font.Name:= 'Arial';
    Font.Color:= clyellow;
      TextOut(origx-2 * xRngPixs +2, origy +110, '4 Year Charts');
    Font.Color:= clred;
      TextOut(origx-2 * xRngPixs+2, origy+135,'MA Short: '+inttostr(MA_SHORT));
    Font.Color:= clblue;
      TextOut(origx-2 * xRngPixs+2, origy+160,'MA Long: '+inttostr(MA_LONG));
    Pen.Color:= clBlue;
    //procedure drawChart(vForm: TForm);
  end;
end;
 
function getFramePerfCount(const perfMem: TPerfMem; frameWidth: 
        integer): Integer;
var
  z, i: Integer;
  buysell: Byte;
begin
   z:= 0;
   buysell:= 0;
   for i:= 1 to frameWidth -1 do begin
     inc(z);
     if perfMem[z]= SELLSYM then begin
       incb(buysell);
       //inc(z);
     end
   end;
  result:= buysell;
end; 
 

procedure MAPerformance(const memos: TMemor; ma: TMAverage; 
        framePerf: integer; var perfMem: TPerfMem; var perfAmount: integer);
var
  z, i, delta1, delta2, deltaBuySell: Integer;
  firstBuy, firstSell, nextSell, nextBuy: Byte;
begin
   //symbol 1 is buy, symbol 2 is sell
   firstbuy:= 1;
   firstsell:= 0;
   perfAmount:= 0;
   delta1:= 0;
   delta2:= 0;
   z:= 5;
   nextSell:= 1;
   nextBuy:= 1;
   for i:= 1 to framePerf do perfMem[i]:=0; //check
   while z < framePerf-10 do  begin
    inc(z);
    if ((memos[z]) > (ma[z])) and (firstBuy=1) then begin
      delta1:= round((memos[z] + memos[z+1])/2);
      firstBuy:= 0;
      firstSell:= 1;
      nextSell:= 1;
      perfMem[z]:= BUYSYM;
    end else
    if (((memos[z])<= ma[z])) and (firstSell=1) then begin //sell
      delta2:= round((memos[z] + memos[z+1])/2);
      firstSell:= 0;
      firstBuy:= 1;
      nextBuy:= 1;
      perfMem[z]:= SELLSYM;
      deltaBuySell:= delta2 - delta1;
      perfMem[z+1]:= deltaBuySell;
      perfAmount:= perfAmount + deltaBuySell;
    end;
    //approximator to next sell and to next buy
    if nextBuy = 1 then begin
      nextBuy:= 0;
      if ((z+DISTMIN)<(framePerf-DISTMIN)) then
       z:= z + DISTMIN else exit;
      if ((memos[z]) > ma[z]) and (z < framePerf) then repeat
        inc(z)
      until (memos[z]) < ma[z];
    end;
    if nextSell = 1 then begin
      nextSell:= 0;
      if ((z+DAYMIN)<(framePerf-DAYMIN)) then
       z:= z + DAYMIN else exit;
      if ((memos[z]) < ma[z]) and (z < framePerf-9) then repeat
        inc(z)
      until (memos[z]) >= ma[z];
    end;
   end;
end;

function MovingAverage(const memos: TMemor; var MA: TMAverage; 
        datlen: integer; time: byte): Boolean;
var
  masum, y: Double;
  i: Integer;
begin
   masum:= 0;
   for i:= 1 to datlen -1 do MA[i]:= 0;
   for i:= 1 to datlen -1 do begin
     y:= memos[i];
     if i <= time then begin
       masum:= masum + y;
       MA[i]:= round(masum/i);
     end;
     if i > time then begin
      //moving the timewindow
       masum:= masum - ((memos[i - time])) + y;
       MA[i]:= round(masum/time);
     end;
   end;
  result:= true;
end;

function optMovingAverage(from, till: byte; const chartData: TMemor; 
        chartcount: word; var optMA: byte; perfList: TStringList): TStringList;
var
  i, perfAmount, framepcount, maxperf: Integer;
  period: string;
  perfMem: TPerfMem;
  maData: TMAverage;
  perfcount, cycle: Byte;
begin
   perfcount:= till - from;
   perfAmount:= 0;
   cycle:= from;
   maxperf:= -1000;
   optMA:= 0;
  try
    for i:= 1 to perfcount do begin
     //period:=' ';  external exception!!!
     incb(cycle);
     movingAverage(chartData, maData, chartcount, cycle);
     MAPerformance(chartData, maData, chartcount,
                              perfMem, perfAmount);
     if perfamount > maxperf then begin
       maxperf:= perfamount;
       optMA:= from + i;
     end;
     framePcount:=getFramePerfCount(perfMem, chartcount);
     period:= format('%d %d   %d  %d',[cycle, perfamount, framePCount, optMA]);
     perfList.add(period);
    end;
    result:= perflist;
  except
    //raise EOptMovingAverage.Create(trans.strlit[35])
  end;
end;
 
 
 
procedure letPrimeStatistics(const chartData: TMemor; var mn, std: extended);
begin
  MeanAndStdDev(chartData, mn, std);
end; 

{function TotalVariance(const Data: array of Double): Extended;
  var Sum, SumSquares: Extended;
  begin
    SumsAndSquares(Data, Sum, SumSquares);
    Result:= SumSquares - Sqrt(Sum)/(High(Data) - Low(Data) + 1);
  end;}
 
procedure preInitArray;
var i: Integer;
begin
   for i:= 1 to DAT-1 do chartdata[i]:= 0;
end;


function ChartGenerator(HBase, count: integer; var vdata: TMemor): Boolean;
var
  i, y2: Integer;
  startvalue: Extended;
begin
  randomize;
  y2:= HBase;
  startvalue:= 0.5;
  try
    result:= false;
    for i:= 1 to count do begin
      y2:= y2 + (random(13) - random(13));
      if y2 > 0 then
      vdata[i]:= abs(round(y2))
      else vdata[i]:= 1;
    end;
   result:= true;
  finally
   //randomize;
  end;
end;

procedure drawPerformance(vForm: TForm);
var
  i, z: Integer;
  bSize, hsize: LongInt;
begin
   z:= 1;
   hsize:= vForm.Height - 1 div 2;
   MAPerformance(chartData, maData3, CHDAT,
                        perfMem, perfAmount);
   transCount:= getFramePerfCount(perfMem, CHDAT);
   with vForm.canvas do begin
     bSize:= vForm.top + vForm.height;  //canvas bottom
     pen.Color:= clblue;
     //TextOut(25,50, inttoStr(perfAmount)+
       //              ' Local Gain by ' +inttoStr(MA_CYCLE));
     textOut(20,65, inttoStr(transCount)+ ' Transactions');
     textOut(20,80, inttoStr(perfAmount)+ ' Total Gain');
     textOut(20,95, inttoStr(MA_LONG) + ' Long');
     for i:= 1 to CHDAT - 15 do begin
       inc(z);
       if perfMem[z] = 1 then begin
         Pen.Color:= clgreen;
         MoveTo(z-1, hsize - (round(maData3[z-1])));
         LineTo(z-1, bSize);
       end else
       if perfMem[z] = 2 then begin
         Pen.Color:= clred;
         MoveTo(z-1, hsize -(round(maData3[z-1])));
         LineTo(z-1, bSize);
         textout(z, hsize-60, inttoStr(perfMem[z+1]));
         inc(z);
       end
     end; // loop
   end; //with
end; 


procedure drawChart(vForm: TForm);
var
  i, hsize: integer;
begin
  with vForm.canvas do begin
    hsize:= vForm.Height - 1 div 2;
    Pen.Color:= random(clblue);
    if Pen.Color = clblack then
      Pen.Color:= random(clblue);
    //setZoomFact(high(chartdata), fileNameChart);
    moveto(0, hsize -(round(chartData[1])));
    for i:= 1 to CHDAT do
      LineTo(i, hsize -(round(chartData[i])));
    MovingAverage(chartData, maData2, CHDAT, MA_SHORT)
    for i:= 1 to CHDAT do
      Pixels[i, hsize-(round(maData2[i]))]:= clred;
    MovingAverage(chartData, maData3, CHDAT, MA_LONG)
    for i:= 1 to CHDAT do
      Pixels[i, hsize-(round(maData3[i]))]:= clblue;  
  end;
end;


procedure FormClick(sender: TObject);
var mn, std: extended;
begin
  preInitArray;
  cFrm.repaint;
  if chartGenerator(cFrm.height div 2, CHDAT, chartData) then
      drawChart(cfrm);
  drawPerformance(cFrm);    
  letPrimeStatistics(chartData, mn, std)
  writeln('Mean: '+floattoStr(mn) + '  Std: '+floattostr(std))
  writeln('Total Variance: '+inttostr(trunc(totalVariance(chartData))))
end;      

procedure FormKeyPress(Sender: TObject; var Key: Char);
begin
 if Key =  #13 
 then FormClick(self);
 if Key = #27 then cFrm.close;
end;

procedure LoadForm;
begin
  cFrm:= TForm.create(self);
  with cFrm do begin
    caption:= 'ChartGenerator of 4 Years, click to continue or press Enter';  
    BorderStyle:= bsDialog;
    height:= CHHEIGHT;
    width:= CHDAT;
    color:= clblack;
    onPaint:= @PaintBox1Paint;
    onClick:= @FormClick;
    onKeyPress:= @FormKeyPress
    show;
  end  
end;

//main generator loop
var 
  i: integer;
begin
//************* maXbox graphics serie***************************************
  loadForm;
  preInitArray;
  paintbox1paint(self);
  for i:= 1 to 3 do begin
    if chartGenerator(cFrm.height div 2, CHDAT, chartData) then
      drawChart(cfrm);
  end
  //drawPerformance(cFrm);
  {//unit test drives
  for i:= 1 to chdat-1 do 
   writeln(floattostr(chartdata[i]))
  writeln(inttostr(cFrm.height div 2))
  letPrimeStatistics(chartData, mn, std)
  writeln('mean: '+floattoStr(mn) + 'std: '+floattostr(std)) }
end.

just inside maxbox
         ____    ___   _      ____    _   _   _
        |  _ \  |  _| | |    |  _ \  | | | | | |
        | | . | | |_  | |    | |_| | | |_| | | |
        | | | | |  _| | |    |  __/  |  _  | | |          
        | |_. | | |_  | |__  | |     | | | | | |                      
        |____/  |___| |____| |_|     |_| |_| |_| 
                                     
