上周入了一台ASUS PA90迷你主机,由于穷,买的最低配的版本。基础配置如下:

  • i5-9400 (6C6T)
  • 16GB DDR4 2666
  • 256G SSD + 1TB HDD
  • nVIDIA RTX 2060 6GB

华硕很狡猾,这个型号的机器为了拉开差距,配置再往上选的话有这么两个选项:

  1. 32GB内存 + Quardo P2000显卡,多7000大洋;
  2. i9-9900K + (512G SSD + 1TB HDD),多9000大洋; 而最低配的价格是9000多大洋。我觉得这个最低配是卖不出去了然后后出的一个子型号。

拆机

拆机参考chiphell的评测教程,比较方便地就能拆开了。外面的金属铁壳4枚螺丝,然后里面两侧的保护罩各2枚螺丝就能打开。2.5寸的硬盘口是“挂”在侧面的,一个铁壳子四角有螺丝拧下来,拆起来还算方便。吐槽一些这些金属器件真的是重,大概是为了散热吧。

ASUS_PA90_0.jpg ASUS_PA90_1.jpg ASUS_PA90_2.jpg ASUS_PA90_3.jpg

优点

金属外壳散热比较给力。主板用料还是可以的。机器的运行声音也十分安静,比我以前配的那台带显卡的ITX主机安静多了。 各种接口很丰富,并且对DIY的支持度还是挺高的,CPU看样子也是可以直接换的(虽然我是没钱换)。

目前是把1TB的HDD(WD Barracuda叠瓦盘)换成了一个Lexar的1T SSD,运行良好。我又发现这个低配版配的256G SSD居然是金士顿的,而且是SATA3协议你敢信!试了一下把内存跑满,然后就发现机器异常卡,虚拟内存在缓慢地写啊写啊写Orz... 好在这个机子有2个2280的槽分布在主板的两面(主板背面还挺难拆的,好在预装的那一个在主板背面),我的海康威视C2000拼爹爹专攻版已经在路上了,哼!

坑点

电源是两块大砖头

是的你没看错,这货的电源是外置的两块砖头,我收到的一块是230W,另一个是280W。其中280W的电源是专供显卡用的。试了一下,如果拔去显卡的那条线,机子也能开起来哈哈哈。

挑内存

这货用的笔记本内存,然后我从ThinkPad上拆下来一条杂牌16G 2666内存插上去,结果机器直接不启动。更坑的是我好像没有听到主板报警声,难道蜂鸣器也被取缔了? 然后我京东购入了一条DDR4 2666 HyperX金士顿本条,插上后能成功点亮,但是不知为何频率被限制在了2400. 这周没时间了,下周来查查原因看,总之感觉有点坑。

更新: 杂牌内存不启动的问题得到了解决。主板上原有一条16G的内存条,一共4个DIMM口。在插第二条内存的时候,比如原来插了DIMM0,那只能插DIMM2组双通道,不然会不亮。但是降频的问题还是继续,管他呢,好歹现在能用48G内存了~

阉割了水冷

