外汇EA——基于均线的简单EA

上次写了一个简单的均线ea,在图标中同时显示SMA,WMA,EMA,今天写了一个基于SMA和EMA的简单ea,当然,想靠他盈利是不可能的,看代码吧

//+------------------------------------------------------------------+
//|                                                        ma_ea.mq4 |
//|                        Copyright 2014, MetaQuotes Software Corp. |
//|                                          http://coderaladdin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://coderaladdin.com"
#property version   "1.00"
#property strict

#define MAGIC_NUM 20150312

//--- input parameters
input int      period=19;
input int      max_orders=10;
input double      per_lot=0.01;
input double   risk_rate=0.1;

double calcLots() {
   double   lot=per_lot;   
   double minLot = MarketInfo(Symbol(),MODE_MINLOT);
   
   lot=NormalizeDouble(risk_rate*AccountFreeMargin()/AccountLeverage(),1);
   
   if(lot<0.1) lot=0.1;
   if(lot<minLot) lot=minLot;
   return(lot);
}

void CheckForOpen()
  {
   double ema;
   double sma;
   int    res;
//--- go trading only for first tiks of new bar
//   if(Volume[0]>1) return;
//--- get Moving Average 
    sma=iMA(NULL,0,period,0,MODE_SMA,PRICE_CLOSE,0);
    ema=iMA(NULL,0,period,0,MODE_EMA,PRICE_CLOSE,0);
   
//--- sell conditions
   if(Open[1]>ema && Open[1]>sma && ema<sma && Close[1]<ema && Close[1]<sma)
     {
      res=OrderSend(Symbol(),OP_SELL,calcLots(),Bid,3,0,0,"",MAGIC_NUM,0,Red);
      return;
     }
//--- buy conditions
   if(Open[1]<ema && Open[1]<sma && Close[1]>sma && Close[1]>ema && ema>sma)
     {
      res=OrderSend(Symbol(),OP_BUY,calcLots(),Ask,3,0,0,"",MAGIC_NUM,0,Blue);
      return;
     }
//---
  }
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double sma;
   double ema;
//--- go trading only for first tiks of new bar
//   if(Volume[0]>1) return;
//--- get Moving Average 
    sma=iMA(NULL,0,period,0,MODE_SMA,PRICE_CLOSE,0);
    ema=iMA(NULL,0,period,0,MODE_EMA,PRICE_CLOSE,0);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGIC_NUM || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(Open[1]>sma && Open[1]>ema && Close[1]<ema && Close[1]<sma && ema<sma)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(Open[1]<sma && Open[1]<ema && Close[1]>ema && Close[1]>sma && ema>sma)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(Bars<100 || IsTradeAllowed()==false) return;
   
   if(OrdersTotal() <=10) CheckForOpen();                            //  
   else  CheckForClose();
  }
//+------------------------------------------------------------------+

再来看下这个ea下的单
QQ截图20150314102731

外汇指标——Moving Averages

今天开始争取每周一到两篇外汇指标原理分析以及mql4样例代码,今天要剖析的是最简单而又常用的移动平均线(Moving Averages)。
移动平均线又分为简单移动平均线(Simple Moving Averages),加权移动平均线(Weighted Moving Averages),指数移动平均线(Exponential Moving Averages)等
例如当前有XAUUSD的10天收盘价信息
2014.12.29 1182.97
2014.12.30 1200.02
2014.12.31 1182.16
2015.01.02 1188.04
2015.01.05 1204.55
2015.01.06 1218.15
2015.01.07 1210.64
2015.01.08 1208.42
2015.01.09 1222.65
2015.01.12 1227.33
根据以上数据我们可以拿到5天的SMA数据
00a1563f5d7e4a9957c71b90e454e08c
226058487602d8729ea847567d39c54d
2014.12.29 1182.97
2014.12.30 1200.02
2014.12.31 1182.16
2015.01.02 1188.04
2015.01.05 1204.55 1191.548
2015.01.06 1218.15 1198.584
2015.01.07 1210.64 1200.708
2015.01.08 1208.42 1205.96
2015.01.09 1222.65 1212.882
2015.01.12 1227.33 1217.438
再来看加权移动平均(线性加权)
指计算平均值时将数据乘以不同数值,在技术分析中,n日WMA的最近期一个数值乘以n、次近的乘以n-1,如此类推,一直到0:

上式可以推导出72f344ddd46baa0134d886e42df195fc

