2025-05-29 07:13:14
ในบทความก่อนหน้านี้ในซีรีส์นี้ เราได้พูดคุยเกี่ยวกับลำดับชั้นของคลาสสินทรัพย์ที่เป็นพื้นฐานของสินทรัพย์ที่จะถูกซื้อขายภายในระบบจำลองการทดสอบย้อนหลังของ QSTrader
ในบทความนี้เราจะเริ่มการตรวจสอบคลาสต่างๆ ที่ประกอบขึ้นเป็นส่วนประกอบของการจำลองโบรกเกอร์ในระบบ แง่มุมนี้ของ QSTrader จำลองนายหน้า ซึ่งมีหน้าที่ติดตามการบัญชีทั้งหมดที่เกี่ยวข้องกับการทำธุรกรรมในสินทรัพย์ นอกจากนี้ยังรับผิดชอบในการติดตามการกระทำของบริษัทที่มีผลกระทบต่อการถือครองอย่างมีนัยสำคัญ เช่น การจ่ายเงินสดหรือเงินปันผลจากหุ้นสามัญ
ข้อดีอีกประการของการห่อหุ้มตรรกะนี้ไว้ในคลาสคือ หากอินเทอร์เฟซถูกกำหนดไว้อย่างเหมาะสม ก็สามารถเปลี่ยนส่วนประกอบการซื้อขายจำลองเป็นส่วนประกอบการซื้อขายจริงได้ โดยไม่จำเป็นต้องแก้ไขตรรกะการซื้อขายเชิงปริมาณที่เหลืออยู่ ดังนั้น การห่อหุ้มอัลกอริธึมการซื้อขายเชิงปริมาณจะไม่ขึ้นอยู่กับว่าบร็อกเกอร์จะเป็นการจำลองหรือการซื้อขายจริง
โบรกเกอร์เป็นส่วนประกอบที่ซับซ้อนและพึ่งพาส่วนประกอบย่อยต่างๆ เพื่อทำงาน ได้แก่ ลำดับชั้นของคลาส FeeModel ส่วนประกอบพอร์ตโฟลิโอ และส่วนประกอบการทำธุรกรรม ในบทความนี้เราจะมุ่งเน้นไปที่คลาส FeeModel
หนึ่งในแง่มุมที่สำคัญที่สุดของการจำลองกลยุทธ์การซื้อขายแบบเป็นระบบคือการสร้างแบบจำลองและติดตามต้นทุนการทำธุรกรรม ต้นทุนเหล่านี้สามารถมีหลายรูปแบบ รวมถึงค่าคอมมิชชั่นนายหน้าและภาษี รวมถึงต้นทุนการซื้อขายทางอ้อม เช่น การลื่นไถลและผลกระทบจากตลาด การจำลองการลื่นไถลและผลกระทบของตลาดเป็นหัวข้อที่ลึกซึ้งและจะเป็นหัวข้อของบทความในอนาคต สำหรับบทความนี้ เราจะมาดูค่าคอมมิชชันของโบรกเกอร์และภาษี ซึ่งทั้งสองอย่างนี้สามารถสร้างแบบจำลองได้โดยใช้ลำดับชั้นคลาส FeeModel
FeeModel ถูกออกแบบมาเพื่อสรุปรายละเอียดเฉพาะของโครงสร้างต้นทุนของโบรกเกอร์ที่ใช้ในการซื้อขาย สิ่งเหล่านี้อาจมีความซับซ้อนค่อนข้างมากขึ้นอยู่กับภูมิภาคการซื้อขาย ประเภทสินทรัพย์ ปริมาณการซื้อขาย และช่วงเวลาที่ผ่านมาเมื่อการซื้อขายถูกจำลอง
นอกจากค่าธรรมเนียมของโบรกเกอร์เองแล้ว ยังมีภาษีเฉพาะภูมิภาคที่ต้องชำระด้วย ตัวอย่างที่สำคัญคือภาษีแสตมป์ของสหราชอาณาจักรสำหรับการทำธุรกรรมหุ้น
ในรูปแบบปัจจุบัน QSTrader รองรับโมเดลค่าธรรมเนียมที่เรียบง่ายสองแบบ แรกคือ ZeroFeeModel ซึ่งไม่เรียกเก็บค่าคอมมิชชั่นหรือภาษีใดๆ กับการทำธุรกรรมใดๆ สิ่งนี้มีประโยชน์สำหรับการสร้างการจำลองพื้นฐานที่สามารถเปรียบเทียบกับโมเดลค่าธรรมเนียมที่สมจริงกว่าอื่นๆ ได้ อันที่สองคือ PercentFeeModel ซึ่งใช้ค่าคอมมิชชั่นเป็นเปอร์เซ็นต์และ/หรือภาษีเป็นเปอร์เซ็นต์กับจำนวนการซื้อขายที่ให้มา (เรียกว่า 'การพิจารณา') เราจะอธิบายทั้งหมดนี้ทีละอย่าง
FeeModel เป็นคลาสฐานนามธรรมที่คลาสย่อยทั้งหมดสืบทอดแบบจำลองค่าธรรมเนียมจากมัน มันให้การกำหนดวิธีการเชิงนามธรรมสามอย่าง: _calc_commission, _calc_tax และ calc_total_cost เครื่องหมายขีดล่างที่นำหน้าสองวิธีแรกบ่งชี้ว่าวิธีเหล่านี้เป็นวิธีแบบกึ่งส่วนตัวที่มีฟังก์ชันการทำงานที่จำเป็นสำหรับคลาสเอง วิธีสุดท้ายคือวิธีการเชื่อมต่อสาธารณะเทียมและใช้ในการคำนวณต้นทุนการทำธุรกรรมของนายหน้าทั้งหมดเมื่อใช้กับการพิจารณาที่ซื้อขาย
โปรดทราบว่าภาษา Python ไม่มีแนวคิดของเมธอดส่วนตัวหรือสาธารณะ แตกต่างจาก C++ หรือ Java แทนที่จะใช้การขีดล่างเดียวที่นำหน้าวิธีการเพื่อบอกให้ลูกค้ารายอื่นของโมดูลทราบว่าวิธีการใดควรเรียกใช้เป็นอินเตอร์เฟซ (ไม่มีขีดล่าง) ในขณะที่วิธีการใดเป็นวิธีการเฉพาะของการใช้งาน (นำหน้าด้วยขีดล่าง)
วิธีการ _calc_commission และ _calc_tax ถูกแยกออกเพื่อให้สามารถคำนวณตรรกะสำหรับแต่ละประเภทของค่าใช้จ่ายได้แยกกัน กรณีนี้จะเป็นเช่นนี้ เช่น เมื่อมีการใช้ค่าคอมมิชชั่นแบบ 'sliding scale' แต่ภาษีเองอาจเป็นเปอร์เซ็นต์คงที่ที่เฉพาะเจาะจงโดยไม่คำนึงถึงจำนวนการพิจารณาที่ซื้อขาย
วิธี calc_total_cost มีอาร์กิวเมนต์บังคับสามตัวและอาร์กิวเมนต์คีย์เวิร์ดตัวเลือกหนึ่งตัว สามอย่างแรกประกอบด้วยสินทรัพย์ จำนวน และการพิจารณา สินทรัพย์เป็นสิ่งจำเป็นเนื่องจากสินทรัพย์แต่ละประเภทจะมีค่าคอมมิชชั่นที่แตกต่างกัน พารามิเตอร์การพิจารณาคือราคาของสินทรัพย์คูณด้วยปริมาณ และให้แนวคิดเกี่ยวกับ 'จำนวนที่ซื้อขาย' ในสกุลเงิน โดยไม่คำนึงถึงประเภทของสินทรัพย์
แม้ว่ามันอาจดูเหมือนว่าต้องการเพียงพารามิเตอร์ของสินทรัพย์และการพิจารณาเท่านั้น (เนื่องจากค่าคอมมิชชั่นมักจะคำนวณจากจำนวนที่ซื้อขาย) แต่มีโบรกเกอร์บางแห่งที่คำนวณค่าคอมมิชชั่นจากปริมาณของสินทรัพย์ที่ถูกซื้อขาย (นั่นคือ ไม่จำเป็นต้องเป็นราคา) แทนที่จะเป็น "มูลค่าเป็นดอลลาร์" ด้วยเหตุนี้จึงได้รวมไว้ในดีไซน์ของ QSTrader เพื่อรองรับสถานการณ์ประเภทนี้
พารามิเตอร์สุดท้ายคือการอ้างอิงถึงตัวแทนจำหน่าย (ทั้งแบบจำลองหรือแบบจริง) สิ่งนี้จำเป็นเพื่อที่จะได้รับข้อมูลเพิ่มเติมที่อาจเกี่ยวข้องกับการคำนวณค่าคอมมิชชั่น ตัวอย่างหนึ่งอาจเป็นการหาวันที่แท้จริงของการซื้อขาย เนื่องจากโบรกเกอร์เปลี่ยนโครงสร้างค่าคอมมิชชั่นของพวกเขาตลอดเวลา และเพื่อที่จะสร้างแบบจำลองนี้อย่างสมจริงตลอดเวลา จำเป็นต้องทราบวันที่ซื้อขายที่แท้จริง
โค้ดสำหรับ FeeModel มีดังนี้ มันเป็นการนำเสนอคลาสฐานนามธรรมที่ค่อนข้างตรงไปตรงมา:
from abc import ABCMeta, abstractmethod class FeeModel(object): """ Abstract class to handle the calculation of brokerage commission, fees and taxes. """ __metaclass__ = ABCMeta @abstractmethod def _calc_commission(self, asset, quantity, consideration, broker=None): raise NotImplementedError( "Should implement _calc_commission()" ) @abstractmethod def _calc_tax(self, asset, quantity, consideration, broker=None): raise NotImplementedError( "Should implement _calc_tax()" ) @abstractmethod def calc_total_cost(self, asset, quantity, consideration, broker=None): raise NotImplementedError( "Should implement calc_total_cost()" )
คลาสแรกที่ใช้ประยุกต์อินเตอร์เฟซนามธรรมนี้คือคลาสย่อยที่สืบทอดจาก ZeroFeeModel มันเป็นคลาสที่เรียบง่ายมากที่คืนค่า 0.0 สำหรับทั้ง _calc_tax และ _calc_commission ค่าทั้งสองนี้จะถูกนำมาบวกใน calc_total_cost เพื่อให้ได้ 0.0 สำหรับต้นทุนการซื้อขายรวม
ทำไมถึงต้องใช้คลาสแบบนี้ในการจำลองจริง? เหตุผลหลักในการรวมเข้าคือเพื่อให้สามารถเปรียบเทียบระหว่างโมเดลค่าธรรมเนียมต่างๆ ภายในการจำลองการทดสอบย้อนหลัง การใช้ ZeroFeeModel ช่วยให้นักวิจัยเชิงปริมาณสามารถเห็นผลของการทดสอบย้อนหลังโดยไม่มีค่าใช้จ่ายและเปรียบเทียบกับโมเดลต่างๆ ของค่าคอมมิชชั่นนายหน้าและภาษี ดังนั้นจึงเป็นไปได้ที่จะเห็นว่าวิธีการยังคงมีกำไรแม้จะมีค่าธรรมเนียมการทำธุรกรรมอยู่บ้าง
รหัสสำหรับ ZeroFeeModel มีดังนี้ ส่วนใหญ่ของบรรทัดโค้ดสำหรับโมเดลนี้เป็น docstrings การนำไปใช้จริงมีน้อยมาก:
from qstrader.broker.fee_model.fee_model import FeeModel class ZeroFeeModel(FeeModel): """ A FeeModel subclass that produces no commission, fees or taxes. This is the default fee model for simulated brokerages within QSTrader. """ def _calc_commission(self, asset, quantity, consideration, broker=None): """ Returns zero commission. Parameters ---------- asset : `str` The asset symbol string. quantity : `int` The quantity of assets (needed for InteractiveBrokers style calculations). consideration : `float` Price times quantity of the order. broker : `Broker`, optional An optional Broker reference. Returns ------- `float` The zero-cost commission. """ return 0.0 def _calc_tax(self, asset, quantity, consideration, broker=None): """ Returns zero tax. Parameters ---------- asset : `str` The asset symbol string. quantity : `int` The quantity of assets (needed for InteractiveBrokers style calculations). consideration : `float` Price times quantity of the order. broker : `Broker`, optional An optional Broker reference. Returns ------- `float` The zero-cost tax. """ return 0.0 def calc_total_cost(self, asset, quantity, consideration, broker=None): """ Calculate the total of any commission and/or tax for the trade of size 'consideration'. Parameters ---------- asset : `str` The asset symbol string. quantity : `int` The quantity of assets (needed for InteractiveBrokers style calculations). consideration : `float` Price times quantity of the order. broker : `Broker`, optional An optional Broker reference. Returns ------- `float` The zero-cost total commission and tax. """ commission = self._calc_commission(asset, quantity, consideration, broker) tax = self._calc_tax(asset, quantity, consideration, broker) return commission + tax
แบบจำลองที่สมจริงยิ่งขึ้นของต้นทุนการทำธุรกรรมถูกจัดเตรียมโดยคลาส PercentFeeModel คลาสนี้มีวิธีการเริ่มต้น __init__ ที่มีพารามิเตอร์สองตัว อย่างแรกคือ commission_pct ซึ่งเป็นค่าคอมมิชชั่นนายหน้าร้อยละคงที่ที่จะนำไปใช้กับการพิจารณา อย่างที่สองคือ tax_pct ซึ่งเป็นอัตราภาษีคงที่ที่ใช้กับการพิจารณา ค่าทั้งสองนี้ถูกกำหนดในช่วง [0.0, 1.0] นั่นคือ 1.0 เท่ากับ 100%
ทั้งสองวิธีใช้เปอร์เซ็นต์นี้กับมูลค่าที่แท้จริงของการพิจารณา สิ่งนี้หลีกเลี่ยงค่าคอมมิชชั่นติดลบเมื่อขายสินทรัพย์! ตัวอย่างเช่น การคำนวณค่าคอมมิชชันของนายหน้าดูเหมือนว่า: return self.commission_pct * abs(consideration) การดำเนินการสำหรับวิธีการเก็บภาษีเกือบจะเหมือนกัน
รหัสสำหรับ PercentFeeModel มีดังนี้ เช่นเดียวกับ ZeroFeeModel ส่วนใหญ่ของโค้ดสำหรับโมเดลนี้เป็น docstrings การนำไปใช้จริงมีน้อยมาก:
from qstrader.broker.fee_model.fee_model import FeeModel class PercentFeeModel(FeeModel): """ A FeeModel subclass that produces a percentage cost for tax and commission. Parameters ---------- commission_pct : `float`, optional The percentage commission applied to the consideration. 0-100% is in the range [0.0, 1.0]. Hence, e.g. 0.1% is 0.001 tax_pct : `float`, optional The percentage tax applied to the consideration. 0-100% is in the range [0.0, 1.0]. Hence, e.g. 0.1% is 0.001 """ def __init__(self, commission_pct=0.0, tax_pct=0.0): super().__init__() self.commission_pct = commission_pct self.tax_pct = tax_pct def _calc_commission(self, asset, quantity, consideration, broker=None): """ Returns the percentage commission from the consideration. Parameters ---------- asset : `str` The asset symbol string. quantity : `int` The quantity of assets (needed for InteractiveBrokers style calculations). consideration : `float` Price times quantity of the order. broker : `Broker`, optional An optional Broker reference. Returns ------- `float` The percentage commission. """ return self.commission_pct * abs(consideration) def _calc_tax(self, asset, quantity, consideration, broker=None): """ Returns the percentage tax from the consideration. Parameters ---------- asset : `str` The asset symbol string. quantity : `int` The quantity of assets (needed for InteractiveBrokers style calculations). consideration : `float` Price times quantity of the order. broker : `Broker`, optional An optional Broker reference. Returns ------- `float` The percentage tax. """ return self.tax_pct * abs(consideration) def calc_total_cost(self, asset, quantity, consideration, broker=None): """ Calculate the total of any commission and/or tax for the trade of size 'consideration'. Parameters ---------- asset : `str` The asset symbol string. quantity : `int` The quantity of assets (needed for InteractiveBrokers style calculations). consideration : `float` Price times quantity of the order. broker : `Broker`, optional An optional Broker reference. Returns ------- `float` The total commission and tax. """ commission = self._calc_commission(asset, quantity, consideration, broker) tax = self._calc_tax(asset, quantity, consideration, broker) return commission + tax
โปรดทราบว่าชั้นเรียนนี้ที่นำมาใช้ไม่ได้อนุญาตให้มีเปอร์เซ็นต์แบบ 'sliding scale' ตามขนาดของการพิจารณา ในโบรกเกอร์ส่วนใหญ่ในโลกแห่งความเป็นจริง เปอร์เซ็นต์ที่แตกต่างกันจะถูกนำมาใช้เมื่อขนาดของการพิจารณาเพิ่มขึ้น มาตราส่วนเลื่อนนี้ก็อาจจะแตกต่างกันไปตามประเภทสินทรัพย์และภูมิภาคทางภูมิศาสตร์ด้วย
ตรรกะนี้มักจะเฉพาะเจาะจงกับโบรกเกอร์ที่เกี่ยวข้อง และดังนั้นการพยายามสร้างโครงสร้างค่าคอมมิชชันของโบรกเกอร์ทุกรูปแบบจะเป็นงานที่ยาก อย่างไรก็ตาม ลอจิกของคลาสนั้นทั่วไปพอที่จะรองรับโครงสร้างค่าคอมมิชชั่นของโบรกเกอร์ที่หลากหลาย บทความในอนาคตจะครอบคลุมการนำค่าใช้จ่ายในการซื้อขายที่สมจริงมากขึ้นมาใช้โดยใช้ลำดับชั้นของคลาสเดียวกันกับที่กล่าวถึงข้างต้น
อ้างอิง :QSTrader Fee Model Class Hierarchy
จาก https://www.quantstart.com/articles/qstrader-fee-model-class-hierarchy/
2025-01-10 10:12:01
2024-06-10 03:19:31
2024-05-31 03:06:49
2024-05-28 03:09:25
บทความที่น่าสนใจอื่นๆยังมีอีกมากลองเลืือกดูจากด้านล่างนี้ได้นะครับ
2023-11-22 02:16:10
2024-01-04 04:58:24
2023-09-07 10:30:37
2023-10-09 03:59:28
2025-01-25 06:16:24
2024-02-26 10:41:34
2024-10-18 01:36:48
2024-10-18 03:09:39
2024-12-17 04:04:33