IT」カテゴリーアーカイブ

MySqlでDB、テーブル作成メモ 備忘録

MySqlでDB、テーブル作成メモ(条件はユーザはすでに作成済)
株式市場の企業の株価と出来高を登録する。
pythonを使ったスクレイピング処理をこれから行う。この記事にはPythonの記載はない。
mysqldbを使用していたがmysql-connector-pythonが良いらしいのでpip install済

ターミナルでの作業

最近忘れっぽくて、使っていないコマンドをどんどん忘れている。SQL文も忘れてるので、備忘録メモとして記載しておく。記憶力の低下に抵抗せずに、メモをしていつでも思い出せるかメモを見ながら作業するようにする。

・ユーザはmaseda
mysql -u maseda -p
psssはTes*****にした。上に記載。このパスワードはデモ用なので知られてOK

・DBを作成
CREATE DATABASE YahooFinance DEFAULT CHARACTER SET utf8mb4;

・DBを指定する
use YahooFinance;

重複を避けるときはUNIQUEを使う
UNIQUE uni_Code int(5) NOT NULL,
>>今回は使用せず
mysqlのコメントは #,--(ハイフン2つ) /*  */ がある
CodeについてはUNIQUEユニークにしない、毎回同じ企業コードが入るかも

・テーブルを作成
CREATE TABLE Table_Dekidaka(
ID int(11) NOT NULL AUTO_INCREMENT,
Code int(5) NOT NULL,
Market text,
Name text,
Price int(11) ,
Volume int(14),
PreviousVolume int(14),
VolumePer float,
StockDate DATE,
CreateDate DATETIME,
Yobi text,
PRIMARY KEY (ID)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

>>オートインクリメントのIDは、PRIMARY KEY(ID)が必要。ないとエラーになる。

mysql> show tables;
mysql> show columns from Table_Dekidaka;

+----------------+----------+------+-----+---------+----------------+
| Field          | Type     | Null | Key | Default | Extra          |
+----------------+----------+------+-----+---------+----------------+
| ID             | int      | NO   | PRI | NULL    | auto_increment |
| Code           | int      | NO   |     | NULL    |                |
| Market         | text     | YES  |     | NULL    |                |
| Name           | text     | YES  |     | NULL    |                |
| Price          | int      | YES  |     | NULL    |                |
| Volume         | int      | YES  |     | NULL    |                |
| PreviousVolume | int      | YES  |     | NULL    |                |
| VolumePer      | float    | YES  |     | NULL    |                |
| StockDate      | date     | YES  |     | NULL    |                |
| CreateDate     | datetime | YES  |     | NULL    |                |
| Yobi           | text     | YES  |     | NULL    |                |
+----------------+----------+------+-----+---------+----------------+
11 rows in set (0.03 sec)

mysql> 
権限がないときは、権限を与える。
GRANT SHOW DATABASES ON *.* to maseda@localhost;
これでいいはず。もしこれでだめな場合は、必要な権限を与えて。

---
python
mysqldbを使用していたがmysql-connector-pythonが良いらしい。
pip install mysql-connector-python

pip list 一覧表示 OK

 

python、テキストファイル出力、配列に文字を連結するだけ

#python、トレーディングビューのリストに追加するテキストファイル出力、配列に文字を連結するだけ
#必要な情報は、リスト名(テキストファイル名)、企業コード(このコードは調べたい企業コードなので、これだけは自分で探さないといけない)

#トレーディングビューのウォッチリスト(右側)のインポート(、、、のようなアイコン)で取り込める。テキスト名がリスト名になる
#複数企業の登録が楽になるのでチャートを選ぶのが楽になる。

import os
import re
import sys
import datetime
import glob#ファイル一覧
import shutil#move


class twList:
    def __init__(self):
        print()
    def outputText(self,codeList,filename):
        print("文字列処理開始")
        path='/Users/toshiromaseda/Documents/2021年/2021年株/トレーディングビュー/'
        os.chdir(path)#ディレクトリ変更
        print(os.getcwd())#ディレクトリ確認
        try:
            ofile=open(filename+'.txt','tw') 
        except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
            print("ファイルが見つかりません", e)
        except Exception as e: # Exceptionは、それ以外の例外が発生した場合
            print(e)
        #ここで処理する
        #
        addStr="TSE:"
        outputStr=""

        i=0
        for f in codeList:
            if i==len(codeList)-1:
                outputStr+=addStr+str(f)#最後の配列の要素にはカンマを付けない。
            else:    
                outputStr+=addStr+str(f)+','#配列の要素ごとにカンマを付ける
            i+=1    
        print(outputStr)    
        print("文字列処理終了")
        i=0
        #OUTPUT
        ofile.write(outputStr)
        ofile.close()
        
###START
print("START#####################################")
codeList=[2345,
         2670,
         2700,
         3486,
         3646,
         3696,
         4004,
         4544,
         4587,
         4619]#0217記事
fileName="0217記事"#.txtなしで記載すること

if fileName!='' and len(codeList)!=0:
    cList=twList()
    cList.outputText(codeList,fileName)
    print(fileName)


print("End#####################################")

出力例

START#####################################

文字列処理開始
/Users/toshiromaseda/Documents/2021年/2021年株/トレーディングビュー
TSE:2345,TSE:2670,TSE:2700,TSE:3486,TSE:3646,TSE:3696,TSE:4004,TSE:4544,TSE:4587,TSE:4619
文字列処理終了
0217記事
End#####################################

Pythonを使ってヤフーファイナンス日経平均株価の時系列を取得、スクレイピング

Python を使ってヤフーファイナンス 日経平均株価の時系列を取得、スクレイピング
#https://stocks.finance.yahoo.co.jp/stocks/history/?code=998407.O
#日経平均株価の時系列のテーブル表から該当の文字列を取得する、日付 始値 高値 安値 終値

import time
from selenium import webdriver
import csv
import datetime
import os

class jikeiretsu:
    def __init__(self,day,kopen,khigh,klow,kclose):
        self.day=day
        self.kopen=kopen
        self.khigh=khigh
        self.klow=klow
        self.kclose=kclose
        
class yahooFinanceTimeline:
    def __init__(self):
        self.hello="yahoo Finace"
        
    def getTimeline(self):
        #print("カプセルにして取得")
         #動作確認のためのメソッド
        # 仮想ブラウザ起動、URL先のサイトにアクセス
        driver = webdriver.Chrome('/usr/local/bin/chromedriver')#ここでエラーになったらパスが違うかchromedriverをインストールする
        #他のエラーで、「unexpectedly exited. Status code was:-9」だったら、Macの場合はシステム環境設定 → セキュリティとプライバシー で許可すればよい
        url='https://stocks.finance.yahoo.co.jp/stocks/history/?code=998407.O'
        driver.get(url)
        time.sleep(1)
        #title = driver.title
        #print(title)
        main = driver.find_element_by_id("main")
        el = main.find_element_by_css_selector(".padT12.marB10.clearFix")
        tableElem = el.find_element_by_tag_name("table")
        trs = tableElem.find_elements_by_tag_name("tr")
        ths = trs[0].find_elements_by_tag_name("th")
        kabuka=""
        #thタグは1行目のTRにだけ存在する。
        for f in range(0,len(ths)):#日付	始値	高値	安値	終値
            ths[f].text
            kabuka+=ths[f].text+" "
        print(kabuka)
        jikeiretsuArray=[]
        for i in range(0,len(trs)):
            tds = trs[i].find_elements_by_tag_name("td")
            if len(tds)>=5:
                getJikeiretsu=jikeiretsu(tds[0].text,tds[1].text,tds[2].text,tds[3].text,tds[4].text)
                jikeiretsuArray.append(getJikeiretsu)
            else: 
                print("tdsの数が足りない行があるので無視")
        time.sleep(1)    
        driver.close()#起動したウィンドウを閉じる
        print("通常出力日付	始値	高値	安値	終値")
        for f in range(0,len(jikeiretsuArray)):
            print(jikeiretsuArray[f].day,jikeiretsuArray[f].kopen,jikeiretsuArray[f].khigh,jikeiretsuArray[f].klow,jikeiretsuArray[f].kclose)
        print('+----------------------+')
        print("個人的出力順、CSVカンマ区切りで 桁区切りのカンマは削除、昇順day,High,Low,Open,Close,AdjClose")#("個人的な利用の出力順、昇順day,High,Low,Open,Close,AdjClose")    
        count=len(jikeiretsuArray)
        tmpstr=""    
        for n in reversed(range(count)):#).replace(',','') カンマを削除
            tmpstr=jikeiretsuArray[n].day+","+jikeiretsuArray[n].khigh.replace(',','')+","+jikeiretsuArray[n].klow.replace(',','')+","+\
                  jikeiretsuArray[n].kopen.replace(',','')+","+jikeiretsuArray[n].kclose.replace(',','')+","+\
                  jikeiretsuArray[n].kclose.replace(',','')
            print(tmpstr)

    #テスト用のメソッドなので実際は不要なメソッド        
    def getTimelineTest(self):
        print("test")
        #動作確認のためのメソッド
        # 仮想ブラウザ起動、URL先のサイトにアクセス
        driver = webdriver.Chrome('/usr/local/bin/chromedriver')#ここでエラーになったらパスが違うかchromedriverをインストールする
        #他のエラーで、「unexpectedly exited. Status code was:-9」だったら、Macの場合はシステム環境設定 → セキュリティとプライバシー で許可すればよい
        url='https://stocks.finance.yahoo.co.jp/stocks/history/?code=998407.O'
        #driver.get(url+str(code)+'.T')
        driver.get(url)
        time.sleep(1)
        #title = driver.title
        #print(title)
        main = driver.find_element_by_id("main")
        #el = main.find_element_by_id("stockinf")
        #nextClass = el.find_element_by_css_selector(".stocksDtl.clearFix")
        el = main.find_element_by_css_selector(".padT12.marB10.clearFix")
        tableElem = el.find_element_by_tag_name("table")
        trs = tableElem.find_elements_by_tag_name("tr")
        ths = trs[0].find_elements_by_tag_name("th")
        kabuka=""
        #thタグは1行目のTRにだけ存在する。
        for f in range(0,len(ths)):#日付	始値	高値	安値	終値
            ths[f].text
            kabuka+=ths[f].text+" "
        print(kabuka)
        kabuka=""
        for i in range(0,len(trs)):
            tds = trs[i].find_elements_by_tag_name("td")
            for m in range(0,len(tds)):
                kabuka+=tds[m].text+" "#ここはカプセルにしてクラスオブジェクトを配列に入れたほうがいいかも
                #print(kabuka)
            print(kabuka)
            kabuka=""
        time.sleep(1)    
        driver.close()#起動したウィンドウを閉じる
###START
print("START#####################################")
print("Japan yahoo financeの日経平均株価の時系列")
getstock=yahooFinanceTimeline()
getstock.getTimeline()

print("End#####################################")

 

出力例

START#####################################
Japan yahoo financeの日経平均株価の時系列
カプセルにして取得
日付 始値 高値 安値 終値 
tdsの数が足りない行があるので無視
通常出力日付	始値	高値	安値	終値
2021年2月16日 30,229.46 30,714.52 30,191.65 30,467.75
2021年2月15日 29,662.41 30,092.34 29,662.41 30,084.15
2021年2月12日 29,635.88 29,650.51 29,417.32 29,520.07
2021年2月10日 29,412.55 29,562.93 29,368.18 29,562.93
2021年2月9日 29,435.61 29,585.75 29,350.48 29,505.93
2021年2月8日 28,831.58 29,400.56 28,817.6 29,388.5
2021年2月5日 28,631.46 28,785.71 28,548.27 28,779.19
2021年2月4日 28,557.46 28,600.22 28,325.89 28,341.95
2021年2月3日 28,482.71 28,669.95 28,402.3 28,646.5
2021年2月2日 28,207.48 28,379.31 28,089.12 28,362.17
2021年2月1日 27,649.07 28,107.1 27,649.07 28,091.05
2021年1月29日 28,320.72 28,320.72 27,629.8 27,663.39
2021年1月28日 28,169.27 28,360.48 27,975.85 28,197.42
2021年1月27日 28,665.34 28,754.99 28,542 28,635.21
2021年1月26日 28,696.3 28,740.71 28,527.81 28,546.18
2021年1月25日 28,698.89 28,822.29 28,566.85 28,822.29
2021年1月22日 28,580.2 28,698.18 28,527.16 28,631.45
2021年1月21日 28,710.41 28,846.15 28,677.61 28,756.86
2021年1月20日 28,798.74 28,801.19 28,402.11 28,523.26
2021年1月19日 28,405.49 28,720.91 28,373.34 28,633.46
+----------------------+
個人的出力順、カンマを削除、昇順day,High,Low,Open,Close,AdjClose
2021年1月19日,28720.91,28373.34,28405.49,28633.46,28633.46
2021年1月20日,28801.19,28402.11,28798.74,28523.26,28523.26
2021年1月21日,28846.15,28677.61,28710.41,28756.86,28756.86
2021年1月22日,28698.18,28527.16,28580.2,28631.45,28631.45
2021年1月25日,28822.29,28566.85,28698.89,28822.29,28822.29
2021年1月26日,28740.71,28527.81,28696.3,28546.18,28546.18
2021年1月27日,28754.99,28542,28665.34,28635.21,28635.21
2021年1月28日,28360.48,27975.85,28169.27,28197.42,28197.42
2021年1月29日,28320.72,27629.8,28320.72,27663.39,27663.39
2021年2月1日,28107.1,27649.07,27649.07,28091.05,28091.05
2021年2月2日,28379.31,28089.12,28207.48,28362.17,28362.17
2021年2月3日,28669.95,28402.3,28482.71,28646.5,28646.5
2021年2月4日,28600.22,28325.89,28557.46,28341.95,28341.95
2021年2月5日,28785.71,28548.27,28631.46,28779.19,28779.19
2021年2月8日,29400.56,28817.6,28831.58,29388.5,29388.5
2021年2月9日,29585.75,29350.48,29435.61,29505.93,29505.93
2021年2月10日,29562.93,29368.18,29412.55,29562.93,29562.93
2021年2月12日,29650.51,29417.32,29635.88,29520.07,29520.07
2021年2月15日,30092.34,29662.41,29662.41,30084.15,30084.15
2021年2月16日,30714.52,30191.65,30229.46,30467.75,30467.75
End#####################################

 

今日のPythonエラー クラスを作ったときにtakes 0 positional arguments but 1 was given

Pythonで
クラスを作ってメソッドを作ったらエラーになった。
takes 0 positional arguments but 1 was given

https://qiita.com/matsuida55/items/4188430631353a7a1194
「pythonはクラスメソッドの引数1つ目に必ず self を取らなければならない。」

・結論
クラスのメソッドの引数は必要なくても、 引数selfを入れなくてはならない。

誤り:エラーになるtakes 0 positional arguments but 1 was given

#python class サンプル
class nikkeiClass: 
    def __init__(self, cindex, chigh):
        self.index = cindex 
        self.high = chigh 

    def sample():#引数はないのでブランクにした>> ここが誤り
        print(self.index)
        
##START
test=nikkeiClass("aa","bb")
test.sample()
>>>エラー発生 takes 0 positional arguments but 1 was given

正しい

#python class サンプル
class nikkeiClass: 
    def __init__(self, cindex, chigh):
        self.index = cindex 
        self.high = chigh 

    def sample(self):#引数にselfがないとエラーになる
        print(self.index)
        
##START
test=nikkeiClass("aa","bb")
test.sample()
出力結果
aa

 

Pythonを使ってヤフーファイナンス情報を取得、スクレイピング

#複数企業コード対応版 企業コードから企業名と株価を取得する
#Anaconda JupyterLabによる動作 Shift+Enterで実行になる

動作環境:MacOS 、Python、Anaconda JupyterLab

面倒だった点は、複数タグが存在するタグ名tr,td,ddの扱い。複数の場合forで回して配列みたいにしてデータを取得する必要があるし、スペースが含まれるクラス名は別のプロパティ?で読み込む必要がある。

find_element_by_class_nameでスペースを含むクラス名はエラーとなるので、find_element_by_css_selectorとしてドット.で接続する。

誤り:el.find_element_by_class_name(‘stocksDtl clearFix’)

正:el.find_element_by_css_selector(“.stocksDtl.clearFix”)

以下はサンプルコード。使い方は、codelistに企業コードを入力すると、ヤフーファイナンスからスクレイピングして「コード、企業名、終値株価、前日比、日付」を半角スペース区切りで出力するだけ。ヤフーファイナンスに接続するときは、取得間隔を1,2秒程度空けている。連続で取得するとサーバ負荷が増えるから強制切断とかアクセスをブロックされてしまうかもしれない。

>>コード修正、Spanタグが存在しない時間帯があるみたいなので、存在するかどうかのチェックを追記した。2021年2月8日、12時06分

import time
from selenium import webdriver
import csv
import datetime
import os

codelist=[]
codelist=[6315,2207,6928,5724,2702]#企業コード、複数

def getName(code):
    # 仮想ブラウザ起動、URL先のサイトにアクセス
    driver = webdriver.Chrome('/usr/local/bin/chromedriver')#ここでエラーになったらパスが違うかchromedriverをインストールする
    #他のエラーで、「unexpectedly exited. Status code was:-9」だったら、Macの場合はシステム環境設定 → セキュリティとプライバシー で許可すればよい
    url='https://stocks.finance.yahoo.co.jp/stocks/detail/?code='
    driver.get(url+str(code)+'.T')
    #time.sleep(1)
    #title = driver.title
    #print(title)
    main = driver.find_element_by_id("main")
    el = main.find_element_by_id("stockinf")

    #エラー、nextClass = el.find_element_by_class_name('stocksDtl clearFix') Classにスペースが含まれるとエラーになるので別のメソッドにする
    nextClass = el.find_element_by_css_selector(".stocksDtl.clearFix")
    subNextClass = nextClass.find_element_by_class_name("forAddPortfolio")
    tableElem = subNextClass.find_element_by_class_name("stocksTable")
    dlElem = subNextClass.find_element_by_css_selector(".stocksInfo.clearFix")
    
    dds = dlElem.find_elements_by_tag_name("dd")
    trs = tableElem.find_element_by_tag_name("tr")
    symbol = trs.find_element_by_class_name("symbol")
    name = symbol.find_element_by_tag_name("h1")
    stockinfo = []
    stockinfo.append(str(code))
    stockinfo.append(name.text)
    tds = trs.find_elements_by_tag_name("td")
    
    for j in range(0,len(tds)):
        if tds[j].text != "":
            stockinfo.append(tds[j].text)

    ##ddタグの中に spanタグがあって、他に文字がある。spanタグのテキストだけが取得したかった。
    ##>>追記 2021年2月8日エラー処理を追加
    if len(dds[1].find_elements_by_tag_name("span"))>0:#存在チェック elementでなくてelementsにする
        stockinfo.append(dds[1].find_element_by_tag_name("span").text)#日付
    output=stockinfo
    driver.close()#起動したウィンドウを閉じる
    return output

###START
print("START#####################################")
tmpStr=""
f=0
for i in codelist:
    outputStr=getName(i)
    #コード、企業名、終値株価,前日比、日付
    for m in outputStr:
        if f==2:
            tmpStr+=m+'円'+' '
        else:
            tmpStr+=m+' '
        f+=1
        #print(outputStr[0],outputStr[1],outputStr[2]+"円",outputStr[3],outputStr[4])
    print(tmpStr)
    tmpStr=""
    f=0
    time.sleep(2)
print("End#####################################")

 

更に修正した。メソッドをクラスにした。また始値、高値、安値を入れた。2021/02/12

#Python を使って#ヤフーファイナンス 情報を取得、#スクレイピング 
#複数企業コード対応版 企業コードから企業名と株価を取得する
#Anaconda JupyterLabによる動作 Shift+Enterで実行になる
#修正、クラスに変更
#修正2021/02/12、始値、高値、安値を入れた

#手作業はcodelistにコードを入れる
import time
from selenium import webdriver
import csv
import datetime
import os

codelist=[]
codelist=[6134,7952,6462
         ]#企業コード、複数
#これからは、どんなに小さなプログラムでもクラスを使用する。そのほうが汎用性がある。
#同じメソッド名でもクラス名が異なればコピペして使用できる
class yahooFinanceClass():
        def __init__(self):
            self.hello="yahoo Finace"
        
        def getName(self,code):
            # 仮想ブラウザ起動、URL先のサイトにアクセス
            driver = webdriver.Chrome('/usr/local/bin/chromedriver')#ここでエラーになったらパスが違うかchromedriverをインストールする
            #他のエラーで、「unexpectedly exited. Status code was:-9」だったら、Macの場合はシステム環境設定 → セキュリティとプライバシー で許可すればよい
            url='https://stocks.finance.yahoo.co.jp/stocks/detail/?code='
            driver.get(url+str(code)+'.T')
            time.sleep(1)
            #title = driver.title
            #print(title)
            main = driver.find_element_by_id("main")
            el = main.find_element_by_id("stockinf")

            #エラー、nextClass = el.find_element_by_class_name('stocksDtl clearFix') Classにスペースが含まれるとエラーになるので別のメソッドにする
            nextClass = el.find_element_by_css_selector(".stocksDtl.clearFix")
            subNextClass = nextClass.find_element_by_class_name("forAddPortfolio")
            tableElem = subNextClass.find_element_by_class_name("stocksTable")
            dlElem = subNextClass.find_element_by_css_selector(".stocksInfo.clearFix")

            dds = dlElem.find_elements_by_tag_name("dd")
            trs = tableElem.find_element_by_tag_name("tr")
            symbol = trs.find_element_by_class_name("symbol")
            name = symbol.find_element_by_tag_name("h1")
            stockinfo = []
            stockinfo.append(str(code))
            stockinfo.append(name.text)
            tds = trs.find_elements_by_tag_name("td")

            for j in range(0,len(tds)):
                if tds[j].text != "":
                    stockinfo.append(tds[j].text)

            ##始値、高値、安値を取得
            detail = main.find_element_by_id("detail")
            innerDate = detail.find_element_by_class_name("innerDate")
            innerDate_divs = innerDate.find_elements_by_css_selector(".lineFi.clearfix")#S複数
            for n in range(0,len(innerDate_divs)):
                if len(innerDate_divs[n].find_elements_by_class_name("tseDtl"))>0:#存在確認は複数形
                    tseDtl = innerDate_divs[n].find_element_by_class_name("tseDtl")#こっちは単数
                    kubun=tseDtl.find_element_by_class_name("title").text
                    #共通の処理をまとめた
                    if kubun=="安値" or kubun=="高値" or kubun=="始値":
                        ymuiEditLink=tseDtl.find_element_by_css_selector(".ymuiEditLink.mar0")
                        kabuka=ymuiEditLink.find_element_by_tag_name("strong").text
                    #配列に追加    
                    if kubun=="安値":
                        stockinfo.append("安値:"+kabuka)
                    elif kubun=="高値":
                        stockinfo.append("高値:"+kabuka)
                    elif kubun=="始値":  
                        stockinfo.append("始値:"+kabuka)
                              
            ##ddタグの中に spanタグがあって、他に文字がある。spanタグのテキストだけが取得したかった。
            ##>>追記 2021年2月8日エラー処理を追加
            if len(dds[1].find_elements_by_tag_name("span"))>0:#存在チェック elementでなくてelements(複数S)にする
                stockinfo.append(dds[1].find_element_by_tag_name("span").text)#日付 こっちは単数のelement  
            output=stockinfo
            driver.close()#起動したウィンドウを閉じる
            return output
        
###START
print("START#####################################")
tmpStr=""
f=0
obj=yahooFinanceClass()
for i in codelist:
    outputStr=obj.getName(i)
    #コード、企業名、終値株価,前日比、日付
    for m in outputStr:
        if f==2:
            tmpStr+=m+'円'+' '
        else:
            tmpStr+=m+' '
        f+=1
        #print(outputStr[0],outputStr[1],outputStr[2]+"円",outputStr[3],outputStr[4])
    print(tmpStr)
    tmpStr=""
    f=0
    time.sleep(2)
print("End#####################################")    
'''出力例
START#####################################
6134 (株)FUJI 2,795円 前日比+51(+1.86%) 始値:2,794 高値:2,832 安値:2,777 14:08 
7952 (株)河合楽器製作所 3,510円 前日比+380(+12.14%) 始値:3,200 高値:3,540 安値:3,155 14:06 
6462 (株)リケン 2,400円 前日比+114(+4.99%) 始値:2,449 高値:2,449 安値:2,329 14:07 
End#####################################  
'''

 

pythonでCSVを読み込みクラスオブジェクトを配列に入れる

CSVを読み込みクラスオブジェクトを配列に入れる

CSV例,6列必要。1行目は除外する。米ヤフーファイナンスから日経平均株価データを取得すると、今日の分は取得できるのに、なぜか前日のデータが時間帯によって取得できない。そのため、取得できたデータと取得できないデータをCSVにしておいて使用する。

日付,高値,安値,始値,終値,調整終値

となっている。

index      High      Low    Open   Close    AdjClose  列数チェックが必要                                                               
2021-01-07,27624.730469,27340.460938,27340.460938,27490.130859,27490.130859
2021-01-08,28139.029297,27667.750000,27720.140625,28139.029297,28139.029297
2021-01-12,28287.369141,27899.449219,28004.369141,28164.339844,28164.339844
2021-01-13,28140.10,28503.43,28139.66,28456.59,28456.59
2021-01-14,28979.529297,28411.580078,28442.730469,28698.259766,28698.259766

クラスから実際のデータを取得するときは

df[0].indexとかdf[0].closeみたいにして取得する。つまり1行分が1オブジェクトの配列として登録されている。

#CSVにするときは、列数があっているかをチェックする。ヤフーファイナンスはAdjCloseがあるが、ほかはCloseしかない。
import os
import pandas_datareader.data as data
from datetime import datetime,timedelta

#日経平均株価データのクラスオブジェクト、カプセルデータ
class nikkeiClass:
    def __init__(self, cindex, chigh,clow,copen,cclose,cadjclose):
        self.index = cindex
        self.high = chigh
        self.low = clow
        self.open = copen
        self.close = cclose
        self.adjclose = cadjclose
#########################
end = datetime.now()
#start = datetime(end.year, end.month, end.day-8)#こっちだと月マタギでエラーになる。
start = end - timedelta(days=7)
print('start:',start.strftime("%Y/%m/%d"))
print('today:',end.strftime("%Y/%m/%d"))

df=[]
checkLineCount=0
#CSVを読み込む
ifile='/Users/toshiromaseda/Documents/blender/script/2021年1月14日日経.csv'
try:#ファイルが存在しないときのエラー処理try
    with open(ifile,'tr') as fin:
        for iline in fin:
            #try:
                tmp=iline.strip().split(",")#stripしてからsplit()だと理解している。
                if 'High' in tmp[0]:
                    continue
                if len(tmp) < 6:#全部で6列存在する。
                    print('ERROR 列の数があっていません。少ないようです。行数:',checkLineCount)
                    break
                #here
                df.append(nikkeiClass(tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5]))
                checkLineCount+=1