2014.12.29 1182.97
2014.12.30 1200.02
2014.12.31 1182.16
2015.01.02 1188.04
2015.01.05 1204.55 1191.548 1193.626667
2015.01.06 1218.15 1198.584 1202.494
2015.01.07 1210.64 1200.708 1206.512667
2015.01.08 1208.42 1205.96 1209.083333
2015.01.09 1222.65 1212.882 1214.646667
2015.01.12 1227.33 1217.438 1219.462667
再来看指数移动平均数
是以指数式递减加权的移动平均。各数值的加权影响力随时间而指数式递减,越近期的数据加权影响力越重,但较旧的数据也给予一定的加权值
加权的程度以常数α决定,α数值介乎0至1。α也可用天数N来代表:0c3be7f0484ec9ee2888b7b2cb901dc1,所以,N=19天,代表α=0.1。
设时间t的实际数值为Yt,而时间t的EMA则为St;时间t-1的EMA则为St-1,计算时间t≥2是方程式为:
a8b4b375513994c0561fb5df58f10f26
EMA的公式推导见
QQ截图20150311003022
根据我们这边给N=5(通常用12和26比较常用)
那么可以知道k=20.7,也就是说我们要至少拿到前20天的数据才能推导出第一个EMA的值了(实际计算中并没有严格按照这样的数学逻辑计算,而是把第一天的收盘价当成第一个EMA值)
这边我们就不去计算了,因为mt4中都有现成的API计算好了,以上所有的指标都是有的
可以到
Include文件夹下看MovingAverages.mqh这个头文件

//+------------------------------------------------------------------+
//|                                               MovingAverages.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Simple Moving Average                                            |
//+------------------------------------------------------------------+
double SimpleMA(const int position,const int period,const double &price[])
  {
//---
   double result=0.0;
//--- check position
   if(position>=period-1 && period>0)
     {
      //--- calculate value
      for(int i=0;i<period;i++) result+=price[position-i];
      result/=period;
     }
//---
   return(result);
  }
//+------------------------------------------------------------------+
//| Exponential Moving Average                                       |
//+------------------------------------------------------------------+
double ExponentialMA(const int position,const int period,const double prev_value,const double &price[])
  {
//---
   double result=0.0;
//--- calculate value
   if(period>0)
     {
      double pr=2.0/(period+1.0);
      result=price[position]*pr+prev_value*(1-pr);
     }
//---
   return(result);
  }
//+------------------------------------------------------------------+
//| Smoothed Moving Average                                          |
//+------------------------------------------------------------------+
double SmoothedMA(const int position,const int period,const double prev_value,const double &price[])
  {
//---
   double result=0.0;
//--- check position
   if(period>0)
     {
      if(position==period-1)
        {
         for(int i=0;i<period;i++) result+=price[position-i];
         result/=period;
        }
      if(position>=period)
         result=(prev_value*(period-1)+price[position])/period;
     }
//---
   return(result);
  }
//+------------------------------------------------------------------+
//| Linear Weighted Moving Average                                   |
//+------------------------------------------------------------------+
double LinearWeightedMA(const int position,const int period,const double &price[])
  {
//---
   double result=0.0,sum=0.0;
   int    i,wsum=0;
//--- calculate value
   if(position>=period-1 && period>0)
     {
      for(i=period;i>0;i--)
        {
         wsum+=i;
         sum+=price[position-i+1]*(period-i+1);
        }
      result=sum/wsum;
     }
//---
   return(result);
  }
//+------------------------------------------------------------------+
//| Simple moving average on price array                             |
//+------------------------------------------------------------------+
int SimpleMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
                     const int period,const double& price[],double& buffer[])
  {
   int i,limit;
//--- check for data
   if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
   bool as_series_price=ArrayGetAsSeries(price);
   bool as_series_buffer=ArrayGetAsSeries(buffer);
   if(as_series_price)  ArraySetAsSeries(price,false);
   if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
   if(prev_calculated==0) // first calculation
     {
      limit=period+begin;
      //--- set empty value for first bars
      for(i=0;i<limit-1;i++) buffer[i]=0.0;
      //--- calculate first visible value
      double firstValue=0;
      for(i=begin;i<limit;i++)
         firstValue+=price[i];
      firstValue/=period;
      buffer[limit-1]=firstValue;
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++)
      buffer[i]=buffer[i-1]+(price[i]-price[i-period])/period;
//--- restore as_series flags
   if(as_series_price)  ArraySetAsSeries(price,true);
   if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
    return(rates_total);
  }
//+------------------------------------------------------------------+
//|  Exponential moving average on price array                       |
//+------------------------------------------------------------------+
int ExponentialMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
                          const int period,const double& price[],double& buffer[])
  {
   int    i,limit;
//--- check for data
   if(period<=1 || rates_total-begin<period) return(0);
   double dSmoothFactor=2.0/(1.0+period);
//--- save as_series flags
   bool as_series_price=ArrayGetAsSeries(price);
   bool as_series_buffer=ArrayGetAsSeries(buffer);
   if(as_series_price)  ArraySetAsSeries(price,false);
   if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
     {
      limit=period+begin;
      //--- set empty value for first bars
      for(i=0;i<begin;i++) buffer[i]=0.0;
      //--- calculate first visible value
      buffer[begin]=price[begin];
      for(i=begin+1;i<limit;i++)
         buffer[i]=price[i]*dSmoothFactor+buffer[i-1]*(1.0-dSmoothFactor);
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++)
      buffer[i]=price[i]*dSmoothFactor+buffer[i-1]*(1.0-dSmoothFactor);
//--- restore as_series flags
   if(as_series_price)  ArraySetAsSeries(price,true);
   if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
    return(rates_total);
  }
