www.pudn.com > asm_java.zip > World.java


package asm;
import java.util.Vector;
/**
 * Title:        Artificial Stock Market
 * Description:  人工模拟股市(来源:SFI的Swarm版本)的Java版本
 * Copyright:    Copyright (c) 2003
 * Company:      http://agents.yeah.net
 * @author jake
 * @version 1.0
 */

//该类负责对世界的状态进行纪录并编码
public class World {
  public double intrate; /*利率" interest rate"*/
  public double dividendscale; /*股息的基本值" The baseline dividend that is set by initWithBaseline: "*/

  public int pupdown[];	       /*一个数组记录价格的升降情况" array, dimension UPDOWNLOOKBACK "*/
  public int dupdown[];	       /*一个数组记录股息的升降情况" array, dimension UPDOWNLOOKBACK "*/

  public int history_top;      /*价格、股息数组的历史纪录指标" index value of current input into history arrays "*/
  public int updown_top;     /*pupdown和dupdown两个数组的指标"number of time steps to look back to form pupdown and dupdown bits"*/
  public double price;     /*股票的市场价格"market clearning price"*/
  public double oldprice;  /*上一期的市场价格" previous price "*/
  public double dividend;   /*当前的股息" dividend "*/
  public double olddividend; /*上一期的股息"previous dividend"*/
  public double saveddividend; /* copy of olddividend, used for some
                           double-checking on object integrity"*/
  public double savedprice; /* copy of oldprice, used for some
                        double-checking on object integrity"*/
  public double riskNeutral;   /*"dividend/intrate"*/;
  public double profitperunit; /*没支股票的静收益=price - oldprice + dividend"*/
  public double returnratio;   /*回报率=profitperunit/oldprice"*/

  public int malength[];     /*" For each MA, we must specify the length over which the average is calculated. This array has one integer for each of the moving averages we plan to keep, and it is used to set the widths covered by the moving averages."*/

  public int nworldbits; /*世界信息编码的长度"The number of aspects of the world that are recorded as bits"*/
  public int realworld[]; /*真实世界的编码,每个索引对应的值为0~2"An array (dynamically allocated, sorry) of ints, one for each bit being monitored. This is kept up-to-date. There's a lot of pointer math going on with this and I don't feel so glad about it (PJ: 2001-11-01)"*/
  public boolean exponentialMAs; /*是否用指数加权的方法计算移动平均数值"Indicator variable, YES if the World is supposed to report back exponentially weighted moving averages"*/
  public MovingAverage priceMA[];  /*价格的移动平均" MovingAverage objects which hold price information. There are NMAS of these, and have various widths for the moving averages "*/
  public MovingAverage divMA[];   /*股息的移动平均"  MovingAverage objects which hold dividend moving averages. "*/
  public MovingAverage oldpriceMA[]; /*上期价格的移动平均" MovingAverage objects which hold lagged price moving averages "*/
  public MovingAverage olddivMA[];/*上期股息的移动平均" MovingAverage objects which hold lagged dividend moving averages "*/
  public Vector Histories;   //记录世界的历史信息
 double divhistory[];       /*股息历史数组" dividend history array, goes back MAXHISTORY points"*/
 double pricehistory[];     /*价格历史数组" price history array "*/