except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
    print("ファイルが見つかりません。パス、ファイル名を確認してください", e)
    ifile.close()
    sys._exit()#ファイルがなければ終了

print(df[0].index) 
for f in df:
    print('日付:',f.index)


print('END')

 

今日のエラー、Mysql、Can’t connect to local MySQL server

A・症状2021/01/06

iMacを再起動した後で、Anaconda NavigatorからPythonを実行した
するとエラーが発生。PythonでMysqlを使用しているエラーのようだ。
エラーの一部:Can’t connect to local MySQL server through
Mysqlサーバに接続できない

・対応

Mysqlを使用しているPythonでエラーが発生したとき、Can’t connect to local MySQL server through
たぶんMysqlが起動していないから(PCを起動した直後や再起動するとMysqlは停止しているからMysqlを起動する)
(1)mysqlサーバを起動する。ターミナルから実行する
$ mysql.server start
このrootはいつもの(秘密)パスワードで、CSV取り込みは、Test1030のパスワード

(2)Mysqlに接続する(以下は個別のアカウントmasedaを使用した場合。rootの場合はmysql -u root -p)
$ mysql -u maseda -p
Test1030(これは知られてもよい)のパスワード

(3)通常のMysqlコマンドやPythonから実行する
実行できた。

 

B SyntaxError

