如何第一次量化交易就賠錢

閱讀時間約 22 分鐘
  • 文內如有投資理財相關經驗、知識、資訊等內容,皆為創作者個人分享行為。
  • 有價證券、指數與衍生性商品之數據資料,僅供輔助說明之用,不代表創作者投資決策之推介及建議。
  • 閱讀同時,請審慎思考自身條件及自我決策,並應有為決策負責之事前認知。
  • 方格子希望您能從這些分享內容汲取投資養份,養成獨立思考的能力、判斷、行動,成就最適合您的投資理財模式。
如何第一次量化交易投資就賠錢
身為會寫一點程式碼的工程師,量化交易投資無疑是最具吸引力的投資方式。試想只要寫個小程式定期去追蹤股市大盤交易指數,然後自動下單買入賣出,就會賺進源源不絕的財富,光用想的口水都快流下來了。
坐而言不如起而行。這邊有幾個小問題需要克服:
  1. 即時報價
  2. 下單買賣
  3. 交易策略
市面上有許多現成軟體都可以做到上述功能,例如TradingView、MultiCharts或是XQ,但是都需要繳交不少的年費。還好有些券商願意提供報價與下單的API,例如群益與永豐,只要開戶成功,就可以自行DIY寫程式免費去使用這些API達成前兩項功能。筆者自己是採用群益API,主要是因為API文件解說詳細,而且可以在網路上找到不少範例,開發相對較為快速。
接下來重點就是交易策略了。依據筆者個人初淺的調查研究,交易策略可以分成順勢交易與逆勢交易。順勢交易主要判斷方式就是找出一個震盪區間,一旦往上或是往下突破這個震盪區間,就立刻開始買多或是賣空。逆勢交易就是傳說中的摸頭猜底,網路上許多神人可以透過各種波浪理論準確預言價格高低點,可惜大多採用形態學劃線的方式,筆者功力淺薄,還想不出方式將形態學改寫成為程式邏輯。所以本文會採用順勢交易策略,透過一些指標計算當作範例。交易週期也是交易策略中重要的一環,既然有了電腦無時無刻幫忙監控,當然可以選擇較短的交易週期,筆者瀏覽許多網路文章之後,就先選定台指期5分K當作目標。目前券商提供的API都有C#以及Python版本,因為筆者本身對C語言比較熟悉,所以就選了C#當作實作語言。
程式框架很簡單,分成兩個主要的部份: 1. 讀取券商即時報價tick,並立刻轉換成為1分K或是5分K的資料,以及 2. 每5分鐘讀取一次5分K的資料,帶入指標計算,判斷目前是否為合適的買賣點,如果是的話,執行下單的動作。在開發的過程中,筆者自行摸索許多網路資源,趁著還有些力氣將之記錄下來。
  • 讀取券商即時報價,群益金融網 - 證券API提供註冊個股報價功能,並透過Notify之類的回呼函式取得即時報價。例如筆者想取得的個股報價為台指期,因此註冊的個股代號為「TX00」,若是小台指則為「MTX00」,其中00表示當月報價,如果有指定特別月份報價,則修改00為該月份數字。由於某些時候瞬間的台指期成交筆數非常多,所以儲存資料時建議採用ConcurrentQueue的方式,否則資料很容易就遺失。
  • 指標計算部分,筆者藉由Stock Indicators for .NET函式庫幫忙,以節省自行開發的時間。Skender的指標函式庫涵蓋了許多常見指標,並且持續在github提供更新,對於研究交易指標的原理,不失為良好的研究來源。
  • 即時Tick資料轉OHLC的K棒資料格式,筆者參考[利用 LINQ 實現期指Tick檔彙整為K棒]再稍微改寫符合自己的需求如下,這段 LINQ程式寫得非常高明,筆者感悟一陣子才了解。
        private IEnumerable<OHLCBar> generate_OHLCBar(IEnumerable<Tick> ticks, long barSizeInTicks)
        {
            TimeSpan natural_time = new TimeSpan(8, 45, 0);
            var bars = from tick in ticks
                       let barIndexForDay = Math.Floor(tick.Timestamp.TimeOfDay.Subtract(natural_time).TotalSeconds / barSizeInTicks)
                       let barBeginDateTime = tick.Timestamp.Date.Add(natural_time).AddSeconds(barIndexForDay * barSizeInTicks)
                       let barEndDateTime = tick.Timestamp.Date.Add(natural_time).AddSeconds((barIndexForDay + 1) * barSizeInTicks)
                       group tick by new { barBeginDateTime, barEndDateTime, tick.Symbol } into tickGroup
                       orderby tickGroup.Key.barBeginDateTime
                       let orderedPrices = tickGroup.OrderBy(t => t.Timestamp).Select(t => t.Price)
                       select new OHLCBar()
                       {
                           Symbol = tickGroup.Key.Symbol,
                           OPEN = orderedPrices.First(),
                           CLOSE = orderedPrices.Last(),
                           HIGH = orderedPrices.Max(),
                           LOW = orderedPrices.Min(),
                           VOLUME = Convert.ToUInt32(tickGroup.Sum(t => t.Volume)),
                           BeginTime = tickGroup.Key.barBeginDateTime,
                           EndTime = tickGroup.Key.barEndDateTime,
                           Interval = new TimeSpan(0, 0, (int)barSizeInTicks)
                       };
            return bars;
        }
  • 台股交易日期則需要至臺灣證券交易所的OpenAPI查詢。筆者拼湊了個簡單的抓取程式如下。但是必須注意的是臺灣證券交易所把春節年假前的交易日期混在停止交易的日期中,所以就算抓下來之後,還要自行修改內容才能直接當作IsHoliday使用。希望有人能反映給臺灣證券交易所,這種資料是給電腦看的,不是給人看的,格式不要亂塞一通。
        private async Task GetHolidayInfo(string path)
        {
            string req = "https://openapi.twse.com.tw/v1/holidaySchedule/holidaySchedule";
            string csv = await GetHttpData(req);
            File.WriteAllText(path, csv);
        }
        private async Task<string> GetHttpData(string weblink)
        {
            HttpClientHandler handler = new HttpClientHandler();
            handler.UseDefaultCredentials = true;
            HttpClient client = new HttpClient(handler);
            try
            {
                HttpResponseMessage response = await client.GetAsync(weblink);
                response.EnsureSuccessStatusCode();
                string responseBody = await response.Content.ReadAsStringAsync();
                string csv = jsonToCSV(responseBody, ",");
                return csv;
            }
            catch (HttpRequestException e)
            {
                Debug.WriteLine("Exception Caught! Message :{0} ", e.Message);
                return null;
            }
        }
        private static DataTable jsonStringToTable(string jsonContent)
        {
            DataTable dt = JsonConvert.DeserializeObject<DataTable>(jsonContent);
            return dt;
        }
        private static string jsonToCSV(string jsonContent, string delimiter)
        {
            StringWriter csvString = new StringWriter();
            var configuration = new CsvConfiguration(CultureInfo.InvariantCulture)
            {
                Delimiter = delimiter,
                MissingFieldFound = null
            };
            using (var csv = new CsvWriter(csvString, configuration))
            {                
                using (var dt = jsonStringToTable(jsonContent))
                {
                    foreach (DataColumn column in dt.Columns)
                    {
                        csv.WriteField(column.ColumnName);
                    }
                    csv.NextRecord();
                    foreach (DataRow row in dt.Rows)
                    {
                        for (var i = 0; i < dt.Columns.Count; i++)
                        {
                            csv.WriteField(row[i]);
                        }
                        csv.NextRecord();
                    }
                }
            }
            return csvString.ToString();
        }
  • 月結算的交易時間與平常日不同,月結算當日比較早收盤,同時還有轉倉的問題,所以筆者也拼湊判斷月結算的函式如下:
        public static bool IsMonthExpDate(this DateTime d)
        {            
            if (GetMonthExpDate(d).Date == d.Date)
            {
                return true;
            }
            return false;
        }
        private static DateTime GetMonthExpDate(DateTime date) // 取得月份到期日(當月第3個星期三)
        {
            // 本月第一天
            DateTime firstDay = new DateTime(date.Year, date.Month, 1, 14, 0, 0);
            // 找到第一個星期三
            while (firstDay.DayOfWeek != DayOfWeek.Wednesday)
            {
                firstDay = firstDay.AddDays(1);
            }
            firstDay = firstDay.AddDays(14);
            // 長假順延
            while (IsHoliday(firstDay)) 
            {
                firstDay = firstDay.AddDays(1);
            }
            return firstDay;
        }
        public static string GetFutureYM(DateTime date) // 取得該日應交易的年月份
        {
            int year = Convert.ToInt32(date.Year.ToString());
            int month = date.Month;
            DateTime monthExp = GetMonthExpDate(date);
            if (date > monthExp)
            {
                month += 1;
                if (month == 13)
                {
                    month = 1;
                    year = year + 1;
                }
            }
            string FutureYM = year + month.ToString("00");
            return FutureYM;
        }
  • 資料暫存區,因為Tick資料筆數太多,直接存放在SSD硬碟裡會造成讀寫遲緩以及影響SSD硬碟壽命的問題,所以筆者利用AMD Radeon(TM) RAMDisk在DDR記憶體中開了個Z槽當作頻繁資料存取之用。每天早上5點夜盤結束之後,才備份回一般的硬碟裡。當然這期間要祈禱主機沒當機或是斷電關機。
