zaqimon 發表於 12-11-26 23:16

不同視窗同步捲動縮放

本帖最後由 zaqimon 於 12-11-26 23:14 編輯

之前已經有回覆別的文章
我又稍微修改一下程式
加入ZoomRatio變數控制主視窗及被控制視窗之間的顯示日數比例
例如日線及周線就設定ZoomRatio=5就可以顯示幾乎同比例的bar數量
在日線以上週期的視窗之間運作基本上都沒有什麼大問題

我還有嘗試加入台指期1min/5min的同步
請在include之前自行加入TaifexHack = 1;
ZoomRatio也設成5
順順的用習慣的話應該是還堪用啦
但其實我發現問題還蠻多的
目前程式裡面先假設所有周末都不是交易日直接跳過
如果大家有更好的做法可以自行修改



請將最下方AFL放到Include資料夾內且命名為iZoomer.afl
然後在你希望控制連動的主視窗內加入下面程式碼即可
UseZoomer = ParamToggle("Use Zoomer?", "No|Yes", 0);
ZoomRatio = Param("Zoomer ZoomRatio", 5, 0.1, 10, 0.1);
//TaifexHack = 1;
#include_once <iZoomer.afl>
iZoomer.afl
/*

Synchronous scrolling on all windows in AmiBroker

<Usage>
Put this AFL in the Include Folder.
Add below lines into your AFL
UseZoomer = ParamToggle("Use Zoomer?", "No|Yes", 0);
ZoomRatio = Param("Zoomer ZoomRatio", 1, 0.1, 10, 0.1); // 5 is a good ratio for daily/weekly pair
// TaifexHack = 1; // work around for Taifex intraday 1min/5min pair
#include_once <iZoomer.afl>


zaqimon
Add ZoomRatio for showing multiple(x2, x5, x0.7, ...) of current window view range
TaifexHack=1, still not perfect, because it is hard to 'jump' those non trading period. Is there any better idea?


zaqimon
original AFL from http://finance.groups.yahoo.com/group/amibroker/message/141912
I did a slight modification.

*/

function Date2Day( wd_dt) /* convert date to weekday */
{
    wd_datenum = DateTimeConvert(0, (wd_dt));
    wd_c = int( wd_datenum / 100 / 100 / 100 + 19); // datenum start from 1900
    wd_y = int((wd_datenum / 100 / 100) % 100);
    wd_m = int((wd_datenum / 100) % 100);
    wd_d = int( wd_datenum % 100);
    // if Jan., Feb., assume it to be last year's 13th, 14th month.
    if(wd_m<=2)
    {
      wd_m += 12;
      wd_y -= 1;
    }
    // w = (y++-2c++d-1) mod 7
    // formula from http://zh.wikipedia.org/wiki/%E8%94%A1%E5%8B%92%E5%85%AC%E5%BC%8F
    wd_w = wd_y + int(wd_y / 4) + int(wd_c / 4) - 2 * wd_c + int(26 * (wd_m + 1) / 10) + wd_d - 1;
    wd_w = ((wd_w % 7) + 7) % 7; // if -5, -12, -19, ... , make it to be +2
    return int(wd_w); // 0:Sun, 1:Mon, ...
}