・症状

pythonを実行したらエラーメッセージが表示された

・エラーメッセージ

SyntaxError: invalid syntax

対応

指定された行の上の行の閉じカッコの数があっていなかった。
1個少なかったために、次の行でエラーが表示されていた。
test((a,a),(1,1,1)   <<<閉じカッコが足りない
testB()<<<ここでエラーが表示


test((a,a),(1,1,1))

python便利なコマンド使い方、備忘録チートメモ、pythonにはswitch case文はない

配列の要素数はlen(array)で数える

メソッドはdefを先頭に付ける。def funcname():。メソッドを外部ファイルにしたいときは、ファイル名:testfunc.pyだったらimport testfunc(ファイル名、拡張子を除く)とする。

if文でelse ifは pythonではelif(勝手にエリフと読んでる)。一致条件はイコール2つ== if :elif:
elseは同じ。中括弧は使わない。

pythonには、switch case文はない

1行コメントは先頭に#
コメントの複数行はシングルクォーテーション3つかダブルクォーテーション3つで囲む。”’ commnet ”’

改行(折返し)は行末にバックスラッシュ\を付けて改行できる(マックの場合はOptionキーと¥キー、Winの場合はAltキーと¥キー)

文字の結合はプラス+。’abc’+’def’ >>abcdef

print(‘Max:’,max(df))#配列dfに複数の数値が入ってるとしてmax()で最大値が取れる。最小値はmin()

c,mod=divmod(a,b) 商cと余りmodが同時に取得できる

ループ、途中の3から5の数字を使って計算したいときrangeを使う。
for i in range(3,6):で、rangeを使うと3,4,5のように途中から取得できる但し、6は出力されないので注意。ここでは5までが対象になる。6を対象にしたかったら1加算してrange(3,7)のようにする

ディレクトリのTXTファイル一覧を取得 import glob, files=glob.glob(path+’*.txt’)、pathにはディレクトリのパスを入れること。

Int moji=5(int型)を文字にしたいstr(moji)で文字5になる

インクリメントi++、デクリメントi–は存在しない。i+=1,i-=1とする

文字列の挿入は、文字列の2番めの文字(1の後ろ)にabc文字を挿入したい。
tmpstr=’0123456′
hoge=tmpstr[:2]+’abc’+tmpstr[2:]
print(hoge)#01abc23456
[:0][0:]だとabc0123456になる

正規表現はimport re 、re.compile,searchがある。#findで正規表現ができない(と思う)

置換はsub

年月日の取得例
from datetime import datetime
end = datetime.now()
start = datetime(end.year, end.month, end.day)
print(‘start:’,start.strftime(“%Y/%m/%d”))
print(‘today:’,end.strftime(“%Y/%m/%d”))
–月をまたいでもOKな記載は以下
from datetime import datetime,timedelta
end = datetime.now()
#start = datetime(end.year, end.month, end.day-8)#こっちだと月マタギでエラーになる。
start = end – timedelta(days=7)

pass で何もしない。!=を使いたくないときやとりあえずコードを書いて実行したいときに使える
if i==10:
pass
else:
a=20

Blender2.91、Pythonで日経平均株価のローソク足を3Dにしてみた

内容

2020年12月〜2021年1月のある期間の日経平均株価チャートを自動作成
約1、2週間分程度の株価

3Dローソク足(株に興味のない人はつまらないかも、、、)
BlenderのPythonを使うとこんなこともできるということを実践しただけの紹介動画

>>作成したローソク足の3D オブジェクトの紹介、BlenderのPython実行

ユーチューブ動画

参考サイト

https://qiita.com/kjunichi/items/a36fdc9db3876e068249
https://qiita.com/hibit/items/1ac97c71d5adc5b45f85

ブログに記載したインストール内容はこちら
https://pikucha.sakura.ne.jp/blog/2020/12/27/mac%e7%89%88blender%e3%81%aepython%e3%81%abpip%e3%80%81pandas_datareader%e3%82%a4%e3%83%b3%e3%82%b9%e3%83%88%e3%83%bc%e3%83%ab%e3%81%97%e3%81%9f%e3%83%a1%e3%83%a2/

#日経平均株価 とは
「東京証券取引所第一部に上場する約2,000銘柄の株式のうち225銘柄を対象」原則「225銘柄の株価の合計 ÷ 225」となる。修正等ある。
https://ja.m.wikipedia.org/wiki/%E6%97%A5%E7%B5%8C%E5%B9%B3%E5%9D%87%E6%A0%AA%E4%BE%A1

#ローソク足とは、
https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%82%BD%E3%82%AF%E8%B6%B3%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88

「単位期間中に初めに付いた値段を始値(はじめね)、最後に付いた値段を終値(おわりね)、最も高い値段を高値(たかね)、最も安い値段を安値(やすね)」の値をもとにローソクの形状のように表現したもの
ローソク足は江戸時代に出羽国の本間宗久が発案

日経平均株価のデータを取得して、BlenderのPythonを使いローソク足の3D オブジェクトを作成した。

環境:MacOS BigSur

#Blender2.91
Blender用pythonモジュール: #pandas_datareader
準備:Pythonモジュールをインストールする必要がある。
Mac版BlenderのPythonにPip、pandas_datareaderインストールしておく。
・PythonはMacOS BigSur用とBlender用とが存在する。つまり保存場所が異なる。
よってBlenderで使いたいモジュールが必要なときは、個別でインストールが必要。
つまり、MacOSでpandas_datareaderをインストールしても、BlenderのPythonでは
使えない。

目的

:Blender2.91、Pythonスクリプトで日経平均株価データを米ヤフーファイナンスからネット上で取得して、ローソク足として3D(円柱)オブジェクトを作成する。
チャートデータは数日〜1週間程度のデータ

注意事項:

Pythonの文法の説明はほとんどしません。
BlenderのPythonの仕様について投稿者は、よく理解しておらず試行錯誤で作成し、推奨ではないコードの記述や間違いがあります。よって質問等があっても正しく答えられる知識がないため回答できない場合があります。
ご承知おきください。(他の人の回答を期待します。)

・Pythonスクリプトコードの概略説明

米ヤフーファイナンスから日経平均株価のデータを取得
始値、終値、高値、安値データを取得
始値より終値が大きければ陽線(赤)
小さければ陰線(青)とする
始値、終値からローソク本体の大きさ位置を決める
高値、安値からローソクのひげの大きさ位置を決める
直近の日のローソク足だけ横を向いた円錐を配置
直近のローソク足の始値終値を記載
直近の日付を記載
目盛りを配置

^読み方:キャロット

オブジェクトの原点がオブジェクトの中心に配置されていて、オブジェクトの移動やリサイズをする場合は問題は発生しないが、オブジェクトの頂点がオブジェクトの原点(中心点)より離れた位置に配置されていると、
Resizeしたときに、ポイントの縮尺が変わり、想定した位置に配置されない(バグではなく、操作や理解の問題)。
よって、リサイズして、ポイントを移動させたいときは、
オブジェクト自体を移動させてから、リサイズや個別頂点ポイントを移動させたほうが良いと思う。

 

・補足説明

Blenderターミナル起動(print出力を確認するためにターミナルが必要)
/Applications/Blender.app/Contents/MacOS/Blender

Blender2.91のpython場所 –MacOSpythonと異なる場所にある(バージョンが変わる毎にディレクトリが変わる。2.91の部分)
/Applications/Blender.app/Contents/Resources/2.91/python

 

Pythonコード

2021/01/04時点の分、Blenderで実行する。できれば、ターミナルからBlenderを起動してから、Scriptingで使用

修正履歴:2021/01/06、始値終値が重ならないように位置を調整

import os
import bpy
import math
import copy
import time
import pandas_datareader.data as data
from datetime import datetime,timedelta

#blender 2.91 
#Mac Big Sur
#ターミナル起動
#/Applications/Blender.app/Contents/MacOS/Blender

#GLOBAL
# count
# xmove
# bairitsu
#修正履歴
#2021/01/06:始値、終値の位置が重ならないように調整

#https://bluebirdofoz.hatenablog.com/entry/2018/04/25/231414
# オブジェクトの原点変更
# オブジェクトの原点を指定位置に移動する
# 引数   arg_objectname:指定オブジェクト名
# 戻り値
def set_origin_cursor(arg_objectname='Default',arg_location=(0,0,0)):
  # 他のオブジェクトの寸法を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    #ob.select=False#2.7
    ob.select_set(False) #2.9
  # 指定オブジェクトを取得する
  selectob = bpy.data.objects[arg_objectname]
  # 変更オブジェクトをアクティブに変更する
  #bpy.context.scene.objects.active = selectob#2.7
  bpy.context.view_layer.objects.active=selectob#2.9
  # 変更オブジェクトを選択状態にする  
  #selectob.select=True #2.7
  selectob.select_set(True) #2.9
  # 3Dカーソルの元の位置を記録しておく(参照型のコピー)
  #cursorpos = copy.copy(bpy.context.scene.cursor_location)
  # 3Dカーソルの位置を指定位置に移動する
  #bpy.context.scene.cursor_location = arg_location#2.7
  bpy.context.scene.cursor.location=arg_location#2.9
  # オブジェクトの原点を3Dカーソル位置に移動する
  bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  # 3Dカーソルの位置を元に戻す
  #bpy.context.scene.cursor_location = cursorpos #2.7
  #bpy.context.scene.cursor.location=cursorpos#2.9 not use
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  return

def fcandle(candleType,kopen,kclose,bairitsu,xmove,mat1,mat2):
    #count is Global
    global count
    #global xmove
    #global bairitsu
    
    if bairitsu=='' or bairitsu==0:
        print('def fcandle(),bairitsu not defined,use 0.001')
        bairitsu=0.001
    if count=='':
        print('def fcandle(),count is Global, not defined, Please check, so use 1')
        count=1
                  
    candle=candleType
    #1.円柱location:図形の中心座標 radius:円の半径 depth:高さ rotation:立体の回転角(rad)
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(xmove,0,0))
    #location=bpy.context.object.location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "candle"+str(tmpcount)
    
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
        if candle=='yousen':
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = kclose*bairitsu#close
            else:
                vert.co[2] = kopen*bairitsu
        elif candle=='insen':
            if vert.co[2] > 0:
                vert.co[2] = kopen*bairitsu
            else:
                vert.co[2] = kclose*bairitsu
    clocation=(xmove,0,(kopen+kclose)*bairitsu/2) 
    set_origin_cursor(obj.name,clocation)
    location=bpy.context.object.location
    
    return  location#candle             
