Đối với những ngành nghề lâu nay phụ thuộc vào việc tìm kiếm thông qua các bảng tính, Python đặc biệt có giá trị. Citigroup, một ngân hàng của Mỹ, đã giới thiệu một khóa học về Python cho các nhà phân tích học viên của mình. - Nhà kinh tế học
Các chuyên gia tài chính từ lâu đã có quyền truy cập vào VBA (Visual Basic for Applications) trong Excel để xây dựng chức năng tùy chỉnh và tự động hóa quy trình làm việc. Với sự xuất hiện của Google Trang tính trong những năm gần đây như một đối thủ nặng ký trong không gian bảng tính, Google Apps Script hiện cung cấp thêm một sự lựa chọn.
Tuy nhiên, tôi muốn thu hút sự chú ý đến tùy chọn thứ ba, ngôn ngữ lập trình Python, đã trở nên rất phổ biến trong một số lĩnh vực.
Trong bài viết này, tôi sẽ cung cấp một số ví dụ về những gì bạn có thể đạt được với Python, bắt đầu với tổng quan về ngôn ngữ này và tại sao nó lại trở nên phổ biến trong nhiều lĩnh vực như vậy, bao gồm phát triển web, học máy, tài chính, khoa học và giáo dục, chỉ là một vài cái tên. Sau đó, nửa sau sẽ bao gồm hướng dẫn từng bước.
Mục đích của tôi khi viết bài này là để giúp bạn quyết định xem liệu Python có đủ hấp dẫn để bạn cân nhắc thêm nó vào hộp công cụ tài chính của mình hay không. Nếu bạn thực hiện bước nhảy vọt, có rất nhiều ứng dụng, khóa học, video, bài báo, sách và bài đăng trên blog để học ngôn ngữ. Ở cuối phần, tôi đã liệt kê một số tài nguyên đã giúp tôi trong suốt quá trình.
Lời giới thiệu của tôi về lập trình là học BASIC trên Oric 1 vào giữa những năm 1980. Hồi đó BASIC là ngôn ngữ phổ biến nhất dành cho người mới bắt đầu. Các ngôn ngữ khác mà tôi đã sử dụng vào cuối những năm 80 cho đến giữa những năm 90 là Pascal và C, nhưng tôi chưa bao giờ sử dụng chúng trong bất kỳ năng lực chuyên môn nào và tôi không mong đợi sẽ cần hoặc sử dụng các kỹ năng lập trình. Theo hiểu biết của tôi vào thời điểm cuối những năm 90, tài chính và lập trình là hai lĩnh vực rất khác nhau, khi tôi chọn con đường khởi nghiệp trong lĩnh vực tài chính.
Nhanh chóng chuyển tiếp sang năm 2012, và tôi đã tìm kiếm lập trình trở lại như một sở thích, vì vậy tôi bắt đầu nghiên cứu các ngôn ngữ có sẵn vào thời điểm đó. Hóa ra khá nhiều điều đã xảy ra, và khi tôi bắt gặp Python, tôi đã bị cuốn hút, vì nhiều lý do mà tôi sẽ trình bày trong phần tiếp theo. Kể từ đó, tôi đã sử dụng Python cho một loạt các tác vụ, từ các tập lệnh nhỏ đến các dự án lớn hơn, cả cá nhân và chuyên nghiệp. Nhiều, nhưng không phải tất cả, có liên quan đến bảng tính, bàn làm việc của nhiều chuyên gia tài chính.
Dưới đây là một vài ví dụ về cách bảng tính và Python có thể kết hợp với nhau tốt như thế nào:
Tôi làm việc với tất cả các khía cạnh của giao dịch M&A, không chỉ là thực hiện mà còn cả tích hợp. Trong một trường hợp gần đây, nhóm PMO đã quyết định phương pháp quản lý dự án và chương trình kết hợp, sử dụng lập kế hoạch thác nước và biểu đồ Gantt cho các kế hoạch cấp cao cho từng trong số mười hai dòng công việc tích hợp, ngoài ra còn có bảng Kanban để theo dõi hàng trăm hoạt động đang diễn ra. vào bất kỳ thời điểm nào, trong kế hoạch 100 ngày đầu tiên và hơn thế nữa. Công cụ Kanban đã được chọn, MeisterTask, có một số tính năng thống kê và báo cáo, nhưng nhu cầu của chúng tôi vượt ra ngoài điều đó về phân tích và trình bày, đòi hỏi một giải pháp tùy chỉnh. Đây là quy trình làm việc mà tôi đã tự động hóa bằng Python:
Việc phát triển kịch bản yêu cầu một khoản đầu tư trả trước trong vài giờ, nhưng hiện tại, việc cập nhật gói báo cáo cho các cuộc họp của ban chỉ đạo hoặc phân tích đột xuất chỉ mất vài phút. Theo nghĩa đen, khoảng 30 giây để chuyển đến đúng thư mục và chạy tập lệnh bằng lệnh một dòng, sau đó vài phút để sao chép-dán đầu ra vào trang trình bày. Với khoảng 500 hoạt động (thẻ) trên mười hai dòng công việc đã được thực thi khoảng một tháng, theo dõi hàng tuần về cách chúng di chuyển, trong dòng thời gian chương trình hai năm, bạn nhanh chóng thấy mình đang xử lý hàng nghìn và cuối cùng là hàng chục nghìn điểm dữ liệu trên hàng chục trong số các tệp. Nếu không có tự động hóa, chúng ta đang nói về một số nhiệm vụ rất tẻ nhạt ở đây.
Đánh đổi “giá trị thời gian của tiền bạc” giữa việc chỉ bắt tay vào làm hay tăng thêm khối lượng công việc ban đầu bằng cách thiết lập tự động hóa là một chủ đề phổ biến trong tài chính. Tôi đã đưa ra quyết định tương tự với bước đầu tiên của quy trình này, bằng cách xuất dữ liệu dưới dạng tệp CSV. MeisterTask, giống như nhiều ứng dụng web hiện đại, có một API, có thể được kết nối với ứng dụng Python của bạn, nhưng thời gian dành cho việc thiết lập nó sẽ vượt xa thời gian tiết kiệm cho trường hợp sử dụng của chúng tôi ở đây.
Vì vậy, như bạn thấy, đôi khi giải pháp tối ưu là tự động hóa các bước nhất định của quy trình làm việc và giữ các bước khác theo cách thủ công.
Một ví dụ khác là một cái gì đó tôi đã làm vì sở thích cá nhân nhưng tôi muốn làm nổi bật nó vì nó chứa một số yếu tố thú vị khác của tiện ích Python:
Kết quả ở đây có thể được kết hợp với trọng lượng cá nhân của riêng bạn về sở thích và giới hạn tài chính khi tìm kiếm bất động sản.
Đây chỉ là hai ví dụ, tập trung vào việc tự động hóa công việc liên quan đến bảng tính và thêm các tính năng, nhưng cơ hội với Python là gần như vô tận. Trong phần tiếp theo, tôi sẽ phác thảo lý do tại sao nó trở nên phổ biến như vậy, trước khi chuyển sang hướng dẫn mô phỏng Monte Carlo từng bước bằng Python.
Ngôn ngữ lập trình Python đã xuất hiện từ năm 1990, nhưng phải đến những năm gần đây, sự phổ biến của nó mới bùng nổ.
Có một số lý do giải thích cho điều này, chúng ta hãy lần lượt xem xét từng lý do.
Ngôn ngữ lập trình cấp cao là ngôn ngữ trừu tượng hóa nhiều chi tiết về hoạt động bên trong của máy tính. Một ví dụ điển hình là quản lý bộ nhớ. Các ngôn ngữ lập trình cấp thấp hơn yêu cầu sự hiểu biết chi tiết về sự phức tạp của cách bố trí, cấp phát và giải phóng bộ nhớ của máy tính, bên cạnh thời gian sử dụng và các dòng mã cần thiết để xử lý các tác vụ. Python tóm tắt và tự động xử lý nhiều chi tiết này, giúp bạn tập trung vào những gì bạn muốn hoàn thành.
Bởi vì Python là một ngôn ngữ lập trình cấp cao, mã ngắn gọn hơn và gần như hoàn toàn tập trung vào logic nghiệp vụ của những gì bạn muốn đạt được, thay vì các chi tiết triển khai kỹ thuật. Các lựa chọn thiết kế ngôn ngữ góp phần vào điều này:ví dụ, Python không yêu cầu sử dụng dấu ngoặc nhọn hoặc dấu chấm phẩy để mô tả các hàm, vòng lặp và dòng theo cách mà nhiều ngôn ngữ khác làm, điều này làm cho nó ngắn gọn hơn và như một số lập luận, cải thiện dễ đọc.
Một quan sát đã ảnh hưởng đến các lựa chọn thiết kế ngôn ngữ trong Python là các chương trình được đọc thường xuyên hơn chúng được viết. Python vượt trội ở đây vì mã của nó trông rất gần với tiếng Anh thuần túy, đặc biệt nếu bạn đặt tên cho các thành phần khác nhau của tập lệnh hoặc chương trình của mình theo cách hợp lý.
Thử và sai được chứng ngộ vượt trội hơn việc lập kế hoạch của những trí tuệ hoàn mỹ. - David Kelley
Python lý tưởng cho việc tạo mẫu và phát triển nhanh chóng, lặp đi lặp lại (và, vâng, thử-và-sai) vì các công cụ thông dịch tương tác như Python shell, IPython và sổ ghi chép Jupyter nằm ở phía trước và trung tâm trong chuỗi công cụ Python. Trong các môi trường tương tác này, bạn có thể viết và thực thi từng dòng mã một cách riêng biệt và xem kết quả (hoặc một thông báo lỗi hữu ích) ngay lập tức. Các ngôn ngữ khác cũng có điều này, nhưng trong hầu hết các trường hợp, không giống với Python.
Ngoài khả năng tuyệt vời cho việc tạo mẫu, Python cũng là một ngôn ngữ tuyệt vời và mạnh mẽ cho các ứng dụng sản xuất lớn. Một số công ty phần mềm lớn nhất trên thế giới sử dụng rất nhiều Python trong nhiều ứng dụng và trường hợp sử dụng khác nhau.
Mọi thứ cần thiết cho các hoạt động cơ bản đều được tích hợp ngay trong ngôn ngữ này, nhưng ngoài ra, thư viện chuẩn Python có các công cụ để làm việc với tệp, phương tiện, mạng, thông tin ngày và giờ, v.v. Điều này cho phép bạn hoàn thành nhiều nhiệm vụ khác nhau mà không cần phải tìm kiếm các gói của bên thứ ba.
Đối với các chuyên gia tài chính, Pandas với DataFrame và Sê-ri các đối tượng và Numpy với ndarray của nó là các bài tập về phân tích tài chính với Python. Kết hợp với matplotlib và các thư viện trực quan khác, bạn có các công cụ tuyệt vời để hỗ trợ năng suất.
Python được phát triển theo giấy phép nguồn mở, nó cũng miễn phí để sử dụng cho mục đích thương mại.
Sau đây là hướng dẫn từng bước chỉ ra cách tạo phiên bản đơn giản của mô phỏng Monte Carlo được mô tả trong bài đăng blog trước của tôi, nhưng sử dụng Python thay vì plugin @RISK cho Excel.
Phương pháp Monte Carlo dựa trên lấy mẫu ngẫu nhiên để thu được kết quả số. Một ứng dụng như vậy là vẽ các mẫu ngẫu nhiên từ phân bố xác suất đại diện cho các trạng thái tiềm ẩn không chắc chắn trong tương lai của thế giới nơi các biến hoặc giả định có thể đảm nhận một loạt giá trị.
Sẽ rất hữu ích nếu thực hiện mô phỏng Monte Carlo trên mô hình định giá DCF đơn giản thay vì các ví dụ phổ biến hơn mà bạn thấy hiển thị giá trị quyền chọn hoặc các công cụ phái sinh khác, vì đối với điều này, chúng tôi không cần bất kỳ phép toán nào ngoài những điều cơ bản về tính toán báo cáo tài chính và chiết khấu dòng tiền, cho phép chúng tôi tập trung vào các khái niệm và công cụ Python. Xin lưu ý rằng mô hình hướng dẫn cơ bản này nhằm minh họa các khái niệm chính và không hữu ích cho bất kỳ mục đích thực tế nào. Tôi cũng sẽ không đề cập đến bất kỳ khía cạnh học thuật nào của mô phỏng Monte Carlo.
Hướng dẫn giả định rằng bạn đã quen thuộc với các khối xây dựng cơ bản của lập trình, chẳng hạn như các biến và hàm. Nếu không, có thể hữu ích nếu bạn dành 10 phút để kiểm tra các khái niệm chính trong phần giới thiệu này.
Tôi bắt đầu với cùng một mô hình định giá DCF rất đơn giản được sử dụng trong hướng dẫn mô phỏng Monte Carlo. Nó có một số chi tiết đơn hàng chính từ ba báo cáo tài chính và ba ô đầu vào được đánh dấu, trong phiên bản Excel có các ước tính điểm mà bây giờ chúng tôi muốn thay thế bằng phân phối xác suất để bắt đầu khám phá các phạm vi kết quả tiềm năng.
Làm cho nó hoạt động, làm cho nó đúng, làm cho nó nhanh chóng - Kent Beck
Mục đích của hướng dẫn này là cung cấp cho các chuyên gia tài chính mới làm quen với Python không chỉ giới thiệu về một chương trình hữu ích có thể trông như thế nào, mà còn giới thiệu về quy trình lặp đi lặp lại mà bạn có thể sử dụng để phát triển nó. Do đó, nó có hai phần:
Sổ ghi chép Jupyter là một công cụ tuyệt vời để làm việc với Python một cách tương tác. Nó là một trình thông dịch Python tương tác với các ô có thể chứa mã, văn bản Markdown, hình ảnh hoặc dữ liệu khác. Đối với hướng dẫn này, tôi đã sử dụng Nền tảng lượng tử Python, nhưng tôi cũng có thể giới thiệu Colaboratory của Google, miễn phí và chạy trên đám mây. Khi đó, chỉ cần chọn “Máy tính xách tay Python 3 mới” trong menu “Tệp” và bạn đã sẵn sàng.
Sau khi thực hiện xong, bước tiếp theo là nhập các gói của bên thứ ba mà chúng tôi cần để thao tác và trực quan hóa dữ liệu, đồng thời cho chương trình biết rằng chúng tôi muốn xem biểu đồ nội tuyến trong sổ ghi chép của mình, thay vì trong các cửa sổ riêng biệt:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
Một lưu ý trước khi chúng ta bắt đầu đặt tên cho các biến đầu tiên của mình. Như tôi đã nhấn mạnh, khả năng đọc là một trong những điểm mạnh của Python. Ngôn ngữ thiết kế đi một chặng đường dài để hỗ trợ điều đó, nhưng mọi người viết mã có trách nhiệm làm cho nó dễ đọc và dễ hiểu, không chỉ cho người khác mà còn cho chính họ. Như Luật của Eagleson đã tuyên bố, “Bất kỳ mã nào của riêng bạn mà bạn chưa xem xét trong sáu tháng trở lên cũng có thể đã được viết bởi người khác.”
Một nguyên tắc chung là đặt tên cho các thành phần của chương trình của bạn theo cách mà bạn giảm thiểu nhu cầu nhận xét riêng biệt giải thích những gì chương trình của bạn thực hiện.
Với ý nghĩ đó, hãy tiếp tục.
Có nhiều cách mà chúng ta có thể làm việc với dữ liệu bảng tính hiện có bằng Python. Ví dụ:chúng tôi có thể đọc một trang tính vào Pandas DataFrame bằng một dòng mã bằng cách sử dụng read_excel
yêu cầu. Nếu bạn muốn tích hợp chặt chẽ hơn và liên kết thời gian thực giữa bảng tính và mã Python của mình, thì có cả tùy chọn thương mại và miễn phí để cung cấp chức năng đó.
Vì mô hình ở đây rất đơn giản và để tập trung vào các khái niệm Python, chúng tôi sẽ tạo lại nó từ đầu trong tập lệnh của mình. Ở cuối phần đầu tiên, tôi sẽ chỉ cho bạn cách xuất những gì chúng tôi đã tạo sang bảng tính.
Bước đầu tiên hướng tới việc tạo bản trình bày báo cáo tài chính bằng Python, chúng ta sẽ cần một cấu trúc dữ liệu phù hợp. Có rất nhiều thứ để bạn lựa chọn, một số được tích hợp sẵn trong Python, một số khác từ các thư viện khác nhau hoặc chúng ta có thể tạo của riêng mình. Bây giờ, hãy sử dụng Chuỗi từ thư viện Pandas để xem chức năng của nó:
years = ['2018A', '2019B', '2020P', '2021P', '2022P', '2023P']
sales = pd.Series(index=years)
sales['2018A'] = 31.0
sales
Đầu vào này và đầu ra tương ứng của nó được hiển thị bên dưới:
Với ba dòng đầu tiên, chúng tôi đã tạo cấu trúc dữ liệu với chỉ mục bao gồm các năm (mỗi dòng được đánh dấu để hiển thị là Thực tế, Ngân sách hay Dự kiến), giá trị khởi điểm (tính bằng triệu euro, như trong mô hình DCF ban đầu) và ô trống (NaN, “Không phải số”) cho các phép chiếu. Dòng thứ tư in ra một biểu diễn của dữ liệu - nói chung, việc nhập tên của một biến hoặc các đối tượng khác trong trình thông dịch tương tác thường sẽ cung cấp cho bạn một biểu diễn hợp lý về nó.
Tiếp theo, chúng tôi khai báo một biến để đại diện cho mức tăng trưởng doanh số hàng năm dự kiến. Ở giai đoạn này, nó là một ước tính điểm, con số tương tự như trong mô hình DCF ban đầu của chúng tôi. Trước tiên, chúng tôi muốn sử dụng các đầu vào giống nhau đó và xác nhận rằng phiên bản Python của chúng tôi hoạt động tương tự và cho kết quả tương tự như phiên bản Excel, trước khi xem xét việc thay thế các ước tính điểm bằng phân phối xác suất. Sử dụng biến này, chúng tôi tạo một vòng lặp tính toán doanh số bán hàng trong từng năm của các dự báo dựa trên năm trước và tốc độ tăng trưởng:
growth_rate = 0.1
for year in range(1, 6):
sales[year] = sales[year - 1] * (1 + growth_rate)
sales
Bây giờ chúng tôi có doanh số bán hàng dự kiến, thay vì NaN:
Sử dụng phương pháp tương tự, chúng tôi tiếp tục thông qua các báo cáo tài chính, khai báo các biến khi chúng tôi cần và thực hiện các tính toán cần thiết để cuối cùng đạt được dòng tiền tự do. Khi chúng tôi đến đó, chúng tôi có thể kiểm tra xem những gì chúng tôi có có tương ứng với những gì phiên bản Excel của mô hình DCF nói hay không.
ebitda_margin = 0.14
depr_percent = 0.032
ebitda = sales * ebitda_margin
depreciation = sales * depr_percent
ebit = ebitda - depreciation
nwc_percent = 0.24
nwc = sales * nwc_percent
change_in_nwc = nwc.shift(1) - nwc
capex_percent = depr_percent
capex = -(sales * capex_percent)
tax_rate = 0.25
tax_payment = -ebit * tax_rate
tax_payment = tax_payment.apply(lambda x: min(x, 0))
free_cash_flow = ebit + depreciation + tax_payment + capex + change_in_nwc
free_cash_flow
Điều này mang lại cho chúng tôi dòng tiền tự do:
Một dòng ở trên có lẽ cần nhận xét ở giai đoạn này là tax_payment
thứ hai tài liệu tham khảo. Ở đây, chúng tôi áp dụng một chức năng nhỏ để đảm bảo rằng trong các tình huống mà lợi nhuận trước thuế trở nên âm, khi đó chúng tôi sẽ không có khoản thanh toán thuế dương. Điều này cho thấy bạn có thể áp dụng các chức năng tùy chỉnh cho tất cả các ô trong Chuỗi Pandas hoặc DataFrame một cách hiệu quả như thế nào. Tất nhiên, chức năng thực tế được áp dụng là một sự đơn giản hóa. Một mô hình thực tế hơn cho một bài tập định giá lớn hơn sẽ có một mô hình thuế riêng để tính toán các khoản thuế tiền mặt thực tế phải trả dựa trên một số yếu tố cụ thể của công ty.
Sau khi đạt được dòng tiền dự kiến, bây giờ chúng ta có thể tính toán một giá trị đầu cuối đơn giản và chiết khấu tất cả các dòng tiền trở lại hiện tại để có được kết quả DCF. Đoạn mã sau giới thiệu tính năng lập chỉ mục và phân loại, cho phép chúng tôi truy cập một hoặc nhiều phần tử trong cấu trúc dữ liệu, chẳng hạn như đối tượng Chuỗi Pandas.
Chúng tôi truy cập các phần tử bằng cách viết dấu ngoặc vuông ngay sau tên của cấu trúc. Lập chỉ mục đơn giản truy cập các phần tử theo vị trí của chúng, bắt đầu bằng 0, nghĩa là free_cash_flow[1]
sẽ cung cấp cho chúng tôi yếu tố thứ hai. [-1]
là cách viết tắt để truy cập phần tử cuối cùng (dòng tiền của năm trước được sử dụng để tính giá trị đầu cuối) và việc sử dụng dấu hai chấm cho chúng ta một phần, có nghĩa là [1:]
cung cấp cho chúng tôi tất cả các yếu tố ngoại trừ yếu tố đầu tiên, vì chúng tôi không muốn đưa vào năm lịch sử 2018A
trong định giá DCF của chúng tôi.
cost_of_capital = 0.12
terminal_growth = 0.02
terminal_value = ((free_cash_flow[-1] * (1 + terminal_growth)) /
(cost_of_capital - terminal_growth))
discount_factors = [(1 / (1 + cost_of_capital)) ** i for i in range (1,6)]
dcf_value = (sum(free_cash_flow[1:] * discount_factors) +
terminal_value * discount_factors[-1])
dcf_value
Điều đó kết thúc phần đầu tiên của nguyên mẫu của chúng tôi - bây giờ chúng tôi có một mô hình DCF đang hoạt động, mặc dù là một mô hình rất thô sơ, bằng Python.
Trước khi chuyển sang mô phỏng Monte Carlo thực tế, đây có thể là thời điểm tốt để đề cập đến khả năng xuất có sẵn trong gói Pandas. Nếu bạn có đối tượng Pandas DataFrame, bạn có thể ghi đối tượng đó vào tệp Excel bằng một dòng bằng cách sử dụng to_excel
phương pháp. Cũng có chức năng tương tự để xuất sang hơn một chục định dạng và điểm đến khác.
output = pd.DataFrame([sales, ebit, free_cash_flow],
index=['Sales', 'EBIT', 'Free Cash Flow']).round(1)
output.to_excel('Python DCF Model Output.xlsx')
output
Bây giờ chúng tôi đã sẵn sàng để giải quyết thách thức tiếp theo:thay thế một số đầu vào ước tính điểm bằng phân phối xác suất. Mặc dù các bước cho đến thời điểm này có vẻ hơi rườm rà so với việc xây dựng cùng một mô hình trong Excel, nhưng vài dòng tiếp theo sẽ cho bạn cái nhìn sơ lược về sức mạnh của Python.
Bước đầu tiên của chúng tôi là quyết định số lần lặp lại mà chúng tôi muốn chạy trong mô phỏng. Sử dụng 1.000 làm điểm bắt đầu tạo ra sự cân bằng giữa việc nhận đủ điểm dữ liệu để có được các biểu đồ đầu ra hợp lý, so với việc kết thúc mô phỏng trong một khung thời gian hợp lý. Tiếp theo, chúng tôi tạo các bản phân phối thực tế. Để đơn giản, tôi đã tạo ba bản phân phối bình thường ở đây, nhưng thư viện NumPy có một số lượng lớn các bản phân phối để lựa chọn và cũng có những nơi khác để xem, bao gồm cả thư viện chuẩn Python. Sau khi quyết định sử dụng phân phối nào, chúng ta cần chỉ định các tham số cần thiết để mô tả hình dạng của chúng, chẳng hạn như trung bình và độ lệch chuẩn, và số lượng kết quả mong muốn.
iterations = 1000
sales_growth_dist = np.random.normal(loc=0.1, scale=0.01, size=iterations)
ebitda_margin_dist = np.random.normal(loc=0.14, scale=0.02, size=iterations)
nwc_percent_dist = np.random.normal(loc=0.24, scale=0.01, size=iterations)
plt.hist(sales_growth_dist, bins=20)
plt.show()
Ở đây, bạn có thể tranh luận rằng EBITDA không nên là một biến ngẫu nhiên riêng biệt độc lập với doanh số bán hàng mà thay vào đó tương quan với doanh số bán hàng ở một mức độ nào đó. Tôi đồng ý với điều này và nói thêm rằng nó phải được thúc đẩy bởi sự hiểu biết vững chắc về động lực của cấu trúc chi phí (chi phí biến đổi, bán biến đổi và cố định) và các yếu tố thúc đẩy chi phí chính (một số trong số đó có thể có phân phối xác suất riêng, chẳng hạn như giá hàng hóa đầu vào chẳng hạn), nhưng tôi để những phức tạp đó sang một bên ở đây vì lợi ích của không gian và sự rõ ràng.
Bạn càng có ít dữ liệu để cung cấp thông tin cho lựa chọn phân phối và tham số của mình, bạn càng phải dựa vào kết quả của các dòng công việc thẩm định khác nhau, kết hợp với kinh nghiệm, để hình thành quan điểm đồng thuận về phạm vi các tình huống có thể xảy ra. Trong ví dụ này, với dự báo dòng tiền, sẽ có một thành phần chủ quan lớn, có nghĩa là việc hình dung các phân phối xác suất trở nên quan trọng. Ở đây, chúng ta có thể hình dung cơ bản, cho thấy sự phân bổ tăng trưởng doanh số, chỉ với hai dòng mã ngắn. Bằng cách này, chúng tôi có thể nhanh chóng xem bất kỳ phân phối nào cho nhãn cầu phản ánh tốt nhất quan điểm chung của nhóm.
Bây giờ chúng ta có tất cả các khối xây dựng mà chúng ta cần để chạy mô phỏng, nhưng chúng không ở định dạng thuận tiện cho việc chạy mô phỏng. Đây là cùng một đoạn mã mà chúng tôi đã làm việc cho đến nay nhưng tất cả được tập hợp trong một ô và được sắp xếp lại thành một hàm để thuận tiện:
def run_mcs():
# Create probability distributions
sales_growth_dist = np.random.normal(loc=0.1, scale=0.01, size=iterations)
ebitda_margin_dist = np.random.normal(loc=0.14, scale=0.02, size=iterations)
nwc_percent_dist = np.random.normal(loc=0.24, scale=0.01, size=iterations)
# Calculate DCF value for each set of random inputs
output_distribution = []
for i in range(iterations):
for year in range(1, 6):
sales[year] = sales[year - 1] * (1 + sales_growth_dist[0])
ebitda = sales * ebitda_margin_dist[i]
depreciation = (sales * depr_percent)
ebit = ebitda - depreciation
nwc = sales * nwc_percent_dist[i]
change_in_nwc = nwc.shift(1) - nwc
capex = -(sales * capex_percent)
tax_payment = -ebit * tax_rate
tax_payment = tax_payment.apply(lambda x: min(x, 0))
free_cash_flow = ebit + depreciation + tax_payment + capex + change_in_nwc
# DCF valuation
terminal_value = (free_cash_flow[-1] * 1.02) / (cost_of_capital - 0.02)
free_cash_flow[-1] += terminal_value
discount_factors = [(1 / (1 + cost_of_capital)) ** i for i in range (1,6)]
dcf_value = sum(free_cash_flow[1:] * discount_factors )
output_distribution.append(dcf_value)
return output_distribution
Bây giờ chúng ta có thể chạy toàn bộ mô phỏng và vẽ biểu đồ phân phối đầu ra, sẽ là giá trị dòng tiền chiết khấu của công ty này trong mỗi 1.000 lần lặp, với đoạn mã sau. %time
lệnh không phải là mã Python mà là một tốc ký sổ tay đo thời gian để chạy một thứ gì đó (thay vào đó bạn có thể sử dụng hàm Python từ thư viện chuẩn). Nó phụ thuộc vào máy tính bạn chạy, nhưng phiên bản này cần 1-2 giây để chạy 1.000 lần lặp và hình dung kết quả.
%time plt.hist(run_mcs(), bins=20, color='r')
plt.show()
Sự nghi ngờ tiềm ẩn rằng một cái gì đó có thể được đơn giản hóa là nguồn thách thức bổ ích phong phú nhất trên thế giới. - Edsger Dijkstra
Tái cấu trúc đề cập đến quá trình viết lại mã hiện có để cải thiện cấu trúc mà không thay đổi chức năng của nó và nó có thể là một trong những yếu tố thú vị và bổ ích nhất của mã hóa. Có thể có một số lý do để làm điều này. Nó có thể là:
Để cho thấy một bước trong quy trình đó có thể trông như thế nào, tôi đã dọn dẹp nguyên mẫu mà chúng tôi vừa xem qua bằng cách thu thập tất cả các biến ban đầu ở một nơi, thay vì nằm rải rác như trong tập lệnh nguyên mẫu và tối ưu hóa tốc độ thực thi của nó thông qua một quy trình được gọi là vectơ hóa .
Sử dụng mảng NumPy cho phép bạn thể hiện nhiều loại tác vụ xử lý dữ liệu dưới dạng các biểu thức mảng ngắn gọn có thể yêu cầu viết các vòng lặp. Thực hành thay thế các vòng lặp rõ ràng bằng các biểu thức mảng thường được gọi là vectơ hóa. Wes McKinney
Giờ đây, nó trông gọn gàng và dễ hiểu hơn:
# Key inputs from DCF model
years = 5
starting_sales = 31.0
capex_percent = depr_percent = 0.032
sales_growth = 0.1
ebitda_margin = 0.14
nwc_percent = 0.24
tax_rate = 0.25
# DCF assumptions
r = 0.12
g = 0.02
# For MCS model
iterations = 1000
sales_std_dev = 0.01
ebitda_std_dev = 0.02
nwc_std_dev = 0.01
def run_mcs():
# Generate probability distributions
sales_growth_dist = np.random.normal(loc=sales_growth,
scale=sales_std_dev,
size=(years, iterations))
ebitda_margin_dist = np.random.normal(loc=ebitda_margin,
scale=ebitda_std_dev,
size=(years, iterations))
nwc_percent_dist = np.random.normal(loc=nwc_percent,
scale=nwc_std_dev,
size=(years, iterations))
# Calculate free cash flow
sales_growth_dist += 1
for i in range(1, len(sales_growth_dist)):
sales_growth_dist[i] *= sales_growth_dist[i-1]
sales = sales_growth_dist * starting_sales
ebitda = sales * ebitda_margin_dist
ebit = ebitda - (sales * depr_percent)
tax = -(ebit * tax_rate)
np.clip(tax, a_min=None, a_max=0)
nwc = nwc_percent_dist * sales
starting_nwc = starting_sales * nwc_percent
prev_year_nwc = np.roll(nwc, 1, axis=0)
prev_year_nwc[0] = starting_nwc
delta_nwc = prev_year_nwc - nwc
capex = -(sales * capex_percent)
free_cash_flow = ebitda + tax + delta_nwc + capex
# Discount cash flows to get DCF value
terminal_value = free_cash_flow[-1] * (1 + g) / (r - g)
discount_rates = [(1 / (1 + r)) ** i for i in range (1,6)]
dcf_value = sum((free_cash_flow.T * discount_rates).T)
dcf_value += terminal_value * discount_rates[-1]
return dcf_value
The main difference you will notice between this version and the previous one is the absence of the for i in range(iterations)
loop. Using NumPy’s array operation, this version runs in 18 milliseconds compared to the 1.35 seconds for the prototype version - roughly 75x faster.
%time plt.hist(run_mcs(), bins=20, density=True, color="r")
plt.show()
I’m sure that further optimization is possible, since I put together both the prototype and refined version in a short time solely for the purpose of this tutorial.
This tutorial showed some of the powerful features of Python, and if you were to develop this further the opportunities are almost endless. You could for example:
I haven’t even touched upon what you could also do with the various web, data science, and machine learning applications that have contributed to Python’s success.
This article gave an introduction to the Python programming language, listed some of the reasons why it has become so popular in finance and showed how to build a small Python script. In a step-by-step tutorial, I walked through how Python can be used for iterative prototyping, interactive financial analysis, and for application code for valuation models, algorithmic trading programs and more.
For me, at the end of the day, the killer feature of Python technology is that it is simply fun to work with! If you enjoy problem-solving, building things and making workflows more efficient, then I encourage you to try it out. I would love to hear what you have done with it or would like to do with it.