  static int NULLBIT=-1;
  static int PUPDOWNBITNUM=42;
  static int NWORLDBITS=61;
  static int NRATIOS=10;
  static int EQ=0;
  static int UPDOWNLOOKBACK=5;
  static int NMAS=4;
  static int MAXHISTORY=500;
  //定义世界编码对应位的名称
  String bitnamelist[][]={{"on", "dummy bit -- always on"},			// 0
{"off", "dummy bit -- always off"},
{"random", "random on or off"},

{"dup", "dividend went up this period"},		// 3
{"dup1", "dividend went up one period ago"},
{"dup2", "dividend went up two periods ago"},
{"dup3", "dividend went up three periods ago"},
{"dup4", "dividend went up four periods ago"},

{"d5up", "5-period MA of dividend went up"},		// 8
{"d20up", "20-period MA of dividend went up"},
{"d100up", "100-period MA of dividend went up"},
{"d500up", "500-period MA of dividend went up"},

{"d>d5",   "dividend > 5-period MA"},			// 12
{"d>d20",  "dividend > 20-period MA"},
{"d>d100", "dividend > 100-period MA"},
{"d>d500", "dividend > 500-period MA"},

{"d5>d20", "dividend: 5-period MA > 20-period MA"},	// 16
{"d5>d100", "dividend: 5-period MA > 100-period MA"},
{"d5>d500", "dividend: 5-period MA > 500-period MA"},
{"d20>d100", "dividend: 20-period MA > 100-period MA"},
{"d20>d500", "dividend: 20-period MA > 500-period MA"},
{"d100>d500", "dividend: 100-period MA > 500-period MA"},

{"d/md>1/4", "dividend/mean dividend > 1/4"},		// 22
{"d/md>1/2", "dividend/mean dividend > 1/2"},
{"d/md>3/4", "dividend/mean dividend > 3/4"},
{"d/md>7/8", "dividend/mean dividend > 7/8"},
{"d/md>1",   "dividend/mean dividend > 1  "},
{"d/md>9/8", "dividend/mean dividend > 9/8"},
{"d/md>5/4", "dividend/mean dividend > 5/4"},
{"d/md>3/2", "dividend/mean dividend > 3/2"},
{"d/md>2", "dividend/mean dividend > 2"},
{"d/md>4", "dividend/mean dividend > 4"},

{"pr/d>1/4", "price*interest/dividend > 1/4"},		// 32
{"pr/d>1/2", "price*interest/dividend > 1/2"},
{"pr/d>3/4", "price*interest/dividend > 3/4"},
{"pr/d>7/8", "price*interest/dividend > 7/8"},
{"pr/d>1",   "price*interest/dividend > 1"},
{"pr/d>9/8", "price*interest/dividend > 9/8"},
{"pr/d>5/4", "price*interest/dividend > 5/4"},
{"pr/d>3/2", "price*interest/dividend > 3/2"},
{"pr/d>2",   "price*interest/dividend > 2"},
{"pr/d>4",   "price*interest/dividend > 4"},

{"pup", "price went up this period"},			// 42
{"pup1", "price went up one period ago"},
{"pup2", "price went up two periods ago"},
{"pup3", "price went up three periods ago"},
{"pup4", "price went up four periods ago"},

{"p5up", "5-period MA of price went up"},		// 47
{"p20up", "20-period MA of price went up"},
{"p100up", "100-period MA of price went up"},
{"p500up", "500-period MA of price went up"},

{"p>p5", "price > 5-period MA"},			// 51
{"p>p20", "price > 20-period MA"},
{"p>p100", "price > 100-period MA"},
{"p>p500", "price > 500-period MA"},

{"p5>p20", "price: 5-period MA > 20-period MA"},	// 55
{"p5>p100", "price: 5-period MA > 100-period MA"},
{"p5>p500", "price: 5-period MA > 500-period MA"},
{"p20>p100", "price: 20-period MA > 100-period MA"},
{"p20>p500", "price: 20-period MA > 500-period MA"},
{"p100>p500", "price: 100-period MA > 500-period MA"}
};
double ratios[] ={0.25, 0.5, 0.75, 0.875, 1.0, 1.125, 1.25, 1.5, 2.0, 4.0};//比例数值数组
public World() {
  //构建函数,初始化各个变量
  pupdown=new int[UPDOWNLOOKBACK];	       /*" array, dimension UPDOWNLOOKBACK "*/
  dupdown=new int[UPDOWNLOOKBACK];
  malength=new int[NMAS];
  priceMA=new MovingAverage[NMAS];  /*" MovingAverage objects which hold price information. There are NMAS of these, and have various widths for the moving averages "*/
  divMA=new MovingAverage[NMAS];   /*"  MovingAverage objects which hold dividend moving averages. "*/
  oldpriceMA=new MovingAverage[NMAS]; /*" MovingAverage objects which hold lagged price moving averages "*/
  olddivMA=new MovingAverage[NMAS];
  Histories=new Vector();
}
String descriptionOfBit(int n){
  //获得指定位的描述
  if (n == NULLBIT)
    return "(Unused bit for spacing)";
  else if (n < 0 || n >= NWORLDBITS)
    return "(Invalid world bit)";
  return bitnamelist[n][1];
}
String nameOfBit(int n){
  //获得指定位的名称
  if (n == NULLBIT)
    return "null";
  else if (n < 0 || n >= NWORLDBITS)
    return "";
  return bitnamelist[n][0];
}


int bitNumberOf(String name)
/*" Converts a bit name to a bit number. Supplies the number of a bit
 * given its name.  Unknown names return NULLBIT.  Relatively slow
 * (linear search). Could be made faster with a hash table etc, but
 * that's not worth it for the intended usage.  "*/
{
  //根据位的名称获得位的值
  int n;

  for (n = 0; n < NWORLDBITS; n++)
    if (bitnamelist[n][0].equals(name))
      break;
  if (n >= NWORLDBITS) n = NULLBIT;

  return n;
}


void setintrate(double rate)
  /*" Interest rate set in ASMModelSwarm."*/
{
  intrate = rate;
}


void setExponentialMAs(boolean aBool)
  /*" Turns on the use of exponential MAs in calculations.  Can be
    turned on in GUI or ASMModelSwarm.m. If not, simple averages of
    the last N periods."*/
{
  exponentialMAs = aBool;
}


int getNumWorldBits()
  /*" Returns numworldbits; used by the BFagent."*/
{
  return nworldbits;
}


void initWithBaseline(double baseline)
/*"
Initializes moving averages, using initial values based on
a price scale of "baseline" for the dividend.  The baseline is
set in ASMModelSwarm. " */
{
  int i;
  double initprice, initdividend;

// Check pup index
  //if (!nameOfBit(PUPDOWNBITNUM).equals("pup"))
    //system.out("PUPDOWNBITNUM is incorrect");

// Set price and dividend etc from baseline
  dividendscale = baseline;
  initprice = baseline/intrate;//初始化价格
  initdividend = baseline;//初始化股息
  saveddividend = dividend = initdividend;
  setDividend(initdividend);
  savedprice = price = initprice;
  setPrice(initprice);

// Initialize profit measures
  returnratio = intrate;//初始化回报率
  profitperunit = 0.0;

// Initialize miscellaneous variables
  nworldbits = NWORLDBITS;

  //各个移动平均数组的记录长度
  malength[0] = 5;
  malength[1] = 20;
  malength[2] = 100;
  malength[3] = MAXHISTORY;

  history_top = 0;
  updown_top = 0;
  divhistory=new double[MAXHISTORY];       /*" dividend history array, goes back MAXHISTORY points"*/
  pricehistory=new double[MAXHISTORY];

  realworld = new int[NWORLDBITS];

  // Initialize arrays
  for (i = 0; i < UPDOWNLOOKBACK; i++)
    {
    pupdown[i] = 0;
    dupdown[i] = 0;
    }

  for (i = 0; i < MAXHISTORY; i++)
    {
    pricehistory[i] = initprice;
    divhistory[i] = initdividend;
    }
  //初始化各种移动平均数组
  for (i = 0; i < NMAS; i++)
    {
      priceMA[i] = new MovingAverage();
      priceMA[i].initWidth(malength[i],initprice);

      divMA[i] =new MovingAverage();
      divMA[i].initWidth(malength[i],initdividend);

      oldpriceMA[i] = new MovingAverage();
      oldpriceMA[i].initWidth(malength[i],initprice);

      olddivMA[i] =new MovingAverage();
      olddivMA[i].initWidth(malength[i],initdividend);
    }

// Initialize bits
//初始化世界的信息编码
  makebitvector();
}

/*设置价格p,并计算回报率
" Sets the market price to "p".  All price changes (besides trial
prices) should use this method.  Also computes profitperunit and
returnratio.  Checks internally for illegal changes of "price", giving us the
effective benefit of encapsulation with the simplicity of use of
a global variable. "*/
void setPrice(double p){
  //if (price != savedprice)
    //system.Out("Price was changed illegally");

  oldprice = price;
  price = p;

  //计算每股的收益
  profitperunit = price - oldprice + dividend;

  //计算回报率
  if (oldprice <= 0.0)
    returnratio = profitperunit*1000.0;	/* Arbitrarily large */
  else
    returnratio = profitperunit/oldprice;

  savedprice = price;
}

/*"Returns the price, used by many classes."*/
double getPrice(){
  return price;
}

/*"Returns profitperunit, used by Specialist."*/
double getProfitPerUnit(){
  return profitperunit;
}


/*"Sets the global value of "dividend".  All dividend changes should
	use this method.  It checks for illegal changes, as does
	-setPrice:."*/
void setDividend(double d){
  //if (dividend != saveddividend)
    //system.Out("Dividend was changed illegally.");
  //设置股息,并计算风险中性价格
  olddividend = dividend;
  dividend = d;

  saveddividend = dividend;
  riskNeutral = dividend/intrate;
}

/*"Returns the most recent dividend, used by many."*/
double getDividend(){
  return dividend;
}

/*"Returns the risk neutral price.  It is just dividend/intrate."*/
double getRiskNeutral(){
  return riskNeutral;
}

/*" Updates the history records, moving averages, and world bits to
 * reflect the current price and dividend.  Note that this is called
 * in each period after a new dividend has been declared but before
 * the bidding and price adjustment.  The bits seen by the agents thus
 * do NOT reflect the trial price.  The "price" here becomes the
 * "oldprice" by the end of the period. It is called once per period.
 * (This could be done automatically as part of -setDividend:).
 *
 * The dividend used here is at present the latest value, though it
 * could be argued that it should be the one before, to match price.
 * For the p*r/d bits we do use the old one.
 "*/
//对世界当前的状况进行编码,每个运行周期内,先进行该动作然后才让每个agent进行报价、交易
void updateWorld(){
  int i;

/* Update the binary up/down indicators for price and dividend */
//纪录当前的价格和股息是升还是降
  updown_top = (updown_top + 1) % UPDOWNLOOKBACK;
  if(price>oldprice){
    pupdown[updown_top] = 1;
  }else{
    pupdown[updown_top] = 0;
  }
  if(dividend > olddividend){
    dupdown[updown_top] = 1;
  }else{
    dupdown[updown_top] = 0;
  }


/* Update the price and dividend moving averages */
//历史长度下标更新
  history_top = history_top + 1 + MAXHISTORY;

  //update moving averages of price and dividend
  //更新价格和股息的移动平均数组
  for (i = 0; i < NMAS; i++)
    {
      int rago = (history_top-malength[i])%MAXHISTORY;

      priceMA[i].addValue(price);
      divMA[i].addValue(dividend);

      oldpriceMA[i].addValue(pricehistory[rago]);
      olddivMA[i].addValue(divhistory[rago]);
    }


/* Update the price and dividend histories */
//记录价格和股息的历史信息
  history_top %= MAXHISTORY;
  pricehistory[history_top] = price;
  divhistory[history_top] = dividend;

/* Construct the bit vector for the current state of the world */
//建立世界的编码
  makebitvector();
}


void makebitvector()
/*"  Set all the world bits, based on the current dividend, price,
and  their moving averages and histories.  This moves through the
realworld array, bit by bit, setting the values to 0, 1 or 2,
according to the data that has been observed.  Note the pointer math, such as realworld[i++], that steps the integer i through the array.   Note that "i" increases monotonically throughout this routine, always
being the next bit to assign.  It is crucial that the order here is the
same as in bitnamelist[]. "*/
{
  int i, j, k, temp;
  double multiple;


  i = 0;
  //设定前三位"on", "dummy bit -- always on"}{"off", "dummy bit -- always off"},{"random", "random on or off"},
  realworld[i++] = 1;
  realworld[i++] = 0;
  realworld[i++] = (int)(Math.random()*2);

  /* Dividend went up or down, now and for last few periods */
  //{"dup", "dividend went up this period"},		// 3
  //{"dup1", "dividend went up one period ago"},
  //{"dup2", "dividend went up two periods ago"},
  //{"dup3", "dividend went up three periods ago"},
  //{"dup4", "dividend went up four periods ago"},
  temp = updown_top + UPDOWNLOOKBACK;
  for (j = 0; j < UPDOWNLOOKBACK; j++, temp--)
    realworld[i++] = dupdown[temp%UPDOWNLOOKBACK];

  /* Dividend moving averages went up or down
  {"d5up", "5-period MA of dividend went up"},		// 8
  {"d20up", "20-period MA of dividend went up"},
  {"d100up", "100-period MA of dividend went up"},
  {"d500up", "500-period MA of dividend went up"},*/
  for (j = 0; j < NMAS; j++){
      double temp1,temp2;
      if(exponentialMAs){
        temp1=divMA[j].getEWMA();
        temp2=olddivMA[j].getEWMA();
      }else{
        temp1=divMA[j].getMA();
        temp2=olddivMA[j].getMA();
      }
      if(temp1>temp2)realworld[i++] =1;
      else realworld[i++]=0;
  }
  /* Dividend > MA[j] */
//{"d>d5",   "dividend > 5-period MA"},			// 12
//{"d>d20",  "dividend > 20-period MA"},
//{"d>d100", "dividend > 100-period MA"},
//{"d>d500", "dividend > 500-period MA"},

  for (j = 0; j < NMAS; j++){
      double temp1,temp2;
      if(exponentialMAs){
        temp1=dividend;
        temp2=divMA[j].getEWMA();
      }else{
        temp1=dividend;
        temp2=divMA[j].getMA();
      }
      if(temp1>temp2)realworld[i++] =1;
      else realworld[i++]=0;
  }
    //realworld[i++] = dividend > ( GETMA(divMA,j));

  /* Dividend MA[j] > dividend MA[k]
  {"d5>d20", "dividend: 5-period MA > 20-period MA"},	// 16
  {"d5>d100", "dividend: 5-period MA > 100-period MA"},
  {"d5>d500", "dividend: 5-period MA > 500-period MA"},
  {"d20>d100", "dividend: 20-period MA > 100-period MA"},
  {"d20>d500", "dividend: 20-period MA > 500-period MA"},
  {"d100>d500", "dividend: 100-period MA > 500-period MA"},*/
  for (j = 0; j < NMAS-1; j++){
    for (k = j+1; k < NMAS; k++){
      //realworld[i++] = (GETMA(divMA,j)) > (GETMA(divMA,k));
      double temp1,temp2;
      if(exponentialMAs){
        temp1=divMA[j].getEWMA();
        temp2=divMA[k].getEWMA();
      }else{
        temp1=divMA[j].getMA();
        temp2=divMA[k].getMA();
      }
      if(temp1>temp2)realworld[i++] =1;
      else realworld[i++]=0;
    }
  }
  /* Dividend as multiple of meandividend
  {"d/md>1/4", "dividend/mean dividend > 1/4"},		// 22
  {"d/md>1/2", "dividend/mean dividend > 1/2"},
  {"d/md>3/4", "dividend/mean dividend > 3/4"},
  {"d/md>7/8", "dividend/mean dividend > 7/8"},
  {"d/md>1",   "dividend/mean dividend > 1  "},
  {"d/md>9/8", "dividend/mean dividend > 9/8"},
  {"d/md>5/4", "dividend/mean dividend > 5/4"},
  {"d/md>3/2", "dividend/mean dividend > 3/2"},
  {"d/md>2", "dividend/mean dividend > 2"},
  {"d/md>4", "dividend/mean dividend > 4"},*/
  multiple = dividend/dividendscale;
  for (j = 0; j < NRATIOS; j++){
    if(multiple>ratios[j])realworld[i++]=1;
    else  realworld[i++]=0;
  }
  /* Price as multiple of dividend/intrate.  Here we use olddividend to
   * make a more reasonable comparison with the [old] price.
   {"pr/d>1/4", "price*interest/dividend > 1/4"},		// 32
  {"pr/d>1/2", "price*interest/dividend > 1/2"},
  {"pr/d>3/4", "price*interest/dividend > 3/4"},
  {"pr/d>7/8", "price*interest/dividend > 7/8"},
  {"pr/d>1",   "price*interest/dividend > 1"},
  {"pr/d>9/8", "price*interest/dividend > 9/8"},
  {"pr/d>5/4", "price*interest/dividend > 5/4"},
  {"pr/d>3/2", "price*interest/dividend > 3/2"},
  {"pr/d>2",   "price*interest/dividend > 2"},
  {"pr/d>4",   "price*interest/dividend > 4"},*/

  multiple = price*intrate/olddividend;
  for (j = 0; j < NRATIOS; j++){
    if(multiple>ratios[j])realworld[i++]=1;
    else  realworld[i++]=0;
  }
  /* Price went up or down, now and for last few periods
  {"pup", "price went up this period"},			// 42
  {"pup1", "price went up one period ago"},
  {"pup2", "price went up two periods ago"},
  {"pup3", "price went up three periods ago"},
  {"pup4", "price went up four periods ago"},*/
  temp = updown_top + UPDOWNLOOKBACK;
  for (j = 0; j < UPDOWNLOOKBACK; j++, temp--)
    realworld[i++] = pupdown[temp%UPDOWNLOOKBACK];

  /* Price moving averages went up or down
  {"p5up", "5-period MA of price went up"},		// 47
  {"p20up", "20-period MA of price went up"},
  {"p100up", "100-period MA of price went up"},
  {"p500up", "500-period MA of price went up"},*/
  for (j = 0; j < NMAS; j++){
      double temp1,temp2;
      if(exponentialMAs){
        temp1=priceMA[j].getEWMA();
        temp2=oldpriceMA[j].getEWMA();
      }else{
        temp1=priceMA[j].getMA();
        temp2=oldpriceMA[j].getMA();
      }
      if(temp1>temp2)realworld[i++] = 1;
      else realworld[i++]=0;
  }

  /* Price > MA[j]
  {"p>p5", "price > 5-period MA"},			// 51
  {"p>p20", "price > 20-period MA"},
  {"p>p100", "price > 100-period MA"},
  {"p>p500", "price > 500-period MA"},*/
  for (j = 0; j < NMAS; j++){
      double temp1;
      if(exponentialMAs){
        temp1=priceMA[j].getEWMA();
      }else{
        temp1=priceMA[j].getMA();
      }
      if(price>temp1)realworld[i++] =1;
      else realworld[i++] =0;
  }

  /* Price MA[j] > price MA[k]
  {"p5>p20", "price: 5-period MA > 20-period MA"},	// 55
  {"p5>p100", "price: 5-period MA > 100-period MA"},
  {"p5>p500", "price: 5-period MA > 500-period MA"},
  {"p20>p100", "price: 20-period MA > 100-period MA"},
  {"p20>p500", "price: 20-period MA > 500-period MA"},
  {"p100>p500", "price: 100-period MA > 500-period MA"} */
  for (j = 0; j < NMAS-1; j++){
    for (k = j+1; k < NMAS; k++){
      double temp1,temp2;
      if(exponentialMAs){
        temp1=priceMA[j].getEWMA();
        temp2=priceMA[k].getEWMA();
      }else{
        temp1=priceMA[j].getMA();
        temp2=priceMA[k].getMA();
      }
      if(temp1>temp2)realworld[i++] =1;
      else realworld[i++]=0;
    }
  }
}

/*" Returns the real world array of bits.  Used by BFagent to compare
  their worlds to the real world."*/
String getRealWorld(){
  //将realworld数组转换成字符串
  String result="";
  for(int i=0;iWorldVariants.cycleMax){
    Histories.setElementAt(now_world,Histories.size()%WorldVariants.cycleMax);
  }
}

}