//+------------------------------------------------------------------+
//|  Linear weighted moving average on price array                   |
//+------------------------------------------------------------------+
int LinearWeightedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
                             const int period,const double& price[],double& buffer[],int &weightsum)
  {
   int        i,limit;
   double     sum;
//--- check for data
   if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
   bool as_series_price=ArrayGetAsSeries(price);
   bool as_series_buffer=ArrayGetAsSeries(buffer);
   if(as_series_price)  ArraySetAsSeries(price,false);
   if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
     {
      weightsum=0;
      limit=period+begin;
      //--- set empty value for first bars
      for(i=0;i<limit;i++) buffer[i]=0.0;
      //--- calculate first visible value
      double firstValue=0;
      for(i=begin;i<limit;i++)
        {
         int k=i-begin+1;
         weightsum+=k;
         firstValue+=k*price[i];
        }
      firstValue/=(double)weightsum;
      buffer[limit-1]=firstValue;
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++)
     {
      sum=0;
      for(int j=0;j<period;j++) sum+=(period-j)*price[i-j];
      buffer[i]=sum/weightsum;
     }
//--- restore as_series flags
   if(as_series_price)  ArraySetAsSeries(price,true);
   if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
    return(rates_total);
  }
//+------------------------------------------------------------------+
//|  Smoothed moving average on price array                          |
//+------------------------------------------------------------------+
int SmoothedMAOnBuffer(const int rates_total,const int prev_calculated,const int begin,
                       const int period,const double& price[],double& buffer[])
  {
   int i,limit;
//--- check for data
   if(period<=1 || rates_total-begin<period) return(0);
//--- save as_series flags
   bool as_series_price=ArrayGetAsSeries(price);
   bool as_series_buffer=ArrayGetAsSeries(buffer);
   if(as_series_price)  ArraySetAsSeries(price,false);
   if(as_series_buffer) ArraySetAsSeries(buffer,false);
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
     {
      limit=period+begin;
      //--- set empty value for first bars
      for(i=0;i<limit-1;i++) buffer[i]=0.0;
      //--- calculate first visible value
      double firstValue=0;
      for(i=begin;i<limit;i++)
         firstValue+=price[i];
      firstValue/=period;
      buffer[limit-1]=firstValue;
     }
   else limit=prev_calculated-1;
//--- main loop
   for(i=limit;i<rates_total;i++)
      buffer[i]=(buffer[i-1]*(period-1)+price[i])/period;
//--- restore as_series flags
   if(as_series_price)  ArraySetAsSeries(price,true);
   if(as_series_buffer) ArraySetAsSeries(buffer,true);
//---
    return(rates_total);
  }
//+------------------------------------------------------------------+

今天写了一个涵盖SMA,WMA,EMA的indicator,同时显示在图表上,代码如下(EMA第一个值默认和第一个收盘价相同)

//+------------------------------------------------------------------+
//|                                              moving_averages.mq4 |
//|                        Copyright 2014, MetaQuotes Software Corp. |
//|                                          http://coderaladdin.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://coderaladdin.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3
//--- plot SMA
#property indicator_label1  "SMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot WMA
#property indicator_label2  "WMA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot EMA
#property indicator_label3  "EMA"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGreen
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- input parameters
input int      period=19;
//--- indicator buffers
double         SMABuffer[];
double         WMABuffer[];
double         EMABuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   IndicatorBuffers(3);
//--- indicator buffers mapping
   SetIndexBuffer(0,SMABuffer);
   SetIndexBuffer(1,WMABuffer);
   SetIndexBuffer(2,EMABuffer);
   string shortname = "EMA("+string(MODE_SMA)+")WMA("+string(MODE_LWMA)+")EMA("+string(MODE_EMA)+"["+string(period)+"]";
   IndicatorShortName(shortname);
   SetIndexLabel(0,"SMA");
   SetIndexLabel(1,"WMA");
   SetIndexLabel(2,"EMA");
   SetIndexDrawBegin(0,period);
   SetIndexDrawBegin(1,period);
   SetIndexDrawBegin(2,period);
   IndicatorDigits(Digits);
   
   if(period<2)
      return(INIT_FAILED);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
if(rates_total < period -1 || period <2)
  {
   return 0;
  }
ArraySetAsSeries(SMABuffer,false);
ArraySetAsSeries(WMABuffer,false);
ArraySetAsSeries(EMABuffer,false);
ArraySetAsSeries(close,false);
if(prev_calculated==0){
      ArrayInitialize(SMABuffer,0);
      ArrayInitialize(WMABuffer,0);
      ArrayInitialize(EMABuffer,0);
      }
      
       CalculateSimpleMA(rates_total,prev_calculated,close); 
       CalculateLWMA(rates_total,prev_calculated,close);
       CalculateEMA(rates_total,prev_calculated,close);
       
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
void CalculateSimpleMA(int rates_total,int prev_calculated,const double &price[])
  {
   int i,limit;
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
   
     {
      limit=period;
      //--- calculate first visible value
      double firstValue=0;
      for(i=0; i<limit; i++)
         firstValue+=price[i];
      firstValue/=period;
      SMABuffer[limit-1]=firstValue;
     }
   else
      limit=prev_calculated-1;
//--- main loop
   for(i=limit; i<rates_total && !IsStopped(); i++)
      SMABuffer[i]=SMABuffer[i-1]+(price[i]-price[i-period])/period;
//---
  }
