搜尋此網誌

2010-09-30

tucan 免費空間下載軟體

網路上有許多好心人喜歡把較小的影音檔放在免費空間上,而這些免費空間常常都有每日總量限制,或者是等待時間等不方便的地方,當然如果只要下載一兩個檔案,直接用手按就好,但如果要下載數十個檔案,我們就會想要一個下載管理員,當今日的額度用完後,可以在 24 小時候自動繼續下載,或是自動等待 45 秒後下載。

tucan就是這樣一個好用的軟體,可以直接在 ubuntu 的 repository 找到,支援以下空間︰rapidshare, megaupload, gigasize, mediafire, 4shared, sendspace, zshare, filefactory, easy-share, badongo, depositfiles, hotfile, uploading,差不多主流的都有了,如果有付費的帳號密碼,也可以支援,算是除了 Transmission 跟 aMule 外一定要裝的。

這軟體是用 python 跟 gtk+ 寫的,只有 330KB,可以下載來研究看看。

2010-09-29

day count convention

計算債券價格或固定收益的東西,最麻煩的就是 day count convention,如果是用 gnumeric,那就直接設定參數就好了,但如果想要自己寫一個快一點小巧一點的程式,就得慢慢找資料寫程式了。維基的說明還不錯。瑞士交易所ISDA 也有簡單說明文件,可以參考看看。

程式碼
#include <stdio.h>
#include <time.h>        /* mktime tm */

/* List all decleration in the beginning because ISO C forbids mixed declarations and code. */
struct tm totm(char date[8]);
struct tm calctm(struct tm date, int n);
unsigned int leapyear(int year);
unsigned int comptm(struct tm t1, struct tm t2);
int days(char date1[8], char date2[8], int basis);
double yearfrac(char date1[8], char date2[8], unsigned int freq, int basis);

int main() {
    char s1[8] = "20120302";
    struct tm t1, t2;
    t1 = totm(s1);
    t2 = calctm(t1, -5);
    printf("%s%.8f\n", asctime(&t2), yearfrac("20070815","20070823", 2, 9));

    return 0;
}

/* 不採用 strptime,因為 libc 的 time.h 有一些問題,要另外宣告函數原型才能使用。 */
struct tm totm(char date[8]) {
    struct tm t;
    t.tm_year = (date[0] - 48) * 1000 + (date[1] - 48) * 100 + (date[2] - 48) * 10 + (date[3] - 48) - 1900;
    t.tm_mon = (date[4] - 48) * 10 + (date[5] - 48) - 1;
    t.tm_mday = (date[6] - 48) * 10 + (date[7] - 48);
    t.tm_hour = 0;
    t.tm_min = 0;
    t.tm_sec = 0;
    t.tm_isdst = 0;
    mktime(&t);

    return t;
}

struct tm calctm(struct tm date, int n) {
    struct tm temp = date;
    temp.tm_mday += n;
    mktime(&temp);

    return temp;
}

/* C89 doesn't have bool. C99 has stdbool.h to use bool. */
unsigned int leapyear(int year) {
    if ( year % 4 == 0 ) {
        if ( year % 100 == 0 ) {
            if ( year % 400 == 0) {
                return 1;
            } else {
                return 0;
            }
        } else {
            return 1;
        }
    } else {
        return 0;
    }
}

unsigned int comptm(struct tm t1, struct tm t2) {
    if ( t1.tm_year == t2.tm_year && t1.tm_mon == t2.tm_mon && t1.tm_mday == t2.tm_mday ) {
        return 1;
    } else {
        return 0;
    }
}