//MovingAverage类负责一个时间序列求平均值的纪录
//这个时间序列的记录有一个宽度width,然后对所有时间序列求平均值
class MovingAverage{
  public int width;  /*时间序列数据的宽度"number of observations used for a fixed interval moving average"*/
  public int numInputs; /*已经纪录的个数"number of observations that have already been inserted"*/


  public double maInputs[]; /*保存下的历史数聚"historical inputs are kept in this array."*/
  public int arrayPosition; /*当前纪录的下标"element of maInputs that has been most recently inserted"*/
  public double sumOfInputs;/*全长的数据和"sum of the last 'width' inputs"*/
  public double uncorrectedSum; /*当对象被建立以后所有输入的和"sum of all inputs since object was created"*/

  public double expWMA;  //指数加权的移动平均值exponentially weighted moving average
  public double aweight, bweight; /*计算指数加权平均值的权值"Weights used to calculate exponentially weighted moving averages.  These depend on the specified 'width' according to: bweight = -expm1(-1.0/w);aweight = 1.0 - bweight; ewma=aweight*ma(x)+bweight*x"*/
/*"This is a general purpose class for creating Moving Averages, either flat "equally weighted" moving averages or exponentially weighted moving averages"*/

void initWidth(int w){
  //初始化移动平均中的各个变量
  int i;
  width=w;
  maInputs=new double[w];
  for(i=0; i < w; i++){
      maInputs[i] = 0;
  }
  numInputs=0;
  sumOfInputs=0;
  arrayPosition=0;
  uncorrectedSum=0;

  bweight = -Math.exp(-1.0/w);
  aweight = 1.0 - bweight;   //weight for expWMA; ma=a*ma(x)+b*x
}
void initWidth(int w,double val){
  int i;
  width=w;
  maInputs=new double[w];
  for(i=0; i < w; i++)
    {
      maInputs[i] = val;
    }
  numInputs=w;
  sumOfInputs=w*val;
  arrayPosition=0;
  uncorrectedSum=w*val;

  bweight = -Math.exp(-1.0/w);
  aweight = 1.0 - bweight;   //weight for expWMA; ma=a*ma(x)+b*x
  expWMA = val;

}


int getNumInputs(){
  return numInputs;
}


double getMA(){
  //得到序列的平均值
  double movingAverage;
  if (numInputs == 0) return 0;

  //当纪录的个数小于width的时候则指标数是numInputs,否则是width
  else if (numInputs < width){
      movingAverage=  (double)sumOfInputs / (double)  numInputs;
    }
  else{
      movingAverage = (double)sumOfInputs / (double) width;
    }
  return movingAverage;
}

double getAverage(){
  //返回所有记录过的纪录的全体平均值
  if (numInputs ==0) return 0;
  else return (double)uncorrectedSum/numInputs;
}

double getEWMA(){
  return expWMA;
}

void addValue(double x){
  //当加入一个时间序列的纪录的时候

  //记录下标对宽度进行循环
  arrayPosition = (width + numInputs) % width;

  //如果纪录的总数小于宽度就直接纪录,并求总和,如果不是,那么需要把对应记录位置的值减去再加上新的值
  if(numInputs < width){
    sumOfInputs+=x;
    maInputs[arrayPosition]=x;
    }
  else{
      sumOfInputs=sumOfInputs - maInputs[arrayPosition] + x ;
      maInputs[arrayPosition]=x;
    }
  numInputs++;

  //所有记录过的纪录的全体和
  uncorrectedSum+=x;

  expWMA = aweight*expWMA + bweight*x;
}

}