[Power BI] 続・DAXで株価のロウソク足チャートに移動平均線を描く

　前回の「[[Power BI] DAXで株価のロウソク足チャートに移動平均線を描く](https://qiita.com/spumoni/items/7018f2a56282aa50c706)」の続きです。DAX式が怪しいので、まだ検証中の記事です。

# RANKXを使って計算する

　SQLBIのビデオ「[Rolling average with working days in DAX](https://youtu.be/mOVDGFyfWYg)」では、最後にRANKXを使用して、以下のように移動平均線を作成しています。

```text:SQLBI
Rolling 30WD Live =
VAR Dates =
    ADDCOLUMNS (
        ALL ( 'Date'[Date], 'Date'[Working Day] ),
        "@Working Day Number",
            RANKX (
                FILTER ( ALL ( 'Date' ), 'Date'[Working Day] ),
                'Date'[Date],
                ,
                ASC
            ) - NOT 'Date'[Working Day]
    )
VAR NumberOfDays = 30
VAR MaxDate = MAX ( 'Date'[Date] )
VAR MaxWorkingDay =
    MAXX (
        FILTER ( Dates, 'Date'[Date] <= MaxDate ),
        [@Working Day Number]
    )
VAR MinWorkingDay = MaxWorkingDay - ( NumberOfDays - 1 )
VAR MaxDateEver = CALCULATE ( MAX ( Sales[Order Date] ), REMOVEFILTERS() )
VAR DatesToUse =
    FILTER (
        Dates,
        [@Working Day Number] >= MinWorkingDay &&
        'Date'[Date] <= MaxDate
    )
VAR Result =
    DIVIDE (
        CALCULATE  ( [Sales Amount], DatesToUse, REMOVEFILTERS ( 'Date' ) ),
        NumberOfDays
    )
RETURN
    IF ( MaxDate <= MaxDateEver, Result )
```

　これを読み解くのは大変ですが、今回の株価のデータに合わせて作成してみたいと思います。

　まず、終値の平均値を求めるメジャーを作成します。

```text:PriceAve
PriceAve = AVERAGE(df[close])
```

　SQLBIのデータとの違いは、SQLBIでは日付テーブルに **'Date'[Working Day]** という項目が存在し、営業日はtrue、休業日はfalseが入っています。私のデータでは、日付テーブルにそのような項目を設けず、株価データが存在するかどうかで営業日かどうかを判定することにします。

```text:RANKXを使用したバージョン
VAR Dates = 
    ADDCOLUMNS( 
        ALL( '日付テーブル'[Date] ), 
        "@Working Day Number", 
        RANKX( 
            FILTER( ALL( '日付テーブル' ), [PriceAve] > 0 ), 
            '日付テーブル'[Date], 
            , 
            ASC
        ) - ( SUM( df[close] ) = 0 )
    )
VAR NumberOfDays = 5
VAR MaxDate = MAX( '日付テーブル'[Date] )
VAR MaxWorkingDay =
    MAXX(
        FILTER( Dates, '日付テーブル'[Date] <= MaxDate ),
        [@Working Day Number]
    )
VAR MinWorkingDay = MaxWorkingDay - ( NumberOfDays - 1 )
VAR MaxDateEver =
    CALCULATE( MAX( df[date] ), REMOVEFILTERS( ) )
VAR DatesToUse =
    FILTER(
        Dates,
        [@Working Day Number] >= MinWorkingDay
            && [Date] <= MaxDate
    )
VAR Result =
    CALCULATE(
        [PriceAve],
        DatesToUse,
        REMOVEFILTERS( '日付テーブル' )
    )
VAR MarketOpenDate = MAX( df[date] )
RETURN
    IF( MarketOpenDate, Result )
```

# NETWORTKDAYSを使用したバージョン

　最近リリースされたNETWORKDAYSを使ってみます。日付テーブルと株価データの日付を使って休日テーブル holiday を作成し、NETWORKDAYSの引数に入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/591df2ed-afae-d5d5-3aec-c0344e349be0.png)

```text:NETWORKDAYSを使ったバージョン
VAR MinDateEver =
    CALCULATE( MIN( df[date] ), REMOVEFILTERS( ) )
VAR MaxDate = MAX( '日付テーブル'[Date] )
VAR Dates =
    ADDCOLUMNS(
        ALL( '日付テーブル'[Date] ),
        "@Working Day Number",
            NETWORKDAYS( MinDateEver, '日付テーブル'[Date], 1, holiday )
    )
VAR NumberOfDays = 5
VAR MaxWorkingDay =
    MAXX(
        FILTER( Dates, '日付テーブル'[Date] <= MaxDate ),
        [@Working Day Number]
    )
VAR MinWorkingDay = MaxWorkingDay - ( NumberOfDays - 1 )
VAR MaxDateEver =
    CALCULATE( MAX( df[date] ), REMOVEFILTERS( ) )
VAR DatesToUse =
    FILTER(
        Dates,
        [@Working Day Number] >= MinWorkingDay
            && [Date] <= MaxDate
    )
VAR Result =
    CALCULATE(
        [PriceAve],
        DatesToUse,
        REMOVEFILTERS( '日付テーブル' )
    )
VAR MarketOpenDate = MAX( df[date] )
RETURN
    IF( MarketOpenDate, Result )
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/dfa11c79-9340-cc4a-4f34-ec2171df33ff.png)