int days(char date1[8], char date2[8], int basis) {
    int Y1, Y2, M1, M2, D1, D2;
    struct tm t[2];
    t[0] = totm(date1);
    t[1] = totm(date2);
    Y1 = t[0].tm_year;
    Y2 = t[1].tm_year;
    M1 = t[0].tm_mon;
    M2 = t[1].tm_mon;
    D1 = t[0].tm_mday;
    D2 = t[1].tm_mday;
    /* N = (D2 - D1) + 30 * (M2 - M1) + 360 * (Y2 - Y1) */
    switch ( basis ) {
        case 0:
            /*
            30U/360
            http://www.eclipsesoftware.biz/DayCountConventions.html#x3_01a
            date is changed in one rule the changed value is used in the following rules:
            If the investment is EOM and (Date1 is the last day of February) and (Date2 is the last day of February), then change D2 to 30.
            If the investment is EOM and (Date1 is the last day of February), then change D1 to 30.
            If D2 is 31 and D1 is 30 or 31, then change D2 to 30.
            If D1 is 31, then change D1 to 30.
            */
            if ( calctm(t[0], 1).tm_mon == 2 && calctm(t[1], 1).tm_mon == 2 ) {
                D2 = 30;
            } else if ( calctm(t[0], 1).tm_mon == 2 ) {
                D1 = 30;
            } else if ( D2 == 31 && ( D1 == 30 || D1 == 31 ) ) {
                D2 = 30;
            } else if ( D1 == 31 ) {
                D1 = 30;
            }
            break;
        case 1:
            /*
            30U/360
            http://www.eclipsesoftware.biz/DayCountConventions.html#x3_01b
            If D2 is 31 and D1 is 30 or 31, then change D2 to 30.
            If D1 is 31, then change D1 to 30.
            */
            if ( D2 == 31 && ( D1 == 30 || D1 == 31 ) ) {
                D2 = 30;
            } else if ( D1 == 31 ) {
                D1 = 30;
            }
            break;
        case 2:
            /*
            30E/360
            http://www.eclipsesoftware.biz/DayCountConventions.html#x3_02
            If D1 = 31, then change D1 to 30.
            If D2 = 31, then change D2 to 30.
            */
            if ( D1 == 31 ) {
                D1 = 30;
            }
            if ( D2 == 31 ) {
                D2 = 30;
            }
            break;
        case 3:
            /*
            30E/360 ISDA
            http://www.eclipsesoftware.biz/DayCountConventions.html#x3_03
            If D1 = last day of the month, then change D1 to 30.
            If D2 = last day of the month, then change D2 to 30.
            */
            if ( calctm(t[0], 1).tm_mon != M1 ) {
                D1 = 30;
            }
            if ( calctm(t[1], 1).tm_mon != M2 ) {
                D2 = 30;
            }
            break;
        case 4:
            /*
            30E+/360 ISDA
            http://www.eclipsesoftware.biz/DayCountConventions.html#x3_04
            If D1 = 31, then change D1 to 30.
            If D2 = 31, then change M2 to the next month and change D2 to 1.
            */
            if ( D1 == 31 ) {
                D1 = 30;
            }
            if ( D2 == 31 ) {
                t[1] = calctm(t[1], 1);
                Y2 = t[1].tm_year;
                M2 = t[1].tm_mon;
                D2 = t[1].tm_mday;
            }
            break;
    }

    return (D2 - D1) + 30 * (M2 - M1) + 360 * (Y2 - Y1);
}