//+------------------------------------------------------------------+
//|  exponential moving average                                      |
//+------------------------------------------------------------------+
void CalculateEMA(int rates_total,int prev_calculated,const double &price[])
  {
   int    i,limit;
   double SmoothFactor=2.0/(1.0+period);
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
     {
      limit=period;
      EMABuffer[0]=price[0];
      for(i=1; i<limit; i++)
         EMABuffer[i]=price[i]*SmoothFactor+EMABuffer[i-1]*(1.0-SmoothFactor);
     }
   else
      limit=prev_calculated-1;
//--- main loop
   for(i=limit; i<rates_total && !IsStopped(); i++)
      EMABuffer[i]=price[i]*SmoothFactor+EMABuffer[i-1]*(1.0-SmoothFactor);
//---
  }
//+------------------------------------------------------------------+
//|  linear weighted moving average                                  |
//+------------------------------------------------------------------+
void CalculateLWMA(int rates_total,int prev_calculated,const double &price[])
  {
   int        i,limit;
   static int weightsum;
   double     sum;
//--- first calculation or number of bars was changed
   if(prev_calculated==0)
     {
      weightsum=0;
      limit=period;
      //--- calculate first visible value
      double firstValue=0;
      for(i=0;i<limit;i++)
        {
         int k=i+1;
         weightsum+=k;
         firstValue+=k*price[i];
        }
      firstValue/=(double)weightsum;
      WMABuffer[limit-1]=firstValue;
     }
   else
      limit=prev_calculated-1;
//--- main loop
   for(i=limit; i<rates_total && !IsStopped(); i++)
     {
      sum=0;
      for(int j=0;j<period;j++)
         sum+=(period-j)*price[i-j];
      WMABuffer[i]=sum/weightsum;
     }
     }

来看下这个指标的具体效果,在图标中同时显示EMA,SMA,WMA
QQ截图20150314102843
Ok,今天介绍的MA指标就这样了,下次介绍MACD指标

历史拾遗(2014年12月31日四爷爷口述历史整理)

