Spa102!開発ブログ

株式の分析ツールを開発しています。
このツールをサービス化することを目標に奮闘中!


テーマ:
株価分析ツールSpa102! で日経平均をローソク足チャートで表示するため
amChartsを使わせもらいました。

このamChartsですが、jsのlibになってるんですが
かなりの高機能なチャートを簡単に実装できます。

rails で実装したので、多少日本向けに変更したソースを参考までに公開します。



Gemfile
gem "amcharts-rails"


application.js
//= require amcharts

views/xxxxx/xxxx.html.erb
......
<%= render :partial => "candlestick_nikkei_avg" %>
......


views/xxxxx/_candlestick_nikkei_avg.html.erb
<div id="chartdiv" style="width:100%; height:400px;"></div>
<div style="float:right;margin-right:20px;">
  <input onChange="changeZoomDates()" style="width:100px; text-align:center" type="text" id="startDate">-
  <input onChange="changeZoomDates()" style="width:100px; text-align:center" type="text" id="endDate">
</div>


  <script type="text/javascript">
      var chart;
      var graph;
      var graphType = "candlestick";
      var maxCandlesticks = 100;

      var dataString = "<%= @nikkei_avg_str -%>";
      var chartData = [];

      AmCharts.ready(function () {
          // first parse data string
          parseData();

          // SERIAL CHART
          chart = new AmCharts.AmSerialChart();
          chart.pathToImages = "/assets/amcharts/";
          chart.dataProvider = chartData;
          chart.categoryField = "date";
          // listen for dataUpdated event ad call "zoom" method then it happens
          chart.addListener('dataUpdated', zoomChart);
          // listen for zoomed event andcall "handleZoom" method then it happens
          chart.addListener('zoomed', handleZoom);

          // AXES
          // category
          var categoryAxis = chart.categoryAxis;
          categoryAxis.parseDates = true; // as our data is date-based, we set this to true
          categoryAxis.minPeriod = "DD"; // our data is daily, so we set minPeriod to "DD"
          categoryAxis.dashLength = 1;
          categoryAxis.tickLenght = 0;
          categoryAxis.inside = true;

          // value
          var valueAxis = new AmCharts.ValueAxis();
          valueAxis.dashLength = 1;
          valueAxis.axisAlpha = 0;
          chart.addValueAxis(valueAxis);

          // GRAPH
          graph = new AmCharts.AmGraph();
          graph.title = "Price:";
          // as candlestick graph looks bad when there are a lot of candlesticks, we set initial type to "line"
          graph.type = "line";
          // graph colors
          graph.lineColor = "#7f8da9";
          graph.fillColors = "#7f8da9";
          graph.negativeLineColor = "#db4c3c";
          graph.negativeFillColors = "#db4c3c";
          graph.fillAlphas = 1;
          // candlestick graph has 4 fields - open, low, high, close
          graph.openField = "open";
          graph.highField = "high";
          graph.lowField = "low";
          graph.closeField = "close";
          // this one is for "line" graph type
          graph.valueField = "close";

          chart.addGraph(graph);

          // CURSOR
          var chartCursor = new AmCharts.ChartCursor();
          chart.addChartCursor(chartCursor);

          // SCROLLBAR
          var chartScrollbar = new AmCharts.ChartScrollbar();
          chartScrollbar.scrollbarHeight = 30;
          chartScrollbar.graph = graph; // as we want graph to be displayed in the scrollbar, we set graph here
          chartScrollbar.graphType = "line"; // we don't want candlesticks to be displayed in the scrollbar
          chartScrollbar.gridCount = 4;
          chartScrollbar.color = "#FFFFFF";
          chart.addChartScrollbar(chartScrollbar);

          // WRITE
          chart.write("chartdiv");
      });


      // this method is called when chart is first inited as we listen for "dataUpdated" event
      function zoomChart() {
          // different zoom methods can be used - zoomToIndexes, zoomToDates, zoomToCategoryValues
          chart.zoomToIndexes(chartData.length - 30, chartData.length - 1);
      }

      // this methid is called each time the selected period of the chart is changed
      function handleZoom(event) {
          var startDate = event.startDate;
          var endDate = event.endDate;
//          document.getElementById("startDate").value = AmCharts.formatDate(startDate, "DD/MM/YYYY");
//          document.getElementById("endDate").value = AmCharts.formatDate(endDate, "DD/MM/YYYY");
          document.getElementById("startDate").value = AmCharts.formatDate(startDate, "YYYY/MM/DD");
          document.getElementById("endDate").value = AmCharts.formatDate(endDate, "YYYY/MM/DD");

          // as we also want to change graph type depending on the selected period, we call this method
          changeGraphType(event);
      }

      // changes graph type to line/candlestick, depending on the selected range
      function changeGraphType(event) {
          var startIndex = event.startIndex;
          var endIndex = event.endIndex;

          if (endIndex - startIndex > maxCandlesticks) {
              // change graph type
              if (graph.type != "line") {
                  graph.type = "line";
                  graph.fillAlphas = 0;
                  chart.validateNow();
              }
          } else {
              // change graph type
              if (graph.type != graphType) {
                  graph.type = graphType;
                  graph.fillAlphas = 1;
                  chart.validateNow();
              }
          }
      }

      // Parse data
      function parseData() {
          // split data string into array
          var rowArray = dataString.split("\n");
          // loop through this array and create data items
          for (var i = rowArray.length - 1; i > -1; i--) {
              var row = rowArray[i].split(",");
              var dateArray = row[0].split("-");
              // we have to subtract 1 from month, as months in javascript are zero-based
              var date = new Date(Number(dateArray[0]), Number(dateArray[1]) - 1, Number(dateArray[2]));
              var open = row[1];
              var high = row[2];
              var low = row[3];
              var close = row[4];

              chartData.push({
                  date: date,
                  open: open,
                  high: high,
                  low: low,
                  close: close
              });
          }
      }

      // this method converts string from input fields to date object
      function stringToDate(str) {
          var dArr = str.split("/");
          var date = new Date(Number(dArr[2]), Number(dArr[1]) - 1, dArr[0]);
          return date;
      }

      // this method is called when user changes dates in the input field
      function changeZoomDates() {
          var startDateString = document.getElementById("startDate").value;
          var endDateString = document.getElementById("endDate").value;
          var startDate = stringToDate(startDateString);
          var endDate = stringToDate(endDateString);
          chart.zoomToDates(startDate, endDate);
      }
  </script>