#end def

def fcandle_hige(candleType,khigh,klow,bairitsu,candleLocation,mat1,mat2):
    global count
    #global xmove
    #global bairitsu    
    #count,bairitsu is Global
    #if bairistu=='' or bairitsu==0:
    #    print('def fcandle_hige(),bairitsu not defined, so use 0.001')
    #    bairitsu=0.001
    if count=='':
        print('def fcandle_hige(),count is Global, not defined, Please check, so use 1')
        count=1
        
    candle=candleType
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022/7, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(candleLocation[0],candleLocation[1],0))#hige location is same candle location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "hige"+str(tmpcount)
    
    #xmove+=0.048
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = khigh*bairitsu#close
            else:
                vert.co[2] = klow*bairitsu
    set_origin_cursor(obj.name,candleLocation)
    
#end def
# テキストオブジェクトの追加
def add_text(text, t_color,location):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=(0.2,0.1,0.2)) # 図形を変形
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error

#convert to mesh

  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text

  return ob
#end def

def add_textKai(text, t_color,location,size):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=size) # 図形を変形(0.2,0.1,0.2)
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error
#convert to mesh
  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text  
  return ob
#end def

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
def makeBarMaxtoMin(highobj,lowobj):
    #print('Max:',max(highobj))#df['High']
    #print('Min:',min(lowobj))#df['Low']
    #bairitsu is Global
    global count
    global xmove
    global bairitsu    
    #if bairistu=='' or bairitsu==0:
    #    print('def makeBarMaxtoMin(),bairitsu not defined,use 0.001')
     #   bairitsu=0.001    
    #every 500yen
    priceRange=500
    #highPriceNumはバーの本数を取得する
    highPriceNum,highmod=divmod(max(highobj),priceRange)#26200/priceRange
    lowPriceNum,lowmod=divmod(min(lowobj),priceRange)
    #高値については、余りが出たら、1を追加する
    #print('highmod:',highmod)
    if highmod!=0:
        highPriceNum=highPriceNum+1
        #Rangeで範囲を指定してしようする場合1加算では足りないので、rangeで更に1を加算する
        #print('after highPriceNum:',highPriceNum)

    for i in range(math.floor(lowPriceNum),math.floor(highPriceNum+1)):
        #range()が出力するのは、(highPriceNum-1)なので1を加算してhighPriceNum分までを計算させる
        print('barPrice:',i*priceRange)
        #i*priceRangeの位置でBarオブジェクトを作成する。
        # 3Dカーソルの位置を0,0,0
        bpy.context.scene.cursor.location=(0.0,0.0,0.0) 
        color=(0.8,0.5,0.8,0.8)
        add_text(str(i*priceRange), color,(1.8,0.1/3, (i*priceRange)*bairitsu+0.045))#0.045 is ajustment
        
        bpy.context.scene.cursor.location=(0.0,0.0,0.0)
        # 平板作成 26500bar1
        bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
        bpy.ops.transform.translate(value=(0.0,0.1/2,(i*priceRange)*bairitsu))#26500*0.001
        bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
        bpy.context.object.data.materials.append(mat3) # 材質
        for obj in bpy.context.selected_objects:
            if obj.name=='Cube':
                obj.name='bar_'+str(i*priceRange) 