我的曾爷爷那一代(清末)曾是老家当地的富有人家,有40余亩地分布在现在朱家庄穆家庄和荆塘一带,平时会雇人来劳作,也就是小时候课本里的短工长工之类。先简单介绍一下爷爷这一辈的兄弟姐妹,有兄弟4个,姐妹3个,我的大爷爷年轻时死于意外,无子嗣。二爷爷是知识分子,后面详述。老三就是我的亲爷爷,2002年,他87岁时,因食道癌离世。四爷爷如今93岁,身体健康,一个半月前刚做完第二只眼睛的白内障手术。大姑奶奶嫁给了一清苦人家,可怜一生。二姑奶奶嫁到了县城,他儿子也就是我表叔曾是全国优秀教师,现如今桃李满天下,二姑奶奶晚年也算是享了清福,只是在我小学时就过世了。小姑奶奶今年89岁,抗战时期辗转来到上海,后在如今的三甲医院新华医院做护士,直到退休,做过多次心脏手术,并有高血压,身体欠佳,不过精神很棒,并无子嗣,不过有非常非常非常孝顺的继女和继子,都是上海本地人。对了,我能来到这个世界也要谢谢我的姑奶奶,
大爷爷的生平事迹已不可考,也无子嗣,暂时不计,以后也希望能多从四爷爷那边听些关于他的故事。
二爷爷是重点要记录的,他有4子一女,大儿子也就是我堂大伯,今年已经84岁,今年喜得重孙女,四代同堂(关于家族辈分,我只知道从爷爷那辈过来是“承,邦,家,泰”百度知道上看到一个问题,想必是我本家。四爷爷口述的历史还有一个,一朱姓族人因为持有家谱而被害[具体我还要求证,当时没有细问]),身体非常好。大爷爷的一生,跨越晚清,中华民国,中国三个朝代,最终在“新中国”的镇压反革命运动中被处死!据四爷爷说,大爷爷幼时在家念私塾,然后去的东坝念了小学和中学,然后考上了地址在镇江的一所警官学院(google未搜到相关高校资料,猜测应该是民国时期高校),在老家教书一年后分配到当地一个警署任职警官,最后升至乡长。众所周知,共党在49年“解放”南京,也就是在45~49年期间,我家所在地都是国民党的辖区,然而解放后,到了50年后,四爷爷说,共党开始大搞四项运动:1.土地改革,我家四十余亩地这个时候就只能呵呵了;2.镇压反革命,南京作为国民政府的首都,我猜测镇压反革命南京也是重点关照对象吧,每个地方都有些指标,一定要抓出多少个反革命分子才算完成任务。二爷爷由于做过民国政府的乡长,首当其冲便被当地镇压反革命的执行者抓了起来,四爷爷也被抓了,关了5年!!!这个后面再说。二爷爷被抓起来后,先是关押了5个月有余,后来我们村上一些有威望的老人一共15人联名上书要保二爷爷不死,因为二爷爷为人正直,从未与人结下仇怨,本以为这样一来二爷爷可以躲过一劫,谁曾想,本村的一个人(我某个小学同学的爷爷…)还有荆塘村等另外几个村的一些人一起作伪证(猜测是像现如今法院检察官公诉的场景),说我二爷爷在国民政府在职乡长期间如何如何害人如何如何作恶(我立马想到了那些手撕鬼子大片中的那些汉奸!),如此,二爷爷在这镇压反革命运动便成为老毛子大手一挥死去的千千万万“反革命份子”中的一员。我问四爷爷为什么他们要作伪证害死我二爷爷,他们良心上就过得去吗?四爷爷叹口气说,他们给共产党立了功,有每个月60块钱的补贴(每个月还是每年没记清楚,后面再确认)。我问四爷爷后来邓小平上台后各种平反,有没有给二爷爷平反,他说还平什么反,都没有人提这个事情了,大哥哥曾说过,爷爷那一辈是被遗忘的一代,或许能形容下他们的境遇。3.全国各族人民大团结,这个运动好像于我家来说好像并无影响。4.解放台湾,是的,50年的时候就说要“解放”台湾了,四爷爷当年也差点去了台湾,这个后面再详述。
关于我爷爷,他生于民国3年,他的历史我没多问,曾经从父亲口中听到些历史是这样的:爷爷年轻时有些霸道,力气大,爱和人打架,或许是因为家境不错有些吊儿郎当(父亲的描述我并不全信,他不是这段历史亲历者,不过这能够解释二爷爷和四爷爷都是知识分子而我爷爷是个文盲的事实,爷爷年轻时候的事迹,我还要向四爷爷求证)。日本人占领南京8年的时候,听爷爷说过贩猪被日本人关押一个多月。过了三反五反那些老毛子们造出来的运动之后,迎来了惨绝人寰的“自然”灾害,父亲生于1951年,他的幼时便是在这些令人发指的年代度过的。父亲不止100次的和我提起过一句话来形容饿字:“树皮都没得吃”。那时候家里7口人,成人劳动力只有爷爷一个人,奶奶身体不好,又有夜盲症,小孩放牛能挣一点点工分,大伯虽然年长一些,不过他在校读书挣不到工分还需要花钱,所以领粮食的时候总也不够。这自然“灾害”的时候,粮食更是不够了,有一次爷爷三天没有进一口粮食,我父亲他们这些小孩也只有一些麦麸之类的东西吃。长期没有进食,爷爷大腿浮肿,手指按下去一个大洞,再饿下去怕是要成为那3年里面“非正常死亡人数[陈奎德指出毛xx饿死了几千万人]”中的一员了,后来一个表亲因为在生产队的集体食堂里面做事,偷偷给我爷爷弄了些粮食吃,救了我爷爷的命。对了,我查阅维基百科发现,现如今的特权供应竟然是始于那个年代!2002年,爷爷罹患食道癌,我读初一,因为肿瘤阻塞食道无法吃下粮食离世。粮食最终还是要了爷爷的命,真想哭!这边,多说一句,我是爷爷最小的孙子,爷爷最宠我,从02年爷爷走后到现在,我每年里面都会梦到多次爷爷,爷爷临走前还叮嘱大哥哥和表姐以后要多照顾些我。我总是痴想若是爷爷现在还在世,我一定尽我所能让他享福!
四爷爷如今身体还很健康,清瘦,每天还踱着步子在村里上下走动串门,93岁高龄,拐棍都不用,真是让人欣慰!听他自述,19岁就开始当兵,跟着国民党和占领南京的日本人抗争。说到这里,我问南京大屠杀时,日本人有没有到我们高淳来,他说大屠杀之后,日本统治南京八年,高淳,双牌石等等,到处都有日本人的驻点,还在穆家庄和李家庄杀了两个本村的国民党人。而现今桠溪镇境内,有四个当时国民政府下的县政府秘密驻点,分别是句容,高淳,溧水,江宁。四爷爷当兵时,曾给有名的国民党人王昌华在武汉做过一年多法警,王昌华何许人也?我google找到资料:1912年5月5日出生,江苏高淳顾陇庙人(离我村4公里,49年“解放”南京时,顾陇庙村有20多个国名党人转移到台湾),国民党籍。武汉大学毕业,中央政治学校高等科第1期结业。曾任司法行政部科长,重庆实验地方法院检查官及专员,湖北武昌、四川江北等地方法院首席检查官、院长,以及武汉高等特种刑事法庭庭长,兼任武汉大学、汉口大学、中兴大学、中国文化学院教授,高等考试及法官考试审查委员。去台后递补为“国大代表”,历任“司法院”秘书、参事、主任参事、顾问,第二届大法官,光复大陆设计研究委员会委员,中央政策委员会委员,宪政研讨委员会委员,《世界各国宪法大全》编审委员会委员。1990年2月当选为“国民大会”第八次会议主席团主席。曾任“总统府”国策顾问,1996年6月未获续聘。1993年8月被聘为国民党第十四届中央评议委员。http://photo.blog.sina.com.cn/photo/416498dana6fce60117d4。我问四爷爷在王去台湾的时候为什么没有跟着去,他说要走的时候,他的父亲也就是我的曾爷爷去世了,因此未成行。说到台湾,想起来读初中的时候,当时一个王姓同学说他奶奶要去台湾分遗产,当年他的爷爷去了台湾,我读初中那年去世的。今天一问四爷爷,原来四爷爷和那个同学的爷爷熟识,同学的爷爷应该是叫王正汗,湾里村人,当年和顾陇庙村一行人一起去的台湾。没去成台湾直接导致了四爷爷在镇压反革命运动中被关押5年和文革时期被折磨的后果,具体怎么被折磨,我没勇气向四爷爷问,他说到文革只是和我笑笑,不过我父亲亲见过,他说坐老虎凳和那些手撕鬼子抗战片里面特务和日本人折磨俘虏的共产党一样!还有戴高帽游街这些自不必说。。。。。说到四爷爷当兵的历史,他说还曾给一个国军军官朱定深做过两年的警卫,朱定深何许人也?四爷爷说是黄埔军校第三期毕业,我google之,果然找到黄埔军校同学录第3期同学姓名籍贯表中有〈〉朱定深〈〉渊泉〈〉25〈〉江苏〈〉江苏高淳东坝镇吕永泰油坊转〈〉。不过没有找到他的具体官位职级。另外不得不提的是,四爷爷说当年国民党内部也是各种贪污腐败,恩,就是这样。
历史的车轮滚滚向前,下面顺便写一下父亲曾说给我听的一段历史
历史来到了19八9年,我二姑奶奶的小孙子也就是我那个全国优秀教师表叔的三儿子,他当时读大学,或许有人知道六*四,是的,他正是当年的亲历者之一,他在高淳帖邓的大字报,他跑到北京支援,他最后被关押3年。恩,就这样,这段历史的细节,我一定会向他求证的。
还有很多很多“我家的”历史,他们都值得记录!至于文章里面提到的一些名词,你可以上维基百科去看看,或者你可以上youtube看看别人怎么说的。