从高配版的评测图可以看到CPU是水冷的。我手上这台,由于用了i5的处理器加上这么便宜,厂房就连水冷都取消掉了。原有水冷的地方用了一块铁板遮羞:(

显卡是8Pin的电源

瞄了一眼显卡,是用的8Pin电源。但是又看到预留另外的供电,但是没有线缆插在上面。

普通下载的安装包都是在线安装的,对于企业部署或者其他的离线环境来说不大友好。

其实这种情况下下载Edge商业版就行,具体方法是进入 https://www.microsoft.com/zh-cn/edge/business/download

截止本文发文时,最新的版本是84.0.522.52,下载地址在此: http://dl.delivery.mp.microsoft.com/filestreamingservice/files/36d8a910-0311-40a1-82f5-68f003f95abb/MicrosoftEdgeEnterpriseX64.msi

特征(feature, X)与响应(outcome, y)之间的互信息(mutual information, MI)是一种衡量两个变量之间相关性的方法。该方法将相关性这一定义拓展到非线性的关系上。具体而言,它衡量了一个随机变量经由另一随机变量能得到的信息量。

MI的概念与信息熵(entropy)的概念密不可分。信息熵度量了一个随机变量携带的信息量。形式上,两个随机变量(X,Y)的互信息I(X,Y)定义如下: 连续形式 continuous mutual information

离散形式 discrete mutual information

sklern.feature_selection.mutual_info_regression方法实现了计算所有特征与一个连续输出之间互信息值的函数,可用于挑选最可能携带预测信息的特征。它也提供一个分类器版本。

本文全文翻译自Stefan Jansen's Hands-On Machine Learning for Algorithmic Trading*

为unix平台增加XZ多线程解压缩支持(基于7zip LZMA SDK, C/C++)

Note

This post has nothing to do with the pixz project. I am talking about decompressing the original xz archive using 7-zip's LZMA SDK under unix environment.

Background

Originally the 7zip's LZMA SDK (version 19.00) only covers parallel xz decompression for Windows systems. This post shows the C code that adds support for lib pthread, i.e. unix systems. Compiling with C++ using the C library should also work, I have tested it on my own box.

Little Details

Actually the original writer has completed all the necessary abstraction for the multi-threading pipeline. All I have done is adding some macros and pthread equivalents to Windows threading model.

Usage

Replace lzma/C/... with below files. The new code should work on both Windows and Unix systems.

Git Repo

See https://github.com/idailylife/lzma-xz-parallel

Source Code

Threads.h

/* Threads.h -- multithreading library
2017-06-18 : Igor Pavlov : Public domain */

#ifndef __7Z_THREADS_H
#define __7Z_THREADS_H

#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif

#include "7zTypes.h"

EXTERN_C_BEGIN

WRes HandlePtr_Close(HANDLE *h);
WRes Handle_WaitObject(HANDLE h);

#ifdef _WIN32
typedef HANDLE CThread;
#define Thread_Construct(p) *(p) = NULL
#define Thread_WasCreated(p) (*(p) != NULL)
#define Thread_Close(p) HandlePtr_Close(p)
#define Thread_Wait(p) Handle_WaitObject(*(p))
#else
typedef void* LPVOID;
typedef pthread_t* CThread;
#define Thread_Construct(p) *(p) = NULL
#define Thread_WasCreated(p) (*(p) != NULL)
#define Thread_Close(p) HandleThread_Close(*(p))
#define Thread_Wait(p) HandleThread_Join(*(p))
WRes HandleThread_Close(pthread_t* th);
WRes HandleThread_Join(pthread_t* th);

#endif

typedef
#ifdef UNDER_CE
  DWORD
#else
  unsigned
#endif
  THREAD_FUNC_RET_TYPE;

#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);

#ifdef _WIN32

typedef HANDLE CEvent;
typedef CEvent CAutoResetEvent;
typedef CEvent CManualResetEvent;
#define Event_Construct(p) *(p) = NULL
#define Event_IsCreated(p) (*(p) != NULL)
#define Event_Close(p) HandlePtr_Close(p)
#define Event_Wait(p) Handle_WaitObject(*(p))
WRes Event_Set(CEvent *p);
WRes Event_Reset(CEvent *p);
WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); // not used
WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); // not used
WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);

#else
typedef struct {
  bool state;
  pthread_mutex_t mutex;
  pthread_cond_t cond;
} event_t;

typedef event_t* CEvent;
typedef CEvent CAutoResetEvent;
#define Event_Construct(p) *(p) = NULL
#define Event_IsCreated(p) (*(p) != NULL)

WRes Event_Close(CEvent* p);
WRes Event_Set(CEvent *p);
WRes Event_Reset(CEvent *p);
WRes Event_Wait(CEvent* p);
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent* p);

#endif

// CSemaphore is not used for decoding
#ifdef _WIN32
typedef HANDLE CSemaphore;
#define Semaphore_Construct(p) *(p) = NULL
#define Semaphore_IsCreated(p) (*(p) != NULL)
#define Semaphore_Close(p) HandlePtr_Close(p)
#define Semaphore_Wait(p) Handle_WaitObject(*(p))
WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
WRes Semaphore_Release1(CSemaphore *p);
#endif

#ifdef _WIN32