#end def
######################################################################
#main
######################################################################
count=0#count is Global
xmove=0.8#1# move distancs
bairitsu=0.001# size Global

#Stock date
n=maenohi=5
end = datetime.now()
#start = end - timedelta(days=maenohi)#end.day-7 changes
#start = datetime(end.year, end.month, end.day-7)
##土日があると表示させるローソク足の数が少ないので、数が満たされるまでループするためSleepを入れた
#大量のデータはCSVで取得してからローソク足にしたほうが良さそう
x=0
while x<=(maenohi):
    start = end - timedelta(days=n)
    df=data.DataReader('^N225','yahoo',start,end)#3990.T,#^N225
    date=df.index# 日付
    time.sleep(3)
    print('len(date):',len(date))
    print('3秒待ち')
    x=len(date)
    n=n+1
print(df.head(5))
if len(date)==0:
    print('ERROR Can not get any Price data, Check internet or yahoo finance com.')
    sys.exit()

# 既存要素削除
for item in bpy.data.meshes:
    bpy.data.meshes.remove(item)

for item in bpy.data.materials:
    bpy.data.materials.remove(item)
        
#bpy.ops.outliner.item_rename()
#2.立方体 location:図形の中心座標 size:立方体の一辺の長さ rotation:立体の回転角(rad)
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=1.0, rotation=(0, 0, 0))

# 2.材質の定義(赤色)
mat1 = bpy.data.materials.new('Red')
mat1.diffuse_color = (1.0, 0.0, 0.0, 1.0)

# 3.材質の定義(青色)
mat2 = bpy.data.materials.new('blue')
mat2.diffuse_color = (0.0, 0.0, 1.0, 1.0)

mat3 = bpy.data.materials.new('gray')
mat3.diffuse_color = (0.8, 0.8, 0.8, 0.5)

mat5 = bpy.data.materials.new('yellow')
mat5.diffuse_color = (1.0, 0.9, 0.1, 1.0)

# 平板作成 27000bar
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
#Resizeして、ポイント移動をするとポイントの縮尺が変わり、想定した位置に移動しない(推測)。
#これはオブジェクトの原点とScaleの考え方の違いかもしれない。
#よって、リサイズして、ポイントを移動させたいときは、
#リサイズをする前にオブジェクト自体を移動させてから、ポイントを移動させたほうが良いと思う。
#bpy.ops.transform.translate(value=(0.0,0.1/2,27))#27000*0.001
#bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
#bpy.context.object.data.materials.append(mat3) # 材質

# 平板作成 26500bar1
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
#bpy.ops.transform.translate(value=(0.0,0.1/2,bar1*bairitsu))#26500*0.001
#bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
#bpy.context.object.data.materials.append(mat3) # 材質

# 3Dカーソルの位置を0,0,0
#bpy.context.scene.cursor_location =(0.0,0.0,0.0)
bpy.context.scene.cursor.location=(0.0,0.0,0.0)

#26500txt
#color=(0.8,0.5,0.8,0.8)
#add_text('26500', color,(1.8,0.1/3,bar1*bairitsu+0.045))#0.045 is ajustment
#27000txt
#add_text('27000', color,(1.8,0.1/3,bar2*bairitsu+0.045))