double yearfrac(char date1[8], char date2[8], unsigned int freq, int basis) {
    int Y1, Y2, M1, M2, D1, D2, period = 0, Nnl = 0, Nly = 0, N = 0, L = 365;
    double result;
    struct tm t[3];
    t[0] = totm(date1);
    t[1] = totm(date2);
    Y1 = t[0].tm_year;
    Y2 = t[1].tm_year;
    M1 = t[0].tm_mon;
    M2 = t[1].tm_mon;
    D1 = t[0].tm_mday;
    D2 = t[1].tm_mday;

    switch ( basis ) {
        case 0:
            result = days(date1, date2, basis) / 360.0;
            break;
        case 1:
            result = days(date1, date2, basis) / 360.0;
            break;
        case 2:
            result = days(date1, date2, basis) / 360.0;
            break;
        case 3:
            result = days(date1, date2, basis) / 360.0;
            break;
        case 4:
            result = days(date1, date2, basis) / 360.0;
            break;
        case 5:
            /*
            Act/Act (ISDA)
            http://www.eclipsesoftware.biz/DayCountConventions.html#A_01
            This convention splits the accrual period into that portion in a leap year and that in a non-leap year.
            You include the first date in the period and exclude the ending one.
            Fact = Nnl in non-leap year / 365 + Nly in leap year / 366
            */
            while ( comptm(t[0], t[1]) != 1 ) {
                if ( leapyear(t[0].tm_year + 1900) ) {
                    Nly++;
                } else {
                    Nnl++;
                }
                t[0] = calctm(t[0], 1);
            }
            result = Nnl / 365.0 + Nly / 366.0;
            break;
        case 6:
            /*
            Act/Act (ICMA)
            http://www.eclipsesoftware.biz/DayCountConventions.html#A_02
            This is the method used for US Treasury Notes and Bonds. The US Treasury expresses the calculation as:
                AI = CR * ( {N / JulianDays(Date1, Date3) } / Fr).
            This captures the ideas that all days in any given period (but not necessarily in different periods)
            accrue the same amount and that all coupon payments are equal.
            Date1 is the previous coupon date before the current settlement Date2.
            Date3 is the next coupon date after the current settlement Date2.
            */
            t[2] = t[0];
            t[2].tm_mon += 12 / (int) freq;
            mktime(&t[2]);
            while ( comptm(t[0], t[1]) != 1 ) {
                N++;
                t[0] = calctm(t[0], 1);
            }
            period = N;
            while ( comptm(t[1], t[2]) != 1 ) {
                period++;
                t[1] = calctm(t[1], 1);
            }
            result = (double) N / ((int) freq * period);
            break;
        case 7:
            /*
            Act/365 (Fixed)
            http://www.eclipsesoftware.biz/DayCountConventions.html#A_03
            */
            while ( comptm(t[0], t[1]) != 1 ) {
                N++;
                t[0] = calctm(t[0], 1);
            }
            result = N / 365.0;
            break;
        case 8:
            /*
            Act/360
            http://www.eclipsesoftware.biz/DayCountConventions.html#A_04
            */
            while ( comptm(t[0], t[1]) != 1 ) {
                N++;
                t[0] = calctm(t[0], 1);
            }
            result = N / 360.0;
            break;
        case 9:
            /*
            Act/365L
            http://www.eclipsesoftware.biz/DayCountConventions.html#A_05
            Den:
                If Fr = 1 (annual coupons)
                    If February 29 is in the range Date1 (exclusive) to Date3 (inclusive), then use 366.
                    Else use 365.
                Else
                    If Date3 is in a leap year, then use 366.
                    Else use 365.
            */
            t[2] = t[0];
            t[2].tm_mon += 12 / (int) freq;
            mktime(&t[2]);
            if ( freq == 1 ) {
                if ( t[0].tm_mon == 1 && t[0].tm_mday == 29 ) {
                    N++;
                    t[0] = calctm(t[0], 1);
                }
                while ( comptm(t[0], t[1]) != 1 ) {
                    N++;
                    if ( t[0].tm_mon == 1 && t[0].tm_mday == 29 ) {
                        L = 366.0;
                    }
                    t[0] = calctm(t[0], 1);
                }
                while ( comptm(t[0], t[2]) != 1 ) {
                    if ( t[0].tm_mon == 1 && t[0].tm_mday == 29 ) {
                        L = 366.0;
                    }
                }
            } else {
                if ( leapyear(t[2].tm_year + 1900) ) {
                    L = 366.0;
                }
                while ( comptm(t[0], t[1]) != 1 ) {
                    N++;
                    t[0] = calctm(t[0], 1);
                }
            }
            result = (double) N / L;
            break;
    }

    return result;
}
編譯
gcc day_count_convention.c -Wall -Wextra -pedantic -Wconversion -Wundef -Wshadow -o day_count_convention
執行
./day_count_convention
輸出 yearfrac 的結果,計算方式為 Act/365L
0.02185792

遠端控制動物機 (client 端)

基本上用 ubuntu 內建的 terminal server client 就可以了,但是裡面少了一個 VNC 模組,所以只要裝上就好了。
sudo apt-get install xtightvncviewer
transmission 可以直接用瀏覽器遠端操作大部功能,只要在裡面設定好要用哪個 port 就好了。

aMule 的部份稍微麻煩一點,一樣要設定 port,但是要用 aMule 專用的介面才能操作,名稱就叫 aMuleGUI;麻煩一點,但是可以操作的功能也比較多一點。
sudo apt-get install amule-utils-gui

2010-09-26

curl - C 語言的 url 工具

python 固然好用,但是有時也要用 C 寫一些東西,發現了 curl 這樣的 C library,可以抓網路上的檔案。

範例檔

要編譯需要安裝 libcurl3-dev (使用openssl) 或 libcurl4-dev (使用GnuTLS)
sudo apt-get install libcurl3-dev
編譯
gcc curl01.c -o curl01 -lcurl
執行
./curl01