至於交易策略部分,筆者嘗試過一些天馬行空的交易策略,是還沒找到甚麼聖杯,大部分的交易策略幾乎都是賠錢的。為了本文的完整度,筆者參考一篇透過三種指標綜合所打造的交易策略Trading Stocks using Bollinger Bands, Keltner Channel, and RSI in Python範例改寫為C#版本當作台指期5分K交易進出邏輯。進場條件為布林通道上下緣超過肯特納通道上下緣,而且RSI相對強弱指標需要超過70或是低於35。出場條件則是布林通道上下緣低於肯特納通道上下緣或是RSI相對強弱指標回到70至35中間震盪。進出場濾網則是加上了一個ATR價格波動。簡單說就是把肯特納通道當作震盪區間,一旦突破這個區間就開始順勢買多或是賣空,回到這個區間就平倉。
實作完這個簡易的策略之後,當然就是要開始跑回測。回測數據要去哪裡找呢? 還好可以透過群益API下載過去一年份的1分K歷史資料當作回測數據,但是一年份的資料代表性其實是存疑的,不過筆者也沒甚麼好方法,也懶得去撈其他來源的歷史資料,還要驗證資料正確性與格式轉換,只好死馬當活馬醫,透過模擬現在系統時間的方式去餵1分K資料給這個策略執行,以一口大台的成本得到的結果扣除手續費大概就是一千點上下,平均每個工作天可以賺個五點,換算大台指就是台幣一千塊錢,最高連續虧損會落在一百多點,也就是兩萬多塊台幣。老實說,執行這個策略不如不要執行,去超商老老實實的打工比較實在,但是滿足了技術宅探索量化交易的願望。
跑完回測,至少看到期望值是正的。接下來就是模擬下單,到這邊就會發現滑價的問題,用限價去買賣成交常常不成功,只好透過範圍市價的方式交易,然後開始祈禱不要賠太多。以下是群益API設定範圍市價的方法。
        public int OrderFuture(string strStockNo, string strPrice, int nQty, short nBidAsk, short type, ref string strMessage)
        {            
            FUTUREORDER pOrder = new FUTUREORDER()
            {
                bstrFullAccount = m_UserAccount,
                bstrPrice = "P", // 委託價格,「M」表示市價,「P」表示範圍市價
                bstrStockNo = strStockNo,
                nQty = nQty,
                sTradeType = 1, //0:ROD  1:IOC  2:FOK
                sBuySell = nBidAsk, //0:買進 1:賣出
                sDayTrade = 0, //當沖0:否 1:是,可當沖商品請參考交易所規定。
                sNewClose = type, //新平倉,0:新倉 1:平倉 2:自動{新期貨、選擇權使用}
                sReserved = 0  //{期貨委託SendFutureOrderCLR適用}盤別,0:盤中(T盤及T+1盤);1:T盤預約
            };
            m_nCode = OnFutureOrderSignal(m_strLoginID, false, pOrder, ref strMessage);
            return m_nCode;
        }