#date=df.indexをカウントして、それぞれを取得する。ちょっとスマートではないが、、
for fdate in date:
    khigh=df['High'][count]
    klow=df['Low'][count]
    kopen=df['Open'][count]
    kclose=df['Adj Close'][count]
    #ここに日付ごとの処理を入れる。
    #
    if kopen-kclose<0:
        candle='yousen'#color Red
        #print('陽線')
    else:
        candle='insen'#color Blue
        #print('陰線')
    #objを生成する。
    #始値、終値でZ軸の高さを設定する。
    print( fdate.strftime("%Y/%m/%d") )#2020-12-22 00:00:00となるので、時刻を除く2020-12-22
    #Candle_Main####################################################
    candleLocation=fcandle(candle,kopen,kclose,bairitsu,xmove,mat1,mat2)
    xmove+=0.048
    
    #Candle_hige####################################################
    fcandle_hige(candle,khigh,klow,bairitsu,candleLocation,mat1,mat2)
    #count is Global      
    count+=1

#最後のローソクのobjの横に矢印を与える
#この場合、ローソクの原点を移動させて、ローソクの中心に移動させる必要がある
candleCount=0
for obj in bpy.data.objects:
    if 'candle' in obj.name:
        #print(obj.name)
        candleCount+=1
candleName='candle'+str(candleCount)

#Arrow
bpy.ops.mesh.primitive_cone_add(radius1=1, radius2=0, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(0.05, 0.05, 0.05))
#図形を回転(Y軸周りに90°)
bpy.ops.transform.rotate(value=-3.1415/2 ,orient_axis='Y')
bpy.context.object.data.materials.append(mat5) 
bpy.ops.transform.translate(value=(bpy.data.objects[candleName].location[0]+0.08,bpy.data.objects[candleName].location[1],bpy.data.objects[candleName].location[2]))#


bpy.context.scene.cursor.location=(0.0,0.0,0.0)
#open,close
color=(1.0,1.0,1.0,1.0)
#str,color,location,size
lastOpen=df['Open'][len(date)-1]#始値
lastClose=df['Close'][len(date)-1]#終値
roundOpen='O:'+str(round(lastOpen,2))#画面に表示させる直近の始値文字
roundClose='C:'+str(round(lastClose,2))#画面に表示させる直近の終値文字

add_textKai(roundOpen, color,(xmove+0.1,0,lastOpen*bairitsu),(0.06,0.05,0.06))
add_textKai(roundClose, color,(xmove+0.1,0,lastClose*bairitsu),(0.06,0.05,0.06))

#end.strftime("%Y/%m/%d") or date[len(date)-1].strftime("%Y/%m/%d")today
color=(0.0,1.0,0.0,1.0)
coneLocation=bpy.data.objects['Cone'].location
tyokkinDay=date[len(date)-1].strftime("%Y/%m/%d")
if len(date)>0:
    add_textKai(tyokkinDay,color, (coneLocation[0]+0.16,coneLocation[1],coneLocation[2]),(0.06,0.05,0.06))
#print('last day:',date[len(date)-1])

#始値、終値、直近の日付の調整。オブジェクトが重なってしまう金額が近いときに離す処理
if candle=='yousen':#Openが下側でCloseが上側にあるはず
    #bpy.data.objects[roundOpen].dimensions[1]#Z方向の幅サイズではなくてY軸、理由はローカルで回転させたから
    #bpy.data.objects[roundClose].dimensions[1]
    #bpy.data.objects[tyokkinDay].dimensions[1]
    #始値、終値、直近の日付のlocationを取得する。Z方向ではなくてY軸の幅の半分を上下に加減算して重なりを調べる
    #bpy.data.objects[roundOpen].location[2]
    #bpy.data.objects[roundClose].location[2]
    #bpy.data.objects[tyokkinDay].location[2]
    #roundCloseを調整する.roundCloseの下側位置が、直近日付の上側位置以下になっているときに、直近日付の上の方にroundCloseを上へ移動させる
    
    #location is [2]:Z, dimensions is [1]:Y
    if bpy.data.objects[roundClose].location[2]-bpy.data.objects[roundClose].dimensions[1]/2 <= bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        #直近日付の位置に、プラスへ移動
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
    #roundOpenを調整する。roundOpenの「上側」位置が、直近日付の「下側」以上になっているときに、直近日付の「下の方」にroundOpenを下へ移動させる
    if bpy.data.objects[roundOpen].location[2]+bpy.data.objects[roundOpen].dimensions[1]/2 >=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
            #「マイナス」へ移動
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[1]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
else:#insen Openが上側でCloseが下側にあるはず.Yousenとは逆
    #roundOpen
    print('insen')
    if bpy.data.objects[roundOpen].location[2]-bpy.data.objects[roundOpen].dimensions[1]/2<=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Open')
    #roundClose
    if bpy.data.objects[roundClose].location[2]+bpy.data.objects[roundClose].dimensions[1]/2>=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Close')

    

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
makeBarMaxtoMin(df['High'],df['Low'])

#camera move, near Cone obj
camera_obj = bpy.data.objects['Camera']
print(camera_obj.location)
camera_obj.location=(coneLocation[0]+0.16,coneLocation[1]-3.0,coneLocation[2])

print('done.')

''' Result



'''

 

別コード、株価を記載したCSVファイルを読み込んで立体ローソク足にした

米ヤフーファイナンスに接続して当日にデータを取得すると、前日データが欠落するし、データが公開されるまで時間がかかる(20分)ので
CSVで当日データを記載したファイルを読み込んだほうが早いと思ってCSV読み取りでローソク足を立体化するPythonコードを書いた。日経平均株価データのクラスオブジェクト、カプセルデータとして扱う。CSVの場合は、数字が文字列扱いになるので、floatにするなどの型変換が必要だった。
なお、このコードには、別ファイルのBlendファイルからオブジェクト(猫)を読み込むコードを記載してある。
ファイルパスはフルパス。

import os
import bpy
import math
import copy
import time
import pandas_datareader.data as data
from datetime import datetime,timedelta

#blender 2.91 
#Mac Big Sur
#ターミナル起動
#/Applications/Blender.app/Contents/MacOS/Blender

#GLOBAL
# count
# xmove
# bairitsu

#日経平均株価データのクラスオブジェクト、カプセルデータ
class nikkeiClass:
    def __init__(self, cindex, chigh,clow,copen,cclose,cadjclose):
        self.index = cindex
        self.high = chigh
        self.low = clow
        self.open = copen
        self.close = cclose
        self.adjclose = cadjclose

#https://bluebirdofoz.hatenablog.com/entry/2018/04/25/231414
# オブジェクトの原点変更
# オブジェクトの原点を指定位置に移動する
# 引数   arg_objectname:指定オブジェクト名
# 戻り値
def set_origin_cursor(arg_objectname='Default',arg_location=(0,0,0)):
  # 他のオブジェクトの寸法を適用しないよう全てのオブジェクトを走査する
  for ob in bpy.context.scene.objects:
    # 非選択状態に設定する
    #ob.select=False#2.7
    ob.select_set(False) #2.9
  # 指定オブジェクトを取得する
  selectob = bpy.data.objects[arg_objectname]
  # 変更オブジェクトをアクティブに変更する
  #bpy.context.scene.objects.active = selectob#2.7
  bpy.context.view_layer.objects.active=selectob#2.9
  # 変更オブジェクトを選択状態にする  
  #selectob.select=True #2.7
  selectob.select_set(True) #2.9
  # 3Dカーソルの元の位置を記録しておく(参照型のコピー)
  #cursorpos = copy.copy(bpy.context.scene.cursor_location)
  # 3Dカーソルの位置を指定位置に移動する
  #bpy.context.scene.cursor_location = arg_location#2.7
  bpy.context.scene.cursor.location=arg_location#2.9
  # オブジェクトの原点を3Dカーソル位置に移動する
  bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
  # 3Dカーソルの位置を元に戻す
  #bpy.context.scene.cursor_location = cursorpos #2.7
  #bpy.context.scene.cursor.location=cursorpos#2.9 not use
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  return

def fcandle(candleType,kopen,kclose,bairitsu,xmove,mat1,mat2):
    #count is Global
    global count
    #global xmove
    #global bairitsu
    
    if bairitsu=='' or bairitsu==0:
        print('def fcandle(),bairitsu not defined,use 0.001')
        bairitsu=0.001
    if count=='':
        print('def fcandle(),count is Global, not defined, Please check, so use 1')
        count=1
                  
    candle=candleType
    #1.円柱location:図形の中心座標 radius:円の半径 depth:高さ rotation:立体の回転角(rad)
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(xmove,0,0))
    #location=bpy.context.object.location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "candle"+str(tmpcount)
    
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
        if candle=='yousen':
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = kclose*bairitsu#close
            else:
                vert.co[2] = kopen*bairitsu
        elif candle=='insen':
            if vert.co[2] > 0:
                vert.co[2] = kopen*bairitsu
            else:
                vert.co[2] = kclose*bairitsu
    clocation=(xmove,0,(kopen+kclose)*bairitsu/2) 
    set_origin_cursor(obj.name,clocation)
    location=bpy.context.object.location
    
    return  location#candle             