CI中加入生成一维码的lib

给朋友做的一个项目,其中用到生成条形码,主要用到了http://www.barcodephp.com/这个开源的类库,把它集成到了CI里面,代码和集成方法稍后给出来
1.到http://www.barcodephp.com/en/download下载包
2.解压后,将class文件夹放到application/libraries下面,可以改名为barcode,如果需要用他字体的话,font也放到你放字体的地方
3.application/libraries下面新建Barcode.php

<?php
include 'barcode/BCGFontFile.php';
include 'barcode/BCGColor.php';
include 'barcode/BCGDrawing.php';

include 'barcode/BCGcode39.barcode.php';

class Barcode {
    public $colorFront;
    public $colorBlack;
    public $font;

    function __construct(){
        $this->colorBlack = new BCGColor(255,255,255);
        $this->colorFront = new BCGColor(0,0,0);
//        $this->font = new BCGFontFile('/assets/font/Arial.ttf', 18);//需要字体在这里指定
    }

    public function genBarcode($text) {
        $code = new BCGcode39();

        $code->setScale(2); // Resolution
        $code->setThickness(30); // Thickness
        $code->setForegroundColor($this->colorFront); // Color of bars
        $code->setBackgroundColor($this->colorBlack); // Color of spaces
//        $code->setFont($this->font); // Font (or 0)
        $code->parse($text); // Text

        $drawing = new BCGDrawing('', $this->colorBlack);
        $drawing->setBarcode($code);
        $drawing->draw();

        header('Content-Type: image/png');


        $drawing->finish((BCGDrawing::IMG_FORMAT_PNG));
    }
}

调用的时候,直接load这个barcode,然后调用genBarcode即可

计算web访客的一个会话识别算法的php实现

QQ截图20140506173210

最近在做公司的BI系统,由于很多东西都是探索阶段,做起来遇到很多的问题,下面这个是其中一个计算一次访问会话的实现,还待优化和改进

/**
 * @param $data array(key=>array((int)view_time,url,referer)) order by value asc
 * @param $threshold
 * @param $delta
 * @return boolean
 */