2010-09-24

Glade - GTK+ GUI 介面編輯程式

GTK+ 雖然好用,但是要一行一行寫還是太麻煩,Glade 是一個建立 GUI 的好用程式,這樣就可以把心力集中在 libraries 開發就好,耶!

Totem 問題修正

Totem 是 ubuntu 預設的 player,可以網路播放 YouTube 跟 BBC podcast,也可以播放大部份的影音,但是有部份小問題。第一個是 mkv,由於找不到 H.264 Decoder,所以用 gstreamer0.10-ffmpeg;第二個是 BBC podcast 的清單不完整,裝上 libtotem-plparser-dev;其他的應該都是遇到有缺的,會自動尋找跟安裝。

2010-09-16

連結國外股票的權証

台灣真是一個奇妙的地方,明明沒有 GFW 卻好像資訊被封閉一樣,金融機構推出的金融產品就是一例,今天解釋一下,我如果要買這個權證,我會作啥研究。

首先是標的物,這次的都是在香港掛牌的,譬如 A50、富士康跟匯豐銀行。HKExnews披露易,相當於台灣的股市觀測站,但是有正體、簡體跟英文,一般說來,香港的英文翻譯都是比較正確跟通用的,有翻譯需求的可以參考。這裡可以找到財務報表跟公告,還有一些重大資訊。

再來可以去港交所看一下,投資服務中心→公司/證券資料,可以找到一些基本資料,包括每手多少股,譬如匯豐銀行是每手 400 股,如果有對沖交易的人應該需要。

然後就是股價表現了,yahoo finance 是一個選擇,不過我偏好 google finance,比較簡潔,資料也可較正確。跟台灣不同的是,香港的即時股價資訊是要錢的,所以免費的都會延遲 20 分鐘。

最後才是計算 warrant 定價何不合理。香港是全世界權証最發達的地方之一,所以可以找到完整的 term structure 來做定價參考,大型的權証發行機構也都有網站可以用。這裡介紹港交所的,產品及服務→證券產品→結構性產品→衍生權證→衍生權証搜尋,這裡可以找到相關標的所發行的權證,這有一個很重要的街貨比,就是市場上流通/總發行量,可以參考看看。

附註
看來台灣真是一個好混撈錢的地方,不但官方網站做的差,連業者的網站也很差,而且資訊揭露不用遵守啥規定,財報也不需要出英文版,之前有科技公司董事長內線交易,還用投資人的錢請律師,實在是坑殺散戶的寶地啊。

Acer L3600 上用耳麥

直觀上想應該是 plug&play,事實上不是。因為很多耳麥都是 USB 介面的,需要驅動程式,而這方面 ubuntu 還不夠完整,耳麥的硬體晶片可能也是一大問題,最近試了一個就只能在 MS 上用,後來發現如果用 3.5mm 的方式就可以解決了。

我先買一個 apple iphone 的耳麥,ebay 上只要 USD$2.99 (含運),再買一個轉接頭,USD$4.99,把他轉為耳機跟麥克風接頭,這樣就可以了。

其實這最大的好處就是,在美國可以用 google voice 打免錢的北美電話,哈哈。

2010-09-15

自製 XBRL 資料庫

台灣 XBRL 下載區

根據台灣官方機構的說法,2010 年 9 月 30 日前,需要將半年報的 XBRL 檔案交出來,以後也變成強制性的。這真是一項大福音,因為股市觀測站的資料實在錯誤不少,訪間的資料庫公司資料品質更差,而且官方的示範網站實在是做的不怎樣,既不快也不穩,選項也太少,所以自己做才是最好的。

在工具的選擇方面,一樣採用開源的,所以用 python3sqlite3

先檢查有問題的 XBRL 檔,其實只有 tw-gaap-ci-2371-2010Q1-cr.xml 要修正
xbrl-filter
#檢查有問題的 xml 檔
import glob
from lxml import etree

files = glob.glob('*.xml')

for i in files:
    print(i)
    xbrl = etree.parse(i)
    root = xbrl.getroot()
    ns = "{" + root.nsmap['-'.join(i.split('-')[0:3])] + "}*"
    print(ns)
再來就是轉檔
xbrl-convert
#轉檔
import glob
from lxml import etree
import sqlite3