function ZqZoomSync( force )
{
    global ZoomRatio;
    local LastBarIndex, FirstBarIndex, prevLastBarIndex, prevFirstBarIndex, prevFirstDateTime, DT, BI, LastDateTime, FirstDateTime, LastDateTimestr, FirstDateTimestr;
    local reuseLastDTDiff, DTDiff;
    local OAB, OAD, dcount, i, OADoc, OAW, OADocWin, res;
    // Get a count of the number of documents
    OAB = CreateObject( "Broker.Application" );
    OAD = OAB.Documents;
    dcount = OAD.Count;
    // Process multiple windows (documents)
    res = False;
    if ( dcount > 1 )
    {
      // Get current and last start and end DateTimes's
      LastBarIndex = Status( "LastVisibleBarIndex" );
      FirstBarIndex = Status( "FirstVisibleBarIndex" );
      //Nblankbar = Status( "LastVisibleBarIndex" ) - BarCount; // not used !!
      
      // BarIndex may always be the same due to QuickAFL, check prevFirstDateTime in addition
      prevLastBarIndex = Nz( StaticVarGet( "_prevLastVisibleBarIndex" ) );
      prevFirstBarIndex = Nz( StaticVarGet( "_prevFirstVisibleBarIndex" ) );
      prevFirstDateTime = Nz( StaticVarGet( "_prevFirstDateTime" ) );
      prevDTDiff = Nz( StaticVarGet( "_prevDTDiff" ) );
      
      // use this to prevent changing zoom range if bar counts in current window not changed,
      // or you may see bars in other windows quiver back and forth while scrolling
      reuseLastDTDiff = False;
      if(prevLastBarIndex-prevFirstBarIndex == LastBarIndex-FirstBarIndex AND prevDTDiff != 0)
      {
            reuseLastDTDiff = True;
      }
      
      // move outside if() statement for checking prevFirstDateTime
      DT = DateTime();
      BI = BarIndex();
      LastDateTime = LastValue( ValueWhen( LastBarIndex == BI, DT ) ); // LastDateTime could be empty
      FirstDateTime = LastValue( ValueWhen( FirstBarIndex == BI, DT ) );
      
      // Check for a new date/time range
//      _TRACE(""+FirstBarIndex+", "+LastBarIndex);
//      _TRACE(""+FirstDateTime+", "+LastDateTime);
      if ( LastBarIndex != prevLastBarIndex OR FirstBarIndex != prevFirstBarIndex OR FirstDateTime != prevFirstDateTime OR force )
      {

            LastDateTimestr = DateTimeToStr( LastDateTime );
            DTDiff = DateTimeDiff(LastDateTime, FirstDateTime); // in second
            if(reuseLastDTDiff)
            {
                DTDiff = prevDTDiff;
            }
            if(typeof(ZoomRatio) != "number")
            {
                ZoomRatio = 1; // default ZoomRatio
            }
            FirstDateTimestr = DateTimeToStr(DateTimeAdd(LastDateTime, -ZoomRatio * DTDiff, in1Second));
            
            if(typeof(TaifexHack) == "number" AND TaifexHack==1) // Taifex intraday hack, but still not perfect
            {
                tn = DateTimeConvert(1, StrToDateTime(FirstDateTimestr));
                if(tn < 084500)
                {
                  FirstDateTimestr = DateTimeToStr(DateTimeAdd(LastDateTime, -ZoomRatio * DTDiff - 19*3600, in1Second)); // try to 'jump' non trading hours
                  wd = Date2Day(StrToDateTime(FirstDateTimestr));
                  // assume weekend non trading days, 'jump', of course this is not perfect solution
                  if(wd == 0)
                  {
                        FirstDateTimestr = DateTimeToStr(DateTimeAdd(LastDateTime, -ZoomRatio * DTDiff - 19*3600 - 2*24*3600, in1Second));
                  }
                }
            }

            // Set the new last values
            StaticVarSet( "_prevLastVisibleBarIndex", LastBarIndex );
            StaticVarSet( "_prevFirstVisibleBarIndex", FirstBarIndex );
            StaticVarSet( "_prevFirstDateTime", FirstDateTime );
            StaticVarSet( "_prevDTDiff", DTDiff );
            
//            _TRACE(""+FirstDateTimestr+", "+LastDateTimestr);
            // Loop through the document collection
            for ( i = 0; i < dcount; i++ )
            {
                // If it is not the active document -
                OADoc = OAD.Item( i );
                // NOTE - it doesn't hurt to sync the current window and it makes all
                // windows have no blank bars on the right so they look the same
                // I think it's reasonable for not syncing ActiveDocument.
                // Something not belong to the ActiveDocument was shown when not syncing ActiveDocument with multi-threaded charts options disabled.
                if ( OADoc != OAB.ActiveDocument )
                {
                  // Get the document window and zoom to range
//                  _TRACE( " Zoom to range document - " + i + " , " + FirstDateTimestr + " - " + LastDateTimestr );
                  OADW = OADoc.Windows;
                  // Document window count assumed to be 1
                  OADocWin = OADW.Item( 0 );
                  OADocWin.ZoomToRange( FirstDateTimestr, LastDateTimestr ); // this function failed to update chart at the right most margin with empty LastDateTimestr. Just minor issue, don't care.
                }
            }
            res = True;
      }
    }
    return res;
}

//Call for synchronization
If (UseZoomer)
   ZqZoomSync( False ); // set True will enter infinite loop if we also update ActiveDocument






補充內容 (12-12-20 11:32):
補充程式碼在三樓

hipper68 發表於 12-11-26 23:47

真的太讚了...
一定要推一下...

謝謝大大的分享...

zaqimon 發表於 12-12-20 11:32

在第83行處插入下面的程式碼
避免LastDateTime為0的狀況
這樣就算捲動到畫面最右邊blank bar的地方也都還能夠同步// make sure LastDateTime non-zero.
      if(DateTimeDiff(LastDateTime,FirstDateTime)<0) // roll back to the last non-empty bar index
      {
            for(i=BarCount-1; i>0; i--) // all array has BarCount size, BI value has nothing to do with BarCount
            {
                if(DateTimeDiff(DT,FirstDateTime)>0) // we saw the REAL last bar, replace the values.
                {
                  LastBarIndex = BI;
                  LastDateTime = DT;
                  break;
                }
            }
      }

purpletopman68 發表於 16-12-3 08:54

為何他是不通過的???
頁: [1]
查看完整版本: 不同視窗同步捲動縮放