controllers/xxxxxx.rb
・・・・
@nikkei_avg_str = nikkei_avg_str
・・・・


  def self.nikkei_avg_str
    nikkei_averages = DailyStockPrice.where('code = ? and hiduke >= ? and hiduke <= ?', NIKKEI_AVERAGE_CODE, Date.today - 1.year, Date.today).order('hiduke desc')
    candle_chart_str(nikkei_averages)
  end

  private

  def self.candle_chart_str(daily_stock_prices)
    str = ''
    # '日付,始値,高値,安値,終値\n'
    # 行末に\nがあるとちゃんと表示されない。
    daily_stock_prices.each_with_index do |daily_stock_price, i|
      str = str + '\n' if i > 0
      str = str + daily_stock_price.hiduke.strftime('%Y-%m-%d') + ','
      str = str + daily_stock_price.hajimarine.to_s + ','
      str = str + daily_stock_price.takane.to_s + ','
      str = str + daily_stock_price.yasune.to_s + ','
      str = str + daily_stock_price.owarine.to_s
    end
    str

  end




注意
amChartsのサイトからamCharts.jsをダウンロードして、jsをインクルードしたら
production環境でエラーになりました。
gemでインストールすることで解消しました。





amChartsはかなりの優れもので
他にも、下記のようなものもあったりして
http://www.amcharts.com/stock-chart/multiple-panels/

株価と出来高も一緒に表示できちゃいそうですね。


ありがとうございます。
amChartsさん

AD
いいね!した人  |  コメント(0)

AD

Amebaおすすめキーワード

Ameba人気のブログ

Amebaトピックス

ランキング

  • 総合
  • 新登場
  • 急上昇