본문 바로가기
파이썬/MANIM

Manim. 그래프 그리기

by hustler78 2022. 9. 27.
728x90
반응형

 

 

 

Manim 을 본격적으로 이용해 보기 위해 그래프 그리는 작업을 준비했습니다.

금융공학에서 가장 유명한 그래프는 Black Schoels formula를 이용해서 구한  call option의 가격 그래프일 것입니다.

 

2022.08.17 - [금융공학] - 옵션 #2. 옵션 프리미엄 구하기(Closed form)

 

옵션 #2. 옵션 프리미엄 구하기(Closed form)

이번 글은 2022.08.17 - [금융공학] - 옵션 #1. 옵션이란? 옵션의 유명한 관계식이 있다던데.. 옵션 #1. 옵션이란? 옵션의 유명한 관계식이 있다던데.. 예전 글 2022.07.28 - [금융공학] - 선도와 선물 #1 : 선

sine-qua-none.tistory.com

에서 공식을 확인할 수 있고, 옵션 가격식에 대한 python code는 2022.08.19 - [금융공학] - 옵션 #4. 옵션 프리미엄 구하기 실습: 명시적 FDM등에서 발견할 수 있습니다.

 

 

Call option 가격 그래프

 

다음은 

  • 행사가 100
  • 만기 1년
  • 이자율 2%
  • 연속배당률 0%
  • 변동성 : 10%, 20%, 30%, 40%, 50%

인 상황에서 기초자산의 현재가가 50~150을 움직일 때, Manim으로 그려본 그래프입니다.

 

 

 

Python Code

위 그래프를 구현한 코드는 다음과 같습니다.

from scipy.stats import norm
N = norm.cdf