function uvAlgorithm($data, $threshold, $delta) {
    $stack = array();
    $rangeDown = $data[0]['view_time'];
    $vid = md5($rangeDown);
    $rangeUp = $data[0]['view_time'] + $threshold;
//    echo $rangeDown . '~' . $rangeUp . "\n";
//    print_r($data);
    foreach ($data as $k=>$v) {
        if ($k == 0) {
            updateVisitId($v['id'], $vid);
            $stack[] = $v['url'];
            continue;
        }
        if ($v['view_time'] >= $rangeDown && $v['view_time'] < $rangeUp) {
            if (in_array($v['referer'], $stack) || ($data[$k]['view_time'] - $data[$k - 1]['view_time'] < $delta)) {
                $stack[] = $v['url'];
                updateVisitId($v['id'], $vid);
            }
            else {
                updateVisitId($v['id'], md5($v['view_time']));
            }

        }
        else {
            $temp = array_splice($data, $k);
//            print_r($temp);
//            print_r($data);
//            print_r($stack);
            $stack = array();
            if (empty($temp)) {
                return false;
            }
            else {
                uvAlgorithm($temp, $threshold, $delta);
            }
        }
    }
}

也谈rsync

目前工作的公司上线是通过rsync来同步代码的,前公司则是用ftp发布代码到预发布环境然后再用rsync实时同步到线上环境,今天就来看下rsync这个强大的工具

what’s rsync

rsync(remote synchronization)是*nix下一款同步软件,用于远程同步,备份文件,当然也可以本地做同步备份操作。

rsync 可以在中断之后恢复传输;它只传输源文件和目标文件之间不一致的部分;rsync 可以执行完整备份或增量备份。更棒的是,在所有风格的 UNIX 上都可以使用 rsync,包括 Mac OS X,所以很容易连接任何系统。

how to use rsync

shell模式(本地模式)

先来看下目录结构

[root@localhost tmp]# tree -L 2
.
├── rsync1
│   ├── 1.txt
│   ├── a.txt
│   ├── c.txt
│   └── v.txt
├── rsync2
│   └── 1.txt

要将rsync1中的内容完全同步到rsync2中

[root@localhost tmp]# rsync -avz rsync1/ rsync2
sending incremental file list
./
a.txt
c.txt
v.txt

sent 189 bytes  received 72 bytes  522.00 bytes/sec
total size is 0  speedup is 0.00

远程shell模式

[root@localhost tmp]# rsync -avz rsync1/ root@192.168.22.81:/tmp
root@192.168.22.81's password: 
sending incremental file list
./
1.txt
a.txt
c.txt
v.txt

sent 225 bytes  received 91 bytes  9.16 bytes/sec
total size is 0  speedup is 0.00

列表模式

[root@localhost tmp]# rsync rsync1/
drwxr-xr-x        4096 2014/02/20 13:42:21 .
-rw-r--r--           0 2014/02/18 16:41:47 1.txt
-rw-r--r--           0 2014/02/20 13:42:21 a.txt
-rw-r--r--           0 2014/02/20 13:42:21 c.txt
-rw-r--r--           0 2014/02/20 13:42:21 v.txt

这个和ll命令是一样的

服务器模式

在rsyncd下有下列rsync服务的配置

[root@localhost rsyncd]# pwd && ll
/etc/rsyncd
total 12
-rw-r--r-- 1 root root 808 Feb 19 16:21 rsyncd.conf
-rw-r--r-- 1 root root  36 Feb 19 15:10 rsyncd.motd
-rw------- 1 root root  12 Feb 19 15:10 rsyncd.secrets

rsyncd.conf是主要配置文件,

pid file = /var/run/rsyncd.pid  
port = 873
#address = *
uid = root  
gid = root  
use chroot = yes
read only = yes

#limit access to private LANs
hosts allow=*
#hosts deny=*

max connections = 5
motd file = /etc/rsyncd/rsyncd.motd

#This will give you a separate log file
log file = /var/log/rsync.log

#This will log every file transferred - up to 85,000+ per user, per sync
#transfer logging = yes

log format = %t %a %m %f %b
syslog facility = local3
timeout = 300

[root_tmpTrans]  
path = /tmp/rsnctrans
list=yes
ignore errors
auth users = root
secrets file = /etc/rsyncd/rsyncd.secrets
comment = balabala
exclude =   .git/ .svn/

rsyncd.secrets是执行同步、备份的账号,格式为user:password

root:123456

rsyncd.motd是执行时的欢迎信息(message of the day)

hi---------------------------------

现在我们启动rsync服务

rsync --daemon --config=/etc/rsyncd.conf

现在从另一台机器上看这个守护进程

root@ubuntu:/tmp# rsync 192.168.22.81::
hi---------------------------------

root_tmpTrans   balabala

指定模板名称

root@ubuntu:/tmp# rsync 192.168.22.81::root_tmpTrans
hi---------------------------------

Password: 
drwxr-xr-x        4096 2014/02/19 16:43:38 .
-rw-r--r--           0 2014/02/19 15:13:19 a.txt
-rw-r--r--           0 2014/02/19 16:43:38 c.txt
-rw-r--r--           0 2014/02/19 16:37:40 v.txt

注意上面两个例子,访问服务器模式的时候,有两个冒号
此时,直接利用rsync服务器模式,来备份,同步文件,和前面的模式类似