#end def

def fcandle_hige(candleType,khigh,klow,bairitsu,candleLocation,mat1,mat2):
    global count
    #global xmove
    #global bairitsu    
    #count,bairitsu is Global
    #if bairistu=='' or bairitsu==0:
    #    print('def fcandle_hige(),bairitsu not defined, so use 0.001')
    #    bairitsu=0.001
    if count=='':
        print('def fcandle_hige(),count is Global, not defined, Please check, so use 1')
        count=1
        
    candle=candleType
    bpy.ops.mesh.primitive_cylinder_add(location=(0, 0, 0), radius=0.022/7, depth=3, rotation=(0, 0, 0))
    if candle=='yousen':
        bpy.context.object.data.materials.append(mat1) # 材質(赤)指定
    else:#insen 
        bpy.context.object.data.materials.append(mat2) # 材質(青)指定
    bpy.ops.transform.translate(value=(candleLocation[0],candleLocation[1],0))#hige location is same candle location
    
    for obj in bpy.context.selected_objects:
        if obj.name=='Cylinder':
            tmpcount=count+1
            obj.name = "hige"+str(tmpcount)
    
    #xmove+=0.048
    #bpy.ops.object.shade_smooth()
    
    new_bar = bpy.context.object
    for vert in new_bar.data.vertices:
            if vert.co[2] > 0:#Zjiku ni up
                vert.co[2] = khigh*bairitsu#close
            else:
                vert.co[2] = klow*bairitsu
    set_origin_cursor(obj.name,candleLocation)
    
#end def
# テキストオブジェクトの追加
def add_text(text, t_color,location):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=(0.2,0.1,0.2)) # 図形を変形
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error

#convert to mesh

  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text

  return ob
#end def

def add_textKai(text, t_color,location,size):
# 角度設定時に利用
  ROT_QUATER = math.pi / 2
  bpy.ops.object.text_add()
  ob = bpy.context.object
  ob.data.body = text
  ob.data.extrude = 0.05
  ob.data.bevel_depth = 0.002
  
  bpy.ops.font.open(filepath="/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc")
  bpy.data.fonts["HiraginoSans-W6"].name = "HiraginoSans-W6"
  fnt = bpy.data.fonts.load('/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc')
  ob.data.font = fnt 
  
  ob.rotation_euler[0] = ROT_QUATER
  # 3Dカーソルの位置を0,0,0
  bpy.context.scene.cursor.location=(0.0,0.0,0.0)
  #3Dカーソルを原点を変更してから、translateする必要がある。
  bpy.ops.transform.translate(value=location)#26500*0.001,(1.8,0.1/3,26.5)
  bpy.ops.transform.resize(value=size) # 図形を変形(0.2,0.1,0.2)
  
  #ob.rotation_euler[2] = ROT_QUATER
  ob.data.align_x = 'CENTER'
  ob.data.align_y = 'CENTER'
  mat = bpy.data.materials.new('color_txt')
  mat.diffuse_color = t_color#(0.8, 0.8, 0.8, 1.0)
  # マテリアルスロットを追加する
  bpy.ops.object.material_slot_add()
  # 作成したマテリアルスロットに新規マテリアルを設定する
  bpy.context.object.active_material = mat
  #ob.active_material.diffuse_color = (1,0,0)
  #bpy.context.object.active_material.diffuse_color = (1,0,0)
  #mat.diffuse_color = (1.0,0.0,0.0)
  #mat.diffuse_color = (1,0,0)#t_color #error , I do not yet 2020/05/15 
  #ob.data.materials.append(mat)
  #ob.active_material.diffuse_color = t_color # error
#convert to mesh
  #s = bpy.context.scene.objects.active
  #s.name = "text_name"
  bpy.ops.object.convert(target='MESH')# work
  for obj in bpy.context.selected_objects:
     if obj.name=='Text':
         obj.name=text  
  return ob
#end def

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
def makeBarMaxtoMin(highobj,lowobj):
    #print('Max:',max(highobj))#df['High']
    #print('Min:',min(lowobj))#df['Low']
    #bairitsu is Global
    global count
    global xmove
    global bairitsu    
    #if bairistu=='' or bairitsu==0:
    #    print('def makeBarMaxtoMin(),bairitsu not defined,use 0.001')
     #   bairitsu=0.001    
    #every 500yen
    priceRange=500
    #highPriceNumはバーの本数を取得する
    highPriceNum,highmod=divmod(max(highobj),priceRange)#26200/priceRange
    lowPriceNum,lowmod=divmod(min(lowobj),priceRange)
    #高値については、余りが出たら、1を追加する
    #print('highmod:',highmod)
    if highmod!=0:
        highPriceNum=highPriceNum+1
        #Rangeで範囲を指定してしようする場合1加算では足りないので、rangeで更に1を加算する
        #print('after highPriceNum:',highPriceNum)

    for i in range(math.floor(lowPriceNum),math.floor(highPriceNum+1)):
        #range()が出力するのは、(highPriceNum-1)なので1を加算してhighPriceNum分までを計算させる
        print('barPrice:',i*priceRange)
        #i*priceRangeの位置でBarオブジェクトを作成する。
        # 3Dカーソルの位置を0,0,0
        bpy.context.scene.cursor.location=(0.0,0.0,0.0) 
        color=(0.8,0.5,0.8,0.8)
        add_text(str(i*priceRange), color,(1.8,0.1/3, (i*priceRange)*bairitsu+0.045))#0.045 is ajustment
        
        bpy.context.scene.cursor.location=(0.0,0.0,0.0)
        # 平板作成 26500bar1
        bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2.0)
        bpy.ops.transform.translate(value=(0.0,0.1/2,(i*priceRange)*bairitsu))#26500*0.001
        bpy.ops.transform.resize(value=(2.0,0.06/6,0.01/6)) # 図形を変形
        bpy.context.object.data.materials.append(mat3) # 材質
        for obj in bpy.context.selected_objects:
            if obj.name=='Cube':
                obj.name='bar_'+str(i*priceRange) 
#end def
######################################################################
#main
######################################################################
count=0#count is Global
xmove=0.8#1# move distancs
bairitsu=0.001# size Global

print('this Code for reading CSV.')
print('>>>>>CSV出力>>>>>')
#ここからCSV出力用
checkLineCount=0
df=[]

#CSVを読み込む
ifile='/Users/toshiromaseda/Documents/blender/script/2021年1月14日日経.csv'
try:#ファイルが存在しないときのエラー処理try
    with open(ifile,'tr') as fin:
        for iline in fin:
            try:
                tmp=iline.strip().split(",")#stripしてからsplit()だと理解している。
                if 'High' in tmp[0]:
                    continue
                if len(tmp) < 6:#全部で6列存在する。
                    print('ERROR 列の数があっていません。少ないようです。行数:',checkLineCount)
                    break
                print('iline[]:',tmp[0])
                #ここから処理を入れていけばよい
                df.append(nikkeiClass(tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5]))
                checkLineCount+=1
            except:
                print ('error')
except FileNotFoundError as e: # FileNotFoundErrorは例外クラス名
    print("ファイルが見つかりません。パス、ファイル名を確認してください", e)
    ifile.close()
    sys._exit()#ファイルがなければ終了

#Stock date
n=maenohi=5
end = datetime.now()
start = end - timedelta(days=n)
#start = end - timedelta(days=maenohi)#end.day-7 changes
#start = datetime(end.year, end.month, end.day-7)
##土日があると表示させるローソク足の数が少ないので、数が満たされるまでループするためSleepを入れた
#大量のデータはCSVで取得してからローソク足にしたほうが良さそう

'''
x=0
while x<=(maenohi):
    start = end - timedelta(days=n)
    df=data.DataReader('^N225','yahoo',start,end)#3990.T,#^N225
    date=df.index# 日付
    time.sleep(3)
    print('len(date):',len(date))
    print('3秒待ち')
    x=len(date)
    n=n+1
print(df.head(8))
if len(date)==0:
    print('ERROR Can not get any Price data, Check internet or yahoo finance com.')
    sys.exit()
'''

# 既存要素削除
for item in bpy.data.meshes:
    bpy.data.meshes.remove(item)

for item in bpy.data.materials:
    bpy.data.materials.remove(item)
        
#bpy.ops.outliner.item_rename()
#2.立方体 location:図形の中心座標 size:立方体の一辺の長さ rotation:立体の回転角(rad)
#bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=1.0, rotation=(0, 0, 0))

# 2.材質の定義(赤色)
mat1 = bpy.data.materials.new('Red')
mat1.diffuse_color = (1.0, 0.0, 0.0, 1.0)

# 3.材質の定義(青色)
mat2 = bpy.data.materials.new('blue')
mat2.diffuse_color = (0.0, 0.0, 1.0, 1.0)

mat3 = bpy.data.materials.new('gray')
mat3.diffuse_color = (0.8, 0.8, 0.8, 0.5)

mat5 = bpy.data.materials.new('yellow')
mat5.diffuse_color = (1.0, 0.9, 0.1, 1.0)