typedef CRITICAL_SECTION CCriticalSection;
WRes CriticalSection_Init(CCriticalSection *p);
#define CriticalSection_Delete(p) DeleteCriticalSection(p)
#define CriticalSection_Enter(p) EnterCriticalSection(p)
#define CriticalSection_Leave(p) LeaveCriticalSection(p)

#else
/// use mutex instead
typedef pthread_mutex_t* CCriticalSection
WRes CriticalSection_Init(CCriticalSection *p);
WRes CriticalSection_Delete(CCriticalSection *p);
WRes CriticalSection_Enter(CCriticalSection *p);
WRes CriticalSection_Leave(CCriticalSection *p);

#endif
EXTERN_C_END

#endif

Threads.c

/* Threads.c -- multithreading library
2017-06-26 : Igor Pavlov : Public domain */

#include "Precomp.h"

#ifdef _WIN32
  #ifndef UNDER_CE
  #include <process.h>
  #endif
#endif

#include "Threads.h"

#ifdef _WIN32
static WRes GetError()
{
  DWORD res = GetLastError();
  return res ? (WRes)res : 1;
}

static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }

WRes HandlePtr_Close(HANDLE *p)
{
  if (*p != NULL)
  {
    if (!CloseHandle(*p))
      return GetError();
    *p = NULL;
  }
  return 0;
}

WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); }

#else
/// unix specific functions

WRes HandleThread_Close(pthread_t* th) {
  free(th);
  th = NULL;
  return 0;
}

WRes HandleThread_Join(pthread_t* th) {
  return pthread_join(*th, NULL);
}

#endif

#ifdef _WIN32
WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
{
  /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */

  #ifdef UNDER_CE

  DWORD threadId;
  *p = CreateThread(0, 0, func, param, 0, &threadId);

  #else

  unsigned threadId;
  *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId);

  #endif

  /* maybe we must use errno here, but probably GetLastError() is also OK. */
  return HandleToWRes(*p);
}
#else
pthread_attr_t g_th_attrs[64]; //NOTE: maximum of 64 threads
size_t g_th_index = 0;

WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
{
  *p = malloc(sizeof(pthread_t));
  pthread_t* th = *p;
  int ret = pthread_attr_init(&(g_th_attrs[g_th_index]));
  assert(ret==0);
  ret = pthread_create(th, &(g_th_attrs[g_th_index]), func, param);
  g_th_index++;
  return ret;
}
#endif

#ifdef _WIN32
static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
{
  *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
  return HandleToWRes(*p);
}

WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }

WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }

#else 
///unix

WRes Event_Close(CEvent* p) {
  if (!p || !(*p))
    return 0;
  event_t* evt = *p;
  pthread_cond_destroy(&evt->cond);
  pthread_mutex_destroy(&evt->mutex);
  free(evt);
  *p = NULL;
}

WRes Event_Set(CEvent *p) {
  event_t* evt = *p;
  if (pthread_mutex_lock(&evt->mutex) != 0) {
    return 1;
  }
  evt->state = true;

  if (evt->manual_reset) {
    if (pthread_cond_broadcast(&evt->cond)) {
      return 1;
    }
  } else {
    if (pthread_cond_signal(&evn->cond)) {
      return 1;
    }
  }

  if (pthread_mutex_unlock(&evt->mutex)) {
    return 1;
  }

  return 0;
}

WRes Event_Reset(CEvent* p) {
  event_t* evt = *p;
  if (pthread_mutex_lock(&evt->mutex)) {
    return 1;
  }

  evt->state = false;

  if (pthread_mutex_unlock(&evt->mutex)) {
    return 1;
  }

  return 0;
}

WRes Event_Wait(CEvent* p) {
  event_t* evt = *p;
  if (pthread_mutex_lock(&evt->mutex)) {
    return 1;
  }

  while (!evt->state) {
    if (pthread_cond_wait(&evt->cond, &evt->mutex)) {
      pthread_mutex_unlock(&evt->mutex);
      return 1;
    }
  }

  evt->state = false;
  if (pthread_mutex_unlock(&evt->mutex)) {
    return 1;
  }
  return 0;
}

WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) {
  *p = malloc(sizeof(event_t));
  memset(evt, 0, sizeof(event_t));
  evt->state = false;
  evt->manual_reset = false;
  if (pthread_mutex_init(&evt->mutex, NULL)) {
    return 1;
  }
  if (pthread_cond_init(&evt->cond, NULL)) {
    return 1;
  }
  return 0;
}

#endif

#ifdef _WIN32

WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
{
  *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
  return HandleToWRes(*p);
}

static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
  { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
  { return Semaphore_Release(p, (LONG)num, NULL); }
WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }

#endif

#ifdef _WIN32
WRes CriticalSection_Init(CCriticalSection *p)
{
  /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */
  #ifdef _MSC_VER
  __try
  #endif
  {
    InitializeCriticalSection(p);
    /* InitializeCriticalSectionAndSpinCount(p, 0); */
  }
  #ifdef _MSC_VER
  __except (EXCEPTION_EXECUTE_HANDLER) { return 1; }
  #endif
  return 0;
}

#else
WRes CriticalSection_Init(CCriticalSection *p) {
  *p = malloc(sizeof(pthread_mutex_t));
  if (pthread_mutex_init(*p, NULL)) {
    return 1;
  }
  return 0;
}

WRes CriticalSection_Delete(CCriticalSection *p) {
  pthread_mutex_t* mtx = *p;
  return pthread_mutex_destroy(mtx);
}

WRes CriticalSection_Enter(CCriticalSection *p) {
  if (pthread_mutex_lock(&evt->mutex)) {
    return 1;
  }
  return 0;
}

WRes CriticalSection_Leave(CCriticalSection *p) {
  if (pthread_mutex_unlock(&evt->mutex)) {
    return 1;
  }
  return 0;
}

#endif

XzDec.c

add the following macro

#ifndef _WIN32
#define S_OK 0x00000000
#define E_FAIL 0x80004005
#endif

MtDec.c

replace function ThreadFUnc1 with:

static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void* pp)
{
  static int g_ok_stat = 0x0;
  static int g_err_stat = 0x80004005;
  WRes res;
  CMtDecThread *t = (CMtDecThread*)pp;
  CMtDec *p;

  res = ThreadFunc2(t);
  p = t->mtDec;
  if (res == 0) {
#ifdef _WIN32
    return p->exitThreadWRes;
#else
    if (p->exitThreadWRes) { return &g_err_stat; }
    else { return &g_ok_stat; }
#endif
  }
  {
    // it's unexpected situation for some threading function error
    if (p->exitThreadWRes == 0)
      p->exitThreadWRes = res;
    PRF(printf("\nthread exit error = %d\n", res));
    p->exitThread = True;
    Event_Set(&p->threads[0].canRead);
    Event_Set(&p->threads[0].canWrite);
    MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res));
  }
#ifdef _WIN32
    return res;
#else
    return &g_err_stat;
#endif
}

初涉主动投资管理(以及量化)的小同学可能会被一些缩写搞烦。下面是其中几个入门级的指标,他们常被用来评价某个策略的绩效(performance)。

夏普率 Sharpe Ratio

夏普比率(SR)将投资组合的预期超额投资组合与该超额收益的波动率进行比较,该波动率以其标准偏差衡量。 它以每单位风险的平均超额收益来衡量补偿: SR = (R_a - R_f) / σ_a

其中:

  • R_a: 投资组合的收益率,这本来是一个期望值(expectation),但是通常会用投资组合至今N期的平均收益率作为观测值估计它;
  • R_f: 无风险利率
  • σ_a: 投资组合收益的标准差,也是一个期望值,这边通常用至今N期投资组合收益率的标准差来估计它;

信息系数 Information Coefficient(IC)

IC会测量Alpha因子与信号产生的前瞻收益之间的相关性,并捕获经理预测技能的准确性。投资组合的截面IC通常是指模型预测的股票下期收益率(i.e.某alpha因子在这一时刻T给所有股票的因子值)与股票下期(T+x)实际的收益率的相关性。假设有3000只股票,那相关性就是两个3000维向量的相关系数,多半用皮尔森相关系数计算。

信息比率 Information Ratio(IR)

基于IC的一个统计量:IR = mean(IC) / std(IC) 均值除以方差。较高的信息比率(IR)意味着相对于所承担的单位风险下拥有更高的信息系数。