联系上crontab,写好需要的shell脚本,将备份和同步自动话,定时执行,这样就可以应用到更多的场景中。

题外话:1.这篇文章已经在草稿箱躺了2个月了,OMG.2.今天装了markdown插件,第一次用markdown写wordpress,有些地方不是很好用.3.最近心情不好,状态极差.

WEB开发中的请求调试小记

这边就讲一个小发现,以后不定期补充。让调试工具记录下所有的请求,包括各种跳转之前的请求,以前只知道用IE的httpwatch插件来调试,直到周五看了王益同学用firebug调试的时候在net那个tab下有个persist的选项,惊呼发现了新大陆,原来还可以这样!!不用firebug好多年,一直用的chrome做开发,一直都是找chrome插件的来调试跳转请求。。蛋疼。。。然后就果断google了下,其实chrome也有同样的功能,就是在network那个标签下的大黑点preserve log upon navigation,为什么我以前google的时候没找到呢?而且,IE9的dev tools也是有这个功能的!不详述。。

今日两坑

坑1:

$a = 'test';
echo $a['bdd'];

得到结果

t

一个字符串,把它当成数组并取它一个不存在的键值,得到的是第一个字符。今天写一个方法的时候,返回结果可能是字符串也可能是数组,调用这个方法的时候用数组中的某个值来判断,无疑是错的!

坑2:

在post的时候有大量的数据,发现post不过去,原来php在5.3.9以后的版本中加入了最大post数量的限制,默认是1000条,可以在php.ini中找到该项

max_input_vars来做修改。

为什么在5.3.9中加入这个参数?这个就要提到hash冲突的一个漏洞了,这个漏洞在没patch的低版本php中存在,包括java等各种语言中存在。hash表是一种良好的数据结构,当数据被精心构造过之后,会使hash表降级成一个链表结构,在查询数据的时候每次都会发生hash冲突,一次命中率极低,大大降低了效率,这就使得单机DDOS攻击成为可能。因此加入这个post数量限制限制了服务器接收的post数据,即使post过来默认的1000个数据都能精确的造成hash冲突,那么也是在服务器能够承受的范围内了。

可以参考:

参考1

参考2

sed的模式空间和暂存空间

关于sed(stream editor):

————sed是一个批处理(非交互式)编辑器。它可以变换来自文件或者标准输入的输入流。它常被用作管道中的过滤器。由于sed仅仅对其输入扫描一次,因此它比其他交互式编辑器(如ed)更高效。大多数linux发行版都提供了GNU sed,Mac OS X提供了BSD sed。『A Practical Guide to Linux Commands, Editors, and Shell Programming, chapter 13』

sed和awk一样,都是经典的linux神器,网上有大量相关教程,比如很不错的左耳朵耗子博客。今天想记录下之前并没有理解透的暂存空间和模式空间相关的操作(感觉自己智商一直在下降- -)。

模式空间[pattern space]是一个缓冲区,该缓冲区最初保存sed刚刚从输入中读取的行。在将数据放入暂存空间之前,他的内容为空。

暂存空间[hold space]也是一个缓冲区,该缓冲区可以在操作模式空间中的数据时用来暂存数据。

几个命令:

g: 将hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
G: 将hold space中的内容append到pattern space\n后
h: 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
H: 将pattern space中的内容append到hold space\n后
x: 交换pattern space和hold space的内容

看这样一个文件

aladdin@ubuntu:~/tmp$ cat sedtext 
line one
line two
line three

我们看这样一条命令

aladdin@ubuntu:~/tmp$ sed '2,$G;h;$!d' sedtext 
line three
line two
line one

我们来分析一下:

首先,这边sed对sedtext有3个命令的操作

2,$G:从第二行到最后一行执行G命令

h:执行h命令

$!d:删除除了最后一行的所有行

然后看其中具体操作

第一步,sed扫描到第一行,直接执行第二个命令,将模式空间中的内容拷贝到暂存空间中,此时模式空间中是line one,暂存空间中是line one,然后执行第三个命令,删除了模式空间中的第一行,此时模式空间中为空,暂存空间中为line one,

第二步,sed扫描到了第二行,会执行第一个命令G了,此时模式空间中是line two,暂存空间中是line one,G将换行符和暂存空间内容追加到模式空间中,此时模式空间是line two\nline one,暂存空间是line one,然后执行第二个命令,将模式空间中的内容拷贝到暂存空间中,此时模式空间不变,暂存空间为line two\nline one,执行第三个命令之后,模式空间为空,暂存空间为line two\nline one

第三步,sed扫描到第三行,会执行第一个命令G,模式空间为line three,暂存空间是line two\nline one,执行之后模式空间是line three\nline two\nline one,暂存空间是line two\nline one,然后h命令,模式空间不变,暂存空间line three\nline two\nline one然后不执行第三条命令,ok,结束,打印的就是最后模式空间爱你中的内容line three\nline two\nline one

我们可以看下sed '1!G;h;$!d' sedtext也可达到同样效果。