【Python】D3.js でWEBページにローソク足チャートを描画する

2018年5月20日Python,開発

おはようございます。

大分間が空いてしまいました。なんだか極端ですね。
予定通り、D3.jsとTechan.js を使ってチャートの描画をしてみました。

プログラムは前回のものを流用します。

スポンサーリンク

画面の修正

描画用のライブラリ読み込み

「head」要素に次の記述を追加
Main.html

    <script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
    <script type="text/javascript" src="http://techanjs.org/techan.min.js"></script>

チャート表示領域の追加

資産情報の下に表示用の領域を追加します。
Main.html

    <div style="clear:both; padding-top:10px;">
       <div class="entry_title">
          <div class="pull_left">ローソク足チャート</div>
          <div class="pull_right">
             <input type="button" value="更新" />
          </div>
       </div>
       <div id="chartContainer">
       </div>
    </div>

スタイルの追加

style.css

    /**
     * ローソク足チャート用の定義
     */
    text {
        fill: #000;
    }
    path.candle {
        stroke: #000000;
    }
    path.candle.body {
        stroke-width: 0;
    }
    path.candle.up {
        fill: #00AA00;
        stroke: #00AA00;
    }
    path.candle.down {
        fill: #FF0000;
        stroke: #FF0000;
    }

プログラム修正

サーバー側
OHLCの情報をJSON形式に変換して返すメソッドを追加

BfTool.py

class GetOhlcJson(RequestHandler):
    """
    OHLC情報を取得
    """

    def initialize(self):
        logging.info("GetOhlcJson [initialize]")

    def get(self):
        logging.info("GetOhlcJson [post]")

        api = BfApi()

        # 過去1時間のデータを取得
        end = datetime.now()
        start = end - timedelta(hours=2)
        df = api.get_ohlc(start=start, end=end, span=60)

        # X軸に表示するための時間配列を生成
        dates = [(start + timedelta(minutes=mi)).strftime('%Y-%m-%d %H:%M:%S') for mi in range(121)]

        # Json形式に変換
        data = pd.DataFrame({'Date': dates, 'Open': df[1], 'High': df[2], 'Low': df[3], 'Close': df[4], 'Vlume': df[5]})

        self.write(data.to_json(orient="records"))

URLマッピングの追加

BfTool.py

app = tornado.web.Application([
    (r"/", MainHandler),
    (r"/ws", SendWebSocket),
    (r"/balance", GetBalanceHandler),
    (r"/execution", GetExecutionHandler),
    (r"/childOrder", GetChildOrderHandler),
    (r"/sendOrder", SendChildOrderHandler),
    (r"/cancelOrder", CancelChildOrderHandler),
    (r"/sendTicker", SendTicker),
    (r"/startTicker", StartTicker),
    (r"/stopTicker", StopTicker),
    (r"/sendLine", SendLine),
    (r"/getTicker", GetTicker),
    (r"/getOhlc", GetOhlc),
    (r"/getOhlcJson", GetOhlcJson)
    ],
    template_path=os.path.join(os.getcwd(), "templates"),
    static_path=os.path.join(os.getcwd(), "static"),
    js_path=os.path.join(os.getcwd(), "js"),
)

クライアント側

JSONデータを取得し、D3.js でチャートを描画する処理を追加

script.js

/**
 * JSON形式でローソク足情報を取得して表示.
 */
function updateChart() {

    // 表示領域の設定
    var margin = {top: 20, right: 20, bottom: 30, left: 50},
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

    // 日付変換メソッド
    var parseDate = d3.timeParse("%Y-%m-%d %H:%M:%S");

    // 横軸の設定
    var x = techan.scale.financetime()
            .range([0, width]);

    // 縦軸の設定
    var y = d3.scaleLinear()
            .range([height, 0]);

    // ローソク足の設定
    var candlestick = techan.plot.candlestick()
            .xScale(x)
            .yScale(y);

    var xAxis = d3.axisBottom()
            .scale(x)
            .tickFormat(d3.timeFormat("%H:%M")) // 分足なので、時:分表示にする
            .ticks(5) // 5データずつにメモリ表示;

    var yAxis = d3.axisLeft()
            .scale(y);

    // チャートをクリアしてから表示
    if ($("#chartContainer svg").length)
    {
        $("#chartContainer svg").remove();
    }

    var svg = d3.select("#chartContainer").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // サーバーからJSONデータを取得し、コールバック関数で描画処理を実施
    d3.json("getOhlcJson", function(error, data) {

        // 日時で並び替えを行う
        var accessor = candlestick.accessor();
        data = data.slice(0, 200).map(function(d) {
            return {
                date: parseDate(d.Date),
                open: +d.Open,
                high: +d.High,
                low: +d.Low,
                close: +d.Close,
                volume: +d.Volume
            };
        }).sort(function(a, b) { return d3.ascending(accessor.d(a), accessor.d(b)); });

        // ページに要素を追加していく
        svg.append("g")
                .attr("class", "candlestick");

        svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")");

        svg.append("g")
                .attr("class", "y axis")
                .append("text")
                .attr("transform", "rotate(-90)") // Y軸ラベルを縦書きに
                .attr("y", 6)
                .attr("dy", ".71em")
                .style("text-anchor", "end")
                .text("価格(円)");

        draw(data.slice(0, data.length-20));
    });

    /**
     * 描画関数
     */
    function draw(data) {
        x.domain(data.map(candlestick.accessor().d));
        y.domain(techan.scale.plot.ohlc(data, candlestick.accessor()).domain());

        svg.selectAll("g.candlestick").datum(data).call(candlestick);
        svg.selectAll("g.x.axis").call(xAxis);
        svg.selectAll("g.y.axis").call(yAxis);
    }
}

上記メソッドを画面起動時に呼び出せばOKです。

起動してみる

ローソク足チャート

無事に描画されました。
とりあえずは起動時のみですが、1分単位で再描画すればリアルタイムチャートになりそうですね。

まとめ

次回は取引高や移動平均線なんかもやってみたいと思います。

ではでは。

 

スポンサーリンク


関連するコンテンツ

2018年5月20日Python,開発Bitflyer,D3.js,Python,Techan.js,プログラミング,ライブラリ,ローソク足

Posted by doradora