# 3Dカーソルの位置を0,0,0
#bpy.context.scene.cursor_location =(0.0,0.0,0.0)
bpy.context.scene.cursor.location=(0.0,0.0,0.0)

#date=df.indexをカウントして、それぞれを取得する。ちょっとスマートではないが、、
for fdate in df:
    khigh=float(fdate.high)
    klow=float(fdate.low)
    kopen=float(fdate.open)
    kclose=float(fdate.adjclose)
    #ここに日付ごとの処理を入れる。
    #
    if kopen-kclose<0:
        candle='yousen'#color Red
        #print('陽線')
    else:
        candle='insen'#color Blue
        #print('陰線')
    #objを生成する。
    #始値、終値でZ軸の高さを設定する。
    #print( fdate.strftime("%Y/%m/%d") )#2020-12-22 00:00:00となるので、時刻を除く2020-12-22
    #Candle_Main####################################################
    candleLocation=fcandle(candle,kopen,kclose,bairitsu,xmove,mat1,mat2)
    xmove+=0.048
    
    #Candle_hige####################################################
    fcandle_hige(candle,khigh,klow,bairitsu,candleLocation,mat1,mat2)
    #count is Global      
    count+=1

#最後のローソクのobjの横に矢印を与える
#この場合、ローソクの原点を移動させて、ローソクの中心に移動させる必要がある
candleCount=0
for obj in bpy.data.objects:
    if 'candle' in obj.name:
        #print(obj.name)
        candleCount+=1
candleName='candle'+str(candleCount)

#Arrow
bpy.ops.mesh.primitive_cone_add(radius1=1, radius2=0, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(0.05, 0.05, 0.05))
#図形を回転(Y軸周りに90°)
bpy.ops.transform.rotate(value=-3.1415/2 ,orient_axis='Y')
bpy.context.object.data.materials.append(mat5) 
bpy.ops.transform.translate(value=(bpy.data.objects[candleName].location[0]+0.08,bpy.data.objects[candleName].location[1],bpy.data.objects[candleName].location[2]))#


bpy.context.scene.cursor.location=(0.0,0.0,0.0)
#open,close
color=(1.0,1.0,1.0,1.0)
#str,color,location,size
lastOpen=float(df[len(df)-1].open)#始値
lastClose=float(df[len(df)-1].close)#終値
roundOpen='O:'+str(round(lastOpen,2))#画面に表示させる直近の始値文字
roundClose='C:'+str(round(lastClose,2))#画面に表示させる直近の終値文字

add_textKai(roundOpen, color,(xmove+0.1,0,lastOpen*bairitsu),(0.06,0.05,0.06))
add_textKai(roundClose, color,(xmove+0.1,0,lastClose*bairitsu),(0.06,0.05,0.06))

#end.strftime("%Y/%m/%d") or date[len(date)-1].strftime("%Y/%m/%d")today
color=(0.0,1.0,0.0,1.0)
coneLocation=bpy.data.objects['Cone'].location
#tyokkinDay=date[len(date)-1].strftime("%Y/%m/%d")
tyokkinDay=df[len(df)-1].index

if len(df)>0:
    add_textKai(tyokkinDay,color, (coneLocation[0]+0.16,coneLocation[1],coneLocation[2]),(0.06,0.05,0.06))
#print('last day:',date[len(date)-1])

#始値、終値、直近の日付の調整。オブジェクトが重なってしまう金額が近いときに離す処理
if candle=='yousen':#Openが下側でCloseが上側にあるはず
    #bpy.data.objects[roundOpen].dimensions[1]#Z方向の幅サイズではなくてY軸、理由はローカルで回転させたから
    #bpy.data.objects[roundClose].dimensions[1]
    #bpy.data.objects[tyokkinDay].dimensions[1]
    #始値、終値、直近の日付のlocationを取得する。Z方向ではなくてY軸の幅の半分を上下に加減算して重なりを調べる
    #bpy.data.objects[roundOpen].location[2]
    #bpy.data.objects[roundClose].location[2]
    #bpy.data.objects[tyokkinDay].location[2]
    #roundCloseを調整する.roundCloseの下側位置が、直近日付の上側位置以下になっているときに、直近日付の上の方にroundCloseを上へ移動させる
    
    #location is [2]:Z, dimensions is [1]:Y
    if bpy.data.objects[roundClose].location[2]-bpy.data.objects[roundClose].dimensions[1]/2 <= bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        #直近日付の位置に、プラスへ移動
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
    #roundOpenを調整する。roundOpenの「上側」位置が、直近日付の「下側」以上になっているときに、直近日付の「下の方」にroundOpenを下へ移動させる
    if bpy.data.objects[roundOpen].location[2]+bpy.data.objects[roundOpen].dimensions[1]/2 >=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
            #「マイナス」へ移動
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[1]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
else:#insen Openが上側でCloseが下側にあるはず.Yousenとは逆
    #roundOpen
    print('insen')
    if bpy.data.objects[roundOpen].location[2]-bpy.data.objects[roundOpen].dimensions[1]/2<=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundOpen].location[2]=bpy.data.objects[tyokkinDay].location[2]+bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Open')
    #roundClose
    if bpy.data.objects[roundClose].location[2]+bpy.data.objects[roundClose].dimensions[1]/2>=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]/2:
        bpy.data.objects[roundClose].location[2]=bpy.data.objects[tyokkinDay].location[2]-bpy.data.objects[tyokkinDay].dimensions[1]*1.5
        print('Close')

    

#2020/12/29
#print('Max:',max(df['High']))#最大値が取れる
#高値の最大値maxと安値の最小値minを取得して
#500円ごとのバー基準株価線(26500,27000,27500)を自動で作成したい。
#面倒だけど、別途高値、安値の配列オブジェクトを作って、メソッドに渡す
dfHigh=[]
dfLow=[]
for m in df:
    dfHigh.append(float(m.high))
    dfLow.append(float(m.low))

makeBarMaxtoMin(dfHigh,dfLow)

#camera move, near Cone obj
camera_obj = bpy.data.objects['Camera']
print(camera_obj.location)
camera_obj.location=(coneLocation[0]+0.16,coneLocation[1]-3.0,coneLocation[2])

#Neko呼び出し
file_path = '/Users/toshiromaseda/Documents/blender/model/テスト、研究モデル/Neko/Neko_simple_001.blend'
inner_path = 'Object'
object_name = 'Neko'
 
bpy.ops.wm.append(
    filepath=os.path.join(file_path, inner_path, object_name),
    directory=os.path.join(file_path, inner_path),
    filename=object_name
    )

bpy.context.scene.cursor.location=(0.0,0.0,0.0)
# 指定オブジェクトを取得する
#arg_objectname='Neko'
selectob = bpy.data.objects[object_name]
selectob.select_set(True) #2.9
selectob.location=(coneLocation[0],coneLocation[1]-0.1,coneLocation[2])
bpy.ops.transform.resize(value=(0.07,0.07,0.07)) # 図形を変形

print('done.')

''' Result



'''

 

python,株データ取得pandas_datareader 米ヤフーファイナンスからデータ欠落する時間帯があるメモ

#Blenderにpandas_datareaderインストール済

python,株データ取得のためのコード、Anaconda、JupyterLabで実行
#日経平均株価のデータを取得したときに、前日分が欠落することがあった。今日の分は取得できたのに、、、
#過去1週間のデータを取得とするはずだったが一部の日付データが取得できず。
#start: 2020/12/22
#today: 2020/12/29
#df=data.DataReader(‘^N225′,’yahoo’,start,end)
#しかし、午前中は 12/29当日データは取得できたけど、前日12/28分は取得できず。
#AM9-11ごろ x
#AM11:07分頃
#AM11:30 x
#11時53分 今度は28日が取得できて、今日の分が取得できず
#12:07 正常に取得できた。28日と今日の29日

結論:たぶん午前中は欠落するデータがあるかもしれない。午後12:05になると当日の日経平均株価が正常に取得できるようだ。正常に取得できないときは、日付が今日の分29日はあっても前日の28日がない。ちなみに25日分はあった

start: 2020/12/21
today: 2020/12/29
2020/12/21
2020/12/22
2020/12/23
2020/12/24
2020/12/25
2020/12/28>>午前中はこの日のデータが取得できず
2020/12/29>>午前中でも取得できた
                    High           Low          Open         Close  Volume  \
Date                                                                         
2020-12-21  26905.669922  26533.630859  26834.099609  26714.419922   60700   
2020-12-22  26639.990234  26361.660156  26559.330078  26436.390625   58600   
2020-12-23  26585.210938  26414.740234  26580.429688  26524.789062   56000   
2020-12-24  26764.529297  26605.259766  26635.109375  26668.349609   47900   
2020-12-25  26716.609375  26638.279297  26708.099609  26656.609375   33400   
2020-12-28  26854.029297  26664.599609  26691.289062  26854.029297   50700   
2020-12-29  27298.220703  26921.140625  26936.380859  27292.369141       0   

               Adj Close  
Date                      
2020-12-21  26714.419922  
2020-12-22  26436.390625  
2020-12-23  26524.789062  
2020-12-24  26668.349609  
2020-12-25  26656.609375  
2020-12-28  26854.029297  
2020-12-29  27292.369141