import csv
import svgwrite
from datetime import datetime
# 入力CSVと出力SVGファイル
csv_file = r'D:\WinPython\notebooks\stock_prices.csv'
output_file = r'Y:\candles.svg'
# ローソク足のサイズ設定
candle_width = 6
candle_gap = 4
candle_step = candle_width + candle_gap
# 高さ拡大!
price_top = 0
price_bottom = 300
volume_top = 300
volume_bottom = 500
# 初期スケール値
price_min = float('inf')
price_max = 0
volume_max = 0
# データ読み込み&スケール取得
rows = []
with open(csv_file, newline='') as f:
reader = csv.reader(f)
next(reader) # ヘッダーをスキップ
for row in reader:
if len(row) < 6:
continue
try:
date = datetime.strptime(row[0], "%Y-%m-%d")
open_, high, low, close, volume = map(int, row[1:6])
except ValueError:
continue
price_max = max(price_max, high)
price_min = min(price_min, low)
volume_max = max(volume_max, volume)
rows.append((date, open_, high, low, close, volume))
# スケール調整
price_range = price_max - price_min
if price_range == 0:
raise ValueError("price_range がゼロです!")
price_span = price_bottom - price_top
volume_span = volume_bottom - volume_top
def scale_price(p): return ((p - price_min) * price_span) / price_range
def price_to_y(p): return price_bottom - scale_price(p)
# 横幅をデータ数に合わせて自動調整
width = len(rows) * candle_step + 20
height = volume_bottom + 40
# SVG描画
dwg = svgwrite.Drawing(output_file, size=(width, height))
x = 10
month_labels = {}
# 移動平均線の準備
sma_25 = []
sma_50 = []
sma_75 = []
close_prices = []
x_positions = []
for i, (date, open_, high, low, close, volume) in enumerate(rows):
fill = '#f44336' if close >= open_ else '#4caf50'
y_open = price_to_y(open_)
y_close = price_to_y(close)
y_high = price_to_y(high)
y_low = price_to_y(low)
body_top = min(y_open, y_close)
body_bottom = max(y_open, y_close)
body_height = body_bottom - body_top
scaled_volume = volume * volume_span / volume_max
vol_y = volume_bottom - scaled_volume
x_center = x + candle_width // 2
x_positions.append(x_center)
close_prices.append(close)
# ヒゲ(中央から上下に)
dwg.add(dwg.line(start=(x_center, y_high), end=(x_center, body_top), stroke='black', stroke_width=1))
dwg.add(dwg.line(start=(x_center, body_bottom), end=(x_center, y_low), stroke='black', stroke_width=1))
# 胴体
dwg.add(dwg.rect(insert=(x, body_top), size=(candle_width, body_height), fill=fill, stroke='black'))
# Volume棒
dwg.add(dwg.rect(insert=(x, vol_y), size=(candle_width, scaled_volume), fill='#2196f3'))
# 月ラベル(1ヶ月に1回だけ表示)
month_key = date.strftime("%Y-%m")
if month_key not in month_labels:
dwg.add(dwg.text(month_key, insert=(x_center, volume_bottom + 12), font_size='8px', text_anchor='middle'))
month_labels[month_key] = True
x += candle_step
# 移動平均線の描画関数
def draw_sma_line(period, color):
points = []
for i in range(len(close_prices)):
if i + 1 >= period:
avg = sum(close_prices[i + 1 - period:i + 1]) / period
y = price_to_y(avg)
x = x_positions[i]
points.append((x, y))
for i in range(1, len(points)):
dwg.add(dwg.line(start=points[i - 1], end=points[i], stroke=color, stroke_width=1.5))
# 移動平均線を描画
draw_sma_line(25, '#e91e63') # ピンク
draw_sma_line(50, '#4caf50') # 緑
draw_sma_line(75, '#2196f3') # 青
# Y軸ラベル(価格:1000円単位)
step = 1000
label_price = (price_min // step) * step
while label_price <= price_max:
y = price_to_y(label_price)
dwg.add(dwg.text(f"{label_price}円", insert=(2, y + 4), font_size='8px', fill='black'))
label_price += step
# Volume Y軸ラベル(25%刻み)
for i in range(1, 5):
ratio = i * 0.25
value = int(volume_max * ratio)
y = volume_bottom - (volume_span * ratio)
dwg.add(dwg.text(f"{value:,}", insert=(2, y + 4), font_size='8px', fill='blue'))
# 保存
dwg.save()
print(f"[完了] SVGファイルを生成しました: {output_file}")
ディスカッション
コメント一覧
まだ、コメントがありません