在連續跑了幾星期的模擬下單後發現,好像沒有賠太多,運氣好的時候,還真的有賺一些。於是筆者捏緊了懶趴心一橫就開始實單交易,果然不出意外的話就要出意外了,實單交易一直連續賠錢到現在,也不知道回測中的賺錢時間甚麼時候會到來。真正達到第一次量化交易投資就賠錢的境界。
做個總結,因為本文所提及的交易策略較為粗陋,大部分時間都是在等待,也沒有順勢加碼的策略(其實筆者本身也沒有加碼的本錢),所以獲利的空間相當有限,另外台股特性本來就是震盪居多,波段走勢較少,也導致這個策略需要更多的耐心與信心去執行。好處就是電腦自動執行,萬一有個波段行情的時候,電腦程式能夠自行去下單交易,壞處就是獲利期望值太少,甚至扣除手續費與滑價問題的話,還會賠錢,不如其他長期持有的策略賺得還比較多。筆者自己還是趁工作閒暇之餘,找尋其他交易策略,希望有朝一日能夠真正實現財富自由的願望。
為什麼會看到廣告
4會員
9內容數
留言0
查看全部
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
最近身邊出現了一位在股市中放空強勢股而賺錢的「神人」。這位神人的操作技巧讓人刮目相看,讓我們一起來看看他的操作手法以及我們可以從中學到的一些股票投資技巧。
Thumbnail
2022/11/8 受邀分享 很幸運受到大學時導師的邀請,請我跟蘇老師分享,主題是“如何朝優質教師的目標邁進”。 收到消息的我們又驚又喜,不過我們兩個菜鳥,什麼時候是優質教師了呢? 雖然我也對這次的主題感到有點不夠格,但還是盡心盡力準備。我分享我的經驗,並想想當初我大三時,想聽到什麼內容?
Thumbnail
我加入了艾多美! 如果您對艾多美有任何疑惑或想更深入了解,歡迎參考我的分享。艾多美是直銷,但也是大型網路購物中心,提供保健食品、保養品等產品。
Thumbnail
鑒於科技進步神速,現今建築系在手繪的機會真的不多,大部分的人應該和當初的我一樣,第一次畫大圖面臨不知道如何開始的窘境,對於題目的解讀、排版、步驟、該有的內容也都不太了解,本篇文章和大家分享自己在準備建築設計考試時的心路歷程及後來歸納出的繪圖心法,希望能夠幫助剛開始準備的考生更快速地進入狀況!
Thumbnail
最近江蘇發生一則狗咬人事件,咬傷的女子向飼主索賠800萬。故事的主人翁是一隻可愛的鬆獅狗,「本狗」安靜在自家大門休息,來了一對母女對這隻可愛的鬆獅狗釋出喜歡的善意行為,直接靠近並觸碰這隻可愛的鬆獅狗。
Thumbnail
賣出交易 您尚未執行任何賣出交易。賣出操作是在交易品種價格預期下降的情況下執行。 在"商品圖表"或“市場報價”中點擊滑鼠右鍵"新訂單"並指定以下資訊: 交易品種 交易量 受保護的止盈和止損價位 然後點擊Sell賣出。若要取得持倉盈利/虧損,請"關閉持倉"。在這種情況下,將執行反向交易。 或者 檢查清
Thumbnail
這篇文章適合的對象: 1.文字創作欲大爆發,但一打開word卻是一片空白。 2.總是寫了一半就寫不下去,檔案夾裡有一堆待續稿,但一篇完稿都沒有。
Thumbnail
如何設定交易目標 完成一項艱巨的任務時,設定合理的目標是我們的動力和方向,投資交易也是一樣。交易者每日、每週、每月的交易結果都應該有一個目標,那麼應該如何設定合理的交易目標呢? 利用技術分析來設定交易目標 1. 首先,找到入場點到停損位的距離點數(步數); 以「波浪理論」設置交易目標示範
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
最近身邊出現了一位在股市中放空強勢股而賺錢的「神人」。這位神人的操作技巧讓人刮目相看,讓我們一起來看看他的操作手法以及我們可以從中學到的一些股票投資技巧。
Thumbnail
2022/11/8 受邀分享 很幸運受到大學時導師的邀請,請我跟蘇老師分享,主題是“如何朝優質教師的目標邁進”。 收到消息的我們又驚又喜,不過我們兩個菜鳥,什麼時候是優質教師了呢? 雖然我也對這次的主題感到有點不夠格,但還是盡心盡力準備。我分享我的經驗,並想想當初我大三時,想聽到什麼內容?
Thumbnail
我加入了艾多美! 如果您對艾多美有任何疑惑或想更深入了解,歡迎參考我的分享。艾多美是直銷,但也是大型網路購物中心,提供保健食品、保養品等產品。
Thumbnail
鑒於科技進步神速,現今建築系在手繪的機會真的不多,大部分的人應該和當初的我一樣,第一次畫大圖面臨不知道如何開始的窘境,對於題目的解讀、排版、步驟、該有的內容也都不太了解,本篇文章和大家分享自己在準備建築設計考試時的心路歷程及後來歸納出的繪圖心法,希望能夠幫助剛開始準備的考生更快速地進入狀況!
Thumbnail
最近江蘇發生一則狗咬人事件,咬傷的女子向飼主索賠800萬。故事的主人翁是一隻可愛的鬆獅狗,「本狗」安靜在自家大門休息,來了一對母女對這隻可愛的鬆獅狗釋出喜歡的善意行為,直接靠近並觸碰這隻可愛的鬆獅狗。
Thumbnail
賣出交易 您尚未執行任何賣出交易。賣出操作是在交易品種價格預期下降的情況下執行。 在"商品圖表"或“市場報價”中點擊滑鼠右鍵"新訂單"並指定以下資訊: 交易品種 交易量 受保護的止盈和止損價位 然後點擊Sell賣出。若要取得持倉盈利/虧損,請"關閉持倉"。在這種情況下,將執行反向交易。 或者 檢查清
Thumbnail
這篇文章適合的對象: 1.文字創作欲大爆發,但一打開word卻是一片空白。 2.總是寫了一半就寫不下去,檔案夾裡有一堆待續稿,但一篇完稿都沒有。
Thumbnail
如何設定交易目標 完成一項艱巨的任務時,設定合理的目標是我們的動力和方向,投資交易也是一樣。交易者每日、每週、每月的交易結果都應該有一個目標,那麼應該如何設定合理的交易目標呢? 利用技術分析來設定交易目標 1. 首先,找到入場點到停損位的距離點數(步數); 以「波浪理論」設置交易目標示範