files = tuple(sorted(glob.glob('*.xml')))
conn = sqlite3.connect('xbrldata.sqlite')
cur = conn.cursor()
#t for ticker, s for subject, d for date, v for value, g for gaap classification, q for quarterly financial statements
cur.execute("create table 'tw' (t integer, s text, d text, v integer, g text, q text, unique (t, s, d, v, g, q))")

for i in files:
    data = []
    if i[:5] == 'tifrs':
        quarter = i.split('-')[-1][:6]
        gaap = 'IFRS' + '-' + i.split('-')[3]
        ticker = i.split('-')[-2]
        if i.split('-')[-3] == 'cr':
            cr = '-cr'
        else:
            cr = ''
        xbrl = etree.parse(i)
        root = xbrl.getroot()
        ns = root.nsmap
        for n in ns:
            if n not in ['tifrs-notes', None, 'link', 'xbrli', 'xbrldt', 'xbrldi', 'iso4217']:
                for j in root.iterchildren(tag = "{" + ns[n] + "}*"):
                    data.append([ticker, j.tag.partition('}')[2]+cr, j.attrib['contextRef'], j.text.strip(), gaap, quarter])
    else:
        quarter = i.split('-')[4][:6]
        gaap = 'GAAP' + '-' + i.split('-')[2]
        ticker = i.split('-')[3]
        if len(i.split('-')) == 6:
            cr = '-cr'
        else:
            cr = ''
        xbrl = etree.parse(i)
        root = xbrl.getroot()
        ns = root.nsmap
        for n in ns:
            if n in ['-'.join(i.split('-')[0:3]), 'tw-gaap-ar']:
                for j in root.iterchildren(tag = "{" + ns[n] + "}*"):
                    if "OtherSupplementalInformation" in j.tag:
                        data.append([ticker, "OtherSupplementalInformation"+cr+"_"+j.find("{"+ns[n]+"}"+"ChineseAccount").text.strip()+"_"+j.find("{"+ns[n]+"}"+"EnglishAccount").text.strip(), j[0].attrib['contextRef'], j.find("{"+ns[n]+"}"+"Amount").text, gaap, quarter])
                    else:
                        if j.text != None:
                            data.append([ticker, j.tag.partition('}')[2]+cr, j.attrib['contextRef'], j.text.strip(), gaap, quarter])
    cur.executemany("insert or ignore into 'tw' (t, s, d, v, g, q) values (?, ?, ?, ?, ?, ?)", data)

conn.commit()
cur.close()
最後,證交所自己也是公開發行公司卻不出 XBRL,實在是雙重標準。

IFRS 後的年報與季報公告時間分別為 3/31、5/15、8/14、11/14。

2018.05.27 更新︰附上全部的 XBRL 檔,到 2018-Q1。

2010-09-14

好用的壓縮軟體 7-Zip

官網

壓縮率比 zip 高出 30% ~ 50%,而且是 open source。
壓縮支援︰7z, ZIP, GZIP, BZIP2, TAR
解壓縮檔支援︰ARJ, CAB, CHM, CPIO, DEB, DMG, HFS, ISO, LZH, LZMA, MSI, NSIS, RAR, RPM, UDF, WIM, XAR, Z

解壓縮到 temp
find -name "*.zip" -exec 7z e {} -otemp \;
以最高壓縮率壓縮成 7z
7z a -t7z -mx=9 xbrl.7z *.xml
壓縮成 zip
7z a -tzip xbrl.zip *.xml

2010-09-08

批次檔案處理 - 轉檔與刪除

將 BIG5 轉為 UTF8。
find -name "*.c" -exec iconv -f big5 -t utf8 {} -o {} \;
將目前目錄與子目錄下 .exe 的檔案全部移除。
find . -name "*.exe" -exec rm {} \;
find 也可以指定目錄,刪除 ~/Downloads/target/ 下所有 .exe 檔。
find ~/Downloads/target/* -name "*.exe" -exec rm {} \;
在目前的目錄,刪除大小在 2 bytes 到 5 bytes 的 txt。
find . -name "*.txt" -size +2c -a -size -5c -exec rm {} \;
也可以把 find 的 -exec 串接起來,譬如先 ls 再 rm。
find . -name "*.txt" -exec ls {} \; -exec rm {} \;