def CallOptionBS(S, K, T, r, q, sigma):
    if T == 0:
        return np.max(S - K, 0)
    else:
        d1 = (np.log(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * np.sqrt(T))
        d2 = d1 - sigma * np.sqrt(T)
        return S * np.exp(-q * T) * N(d1) - K * np.exp(-r * T) * N(d2)

class CoordSysExample(Scene):
    def construct(self):
        # the location of the ticks depends on the x_range and y_range.
        grid = Axes(
            x_range=[50, 150, 10],  # step size determines num_decimal_places.
            y_range=[0, 50, 10],
            x_length=9,
            y_length=5.5,
            x_axis_config={"include_numbers": True, "font_size": 24},
            #
            # axis_config={
            #     "numbers_to_include": np.arange(50,150+10, 10),
            #     "font_size": 24,
            # },
            tips=False,
        )

        #Labels for the x-axis and y-axis.
        
        y_label = grid.get_y_axis_label(Text("Call Value", font_size=30), edge=LEFT, direction=LEFT, buff=0.4)
        x_label = grid.get_x_axis_label(Text("Stock", font_size=30), direction=DOWN, edge=DOWN)
        grid_labels = VGroup(x_label, y_label)
        
        # Draw Graph
        vol_list = [0.1, 0.2, 0.3, 0.4, 0.5]
        graphs = VGroup()
        for i, vol in enumerate(vol_list):
            if i == 0:
                graph = grid.plot(lambda x: CallOptionBS(x, 100, 1, 0.02, 0, vol), color=BLUE_A)
                label = grid.get_graph_label(graph=graph,
                                             label=MathTex(r"\sigma={}\%".format(vol * 100), font_size=30),
                                             x_val=100,
                                             direction=RIGHT * 2,
                                             color=BLUE_A
                                             )
                graphs += label

            elif i == len(vol_list) - 1:
                graph = grid.plot(lambda x: CallOptionBS(x, 100, 1, 0.02, 0, vol), color=YELLOW_A)
                label = grid.get_graph_label(graph=graph,
                                             label=MathTex(r"\sigma={}\%".format(vol * 100), font_size=30),
                                             x_val=100,
                                             direction=LEFT * 2,
                                             color=YELLOW_A
                                             )
                graphs += label

            else:
                graph = grid.plot(lambda x: CallOptionBS(x, 100, 1, 0.02, 0, vol), color=WHITE)

        title = Title(
            r"Black Scholes Formula for Call Option",
            include_underline=False,
            font_size=40,
        )

        self.add(title, graphs, grid, grid_labels)

 

def CallOptionBS(S, K, T, r, q, sigma):

이 부분은 2022.08.19 - [금융공학] - 옵션 #4. 옵션 프리미엄 구하기 실습: 명시적 FDM 등등에서 많이 다루었던 코드이기 때문에 생략하도록 하겠습니다.

 

간략히 코드를 살펴보죠.

        grid = Axes(
            x_range=[50, 150, 10],  # 50, 150 까지 step =10 으로 간격설정
            y_range=[0, 50, 10],	# 0~50 까지 step= 10으로 간격설정
            x_length=9,		#x 축의 길이는 9
            y_length=5.5,
            x_axis_config={"include_numbers": True, "font_size": 24},	#x축 환경을 세팅함. 숫자라벨을 포함하고, 폰트크기는 24
            
            # x,y 양축을 동시에 환경설정하는 것은 아래와 같은 방법으로..
            # axis_config={
            #     "numbers_to_include": np.arange(50,150+10, 10),
            #     "font_size": 24,
            # },
            tips=False,	# 좌표축끝의 화살표 모양은 제거한다.
        )

Axes 라는 클래스가 나옵니다. 여기의 설명을 그대로 가져왔습니다.

class Axes(x_range=None, y_range=None, x_length=12, y_length=6, axis_config=None, x_axis_config=None, y_axis_config=None, tips=True, **kwargs)


$x,y$ 축을 생성하는 클래스입니다.

PARAMETERS

○ x_range :  The (x_min, x_max, x_step) values of the x-axis.

○ y_range : The (y_min, y_max, y_step) values of the y-axis.

○ x_length : The length of the x-axis.

○ y_length :  The length of the y-axis.

○ axis_config : x축과 y축 동시에 환경설정하는 Numline Class형태

○ x_axis_config : NumberLine that influence the x-axis. (x축 환경설정)

○ y_axis_config : NumberLine that influence the y-axis. (y축 환경설정)

○ tips (bool) : Whether or not to include the tips on both axes. (좌표축 끝의 화살촉 여부)

 

x-axis-config, y-axis-config, axis-config는 모두 축에 대한 환경 설정을 하는 기능으로,  NumberLine이라는 class의 변수들을 그대로 씁니다.  여기를 참고해 보세요.

class NumberLine(x_range=None, length=None, unit_size=1, include_ticks=True, tick_size=0.1, numbers_with_elongated_ticks=None, longer_tick_multiple=2, exclude_origin_tick=False, rotation=0, stroke_width=2.0, include_tip=False, tip_width=0.35, tip_height=0.35, include_numbers=False, font_size=36, label_direction=array([ 0., -1., 0.]), label_constructor=m.mobject.text.tex_mobject.MathTex'>, scaling=m.mobject.graphing.scale.LinearBase object>, line_to_number_buff=0.25, decimal_number_config=None, numbers_to_exclude=None, numbers_to_include=None, **kwargs)[source]


주로 쓰는 파라미터는 아래와 같습니다.

○ rotation (float) – The angle (in radians) at which the line is rotated. 축의 회전에 관계됨

○ include_numbers (bool) – Whether to add numbers to the tick marks. The number of decimal places is determined by the step size, this default can be overridden by decimal_number_config, 축에 label을 표기할지의 문제

○ scaling (_ScaleBase) – The way the x_range is value is scaled, i.e. LogBase for a logarithmic numberline. Defaults to LinearBase. 

○ font_size (float) – The size of the label mobjects. Defaults to 36.

○ numbers_to_exclude (Iterable[float] | None) – An explicit iterable of numbers to not be added to the number line.

○ numbers_to_include (Iterable[float] | None) – An explicit iterable of numbers to add to the number line

tip 은 축의 끝부분 화살촉 표시로, False이면 화살촉이 안 보입니다.

 

 


        #Labels for the x-axis and y-axis.
        
        y_label = grid.get_y_axis_label(Text("Call Value", font_size=30), edge=LEFT, direction=LEFT, buff=0.4)
        x_label = grid.get_x_axis_label(Text("Stock", font_size=30), direction=DOWN, edge=DOWN)
        grid_labels = VGroup(x_label, y_label)

get_x_axis_label , get_y_axis_label : $x$축 $y$축 label 지정을 하는 옵션입니다.

 

get_x_axis_label(label, edge=array([1., 1., 0.]), direction=array([1., 1., 0.]), buff=0.1, **kwargs)

○ label (float | str | Mobject) – The label. Defaults to MathTex for str and float inputs, Label 이름을 뜻함

○ edge (Sequence[float]) – The edge of the x-axis to which the label will be added, by default UR. Label이 축에 어떻게 위치하는지를 정하는 방향

○ direction (Sequence[float]) – Allows for further positioning of the label from an edge, by default UR. Edge에서 더 미세조정하는 Label의 위치 

○ buff (float) – The distance of the label from the line. 선에서 얼만큼 여유를 두고 label이 쓰여지는지

 

 


        # Draw Graph
        vol_list = [0.1, 0.2, 0.3, 0.4, 0.5]	# Volatility는 총 5개 값
        graphs = VGroup()	# 5의 graph를 담을 Vectorized Group설정
        for i, vol in enumerate(vol_list):	# index와 volatility를 같이 for문 돌리기 위해 enumerate씀
            if i == 0:	#첫번째 vol에 대해서
                graph = grid.plot(lambda x: CallOptionBS(x, 100, 1, 0.02, 0, vol), color=BLUE_A)
                	#call option graph를 그림
                
                # grid 축에 그린 graph에 label을 설정함
                label = grid.get_graph_label(graph=graph,
                                             label=MathTex(r"\sigma={}\%".format(vol * 100), font_size=30),
                                             x_val=100,
                                             direction=RIGHT * 2,
                                             color=BLUE_A
                                             )
                graphs += label	# label object를 graph 그룹에 담음

            elif i == len(vol_list) - 1:	# 마지막 vol에 대해서
            	# yellow color 그래프 그림
                graph = grid.plot(lambda x: CallOptionBS(x, 100, 1, 0.02, 0, vol), color=YELLOW_A)
                # label을 붙임
                label = grid.get_graph_label(graph=graph,
                                             label=MathTex(r"\sigma={}\%".format(vol * 100), font_size=30),
                                             x_val=100,
                                             direction=LEFT * 2,
                                             color=YELLOW_A
                                             )
                graphs += label

            else:	# 중간 vol들은 그냥 white로 그림
                graph = grid.plot(lambda x: CallOptionBS(x, 100, 1, 0.02, 0, vol), color=WHITE)

○ get_graph_label 은 그래프에 레이블(label)을 설정하는 메서드입니다. 여기를 참고해 보세요.

 

get_graph_label(graph, label='f(x)', x_val=None, direction=array([1., 0., 0.]), buff=0.25, color=None, dot=False, dot_config=None)


파라미터

○ graph (ParametricFunction) – The curve. (label 을 붙일 커브)

○ label (float | str | Mobject) – The label for the function’s curve. (레이블 명)

○ x_val (float | None) – The x_value along the curve that positions the label. (레이블을 붙일 $x$좌표 위치)

○ direction (Sequence[float]) – The cartesian position, relative to the curve that the label will be at –> LEFT, RIGHT. (레이블이 쓰여지는 방향)

○ buff (float) – The distance between the curve and the label.(레이블과 커브와의 여유거리 조정)

○ color (Color | None) – The color of the label. Defaults to the color of the curve. (레이블의 색)

○ dot (bool) – Whether to add a dot at the point on the graph. (레이블이 쓰여질 $x$좌표에 점 표시를 하는지 여부)

dot_config (dict | None) – Additional parameters to be passed to Dot.

 

 


        title = Title(
            r"Black Scholes Formula for Call Option",
            include_underline=False,
            font_size=40,
        )

Title 은 제목입니다.

class Title(*text_parts, include_underline=True, match_underline_width_to_text=False, underline_buff=0.25, **kwargs)

○ 제목과 폰트사이즈, 밑줄 포함여부 등을 정할 수 있습니다.

 

728x90
반응형

'파이썬 > MANIM' 카테고리의 다른 글

Manim. 삼각형의 scale, rotate  (0) 2022.09.26
Manim. 도형 회전 rotate의 비밀  (0) 2022.09.22
Manim. 삼각형 그리기  (0) 2022.09.21
Manim. 정사각형 그리기  (0) 2022.09.16
Manim. 원 그리기  (0) 2022.09.14

댓글