segwit 到底是什么


近两天在一些BTC交易所的板块中出现了有人疯喊”距离segwit 100% 还有 xxx block, HODL”, 之类的话。那么segwit到底是什么东西? segwit会如何影响比特币呢?

TL;NR

Segwit是一种见证隔离机制。目的主要是把签名从transaction的input中移动到一个独立的数据段中,以减小transaction的大小。其另外一个好处是防止了txid的篡改。其实现协议为BIP141。

为什么现在的txid不安全?

现在的txid生成的时候会带入签名,然而,签名中可以允许有冗余的部分,于是修改签名的冗余部分,签名依然合法,而txid则会改变,这样导致发出原始transaction的节点生成的txid可以被其他节点修改。如果原始的节点利用txid来追踪交易,那就会和MtGox一样被人偷破产。

segwit 生效的几个过程

  1. BIP91 lock in(7.21)
  2. BIP91 激活 BIP 9(7.23 bit4 超过80%)
  3. BIP9 激活 BIP 141(bit1 超过 95%)

因为每个步骤都是按period执行,所以目前bit1虽然超过了95%,但激活是在下一个period。每个period为2016个block。

BIP9 BIP91 BIP141 BIP148 这些是什么?

BIP141 是segwit的本体协议。
BIP9,BIP91,BIP48是segwit的部署方式。

BIP9 规定所有支持segwit的节点在制作block的时候都装入bit1作为统计的flag,当含有bit1的block超过95%的时候就会激活segwit。

由于BIP9风险性比较大,所以。作为缓冲,提出了先通过BIP91激活BIP9,然后激活BIP141的方法。另外一种方法是通过BIP148激活BIP9,然后激活BIP141。

BIP148的做法是规定在8月1号强制所有不含有bit1的block违法来实现。由于在7月23号BIP91已经激活了BIP9,所以这个暴力的方法被避免了。

注意容易混淆的是BIP148和实际上8月1号发生的bitcoin cash的是没有什么关系的。bitcoin cash目的是通过硬分叉解决transaction容量的问题。而上述几个协议都是软分叉的协议。

为什么segwit 导致价格上涨?

Segwit使得比特币更加安全,投资家的信心随之上涨, 结果就是价格上涨了。

segwit 2x 又是什么

segwit2x的2x指的是segwit之后可用空间变成两倍的意思。

使用“apple watch complication”显示当前比特币价格

有时候我们想要扫一眼手表就可以看到当前的比特币价格。这个时候,我们可以考虑把价格显示到apple watch的complication这个widget中。

complication 是什么

所谓的complication其实就是显示在自定义表盘上的这些模块了。其中有大有小。比如下面的例子,除了时间以外,
有表示日期,温度,运动量的小模块,也有表示日程安排的大模块。

那么为了表示我们需要的比特币价格的模块,有哪些方法呢?

方法1:通过WatchConnectivity

WatchConnectivity 这个Framework用来实现ios和watchos的通信。

这个时候很显然我们要自己建一个ios的application,然后通过这个application把当前的比特币价格传送给apple watch,然后表示在表盘的complications上面。 用xcode新建watch application然后勾选上complications的选项这个就不说了。

ios获取数据

我们看到bitflyer提供了realtime的PubNub的subscribe key。利用这个Key我们可以连续获得ticker。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//AppDelegate.swift

import PubNub

// 需要 delegate PNObjectEventListener

// ...省略

let configuration = PNConfiguration(publishKey: "demo", subscribeKey: "sub-c-52a9ab50-291b-11e5-baaa-0619f8945a4f")
self.client = PubNub.clientWithConfiguration(configuration)
self.client.addListener(self)
self.client.subscribeToChannels(["lightning_ticker_BTC_JPY"], withPresence: false)

// 添加实现delegate的fucntion

func client(_ client: PubNub, didReceiveMessage message: PNMessageResult) {

let bicoinInfo = message.data.message as! NSDictionary

// bitcoinInfo是一个词典类型,保存了诸如`best_ask`, `best_bid`, `ltp` 之类的情报。
// bitcoinInfo["ltp"] => 299900
// 我们需要把这个东西传给apple watch。
}

ios传送数据

导入 WatchConnectivity, 实现WCSessionDelegate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 导入
import WatchConnectivity

// 初始化
if WCSession.isSupported() {
self.session.delegate = self
self.session.activate()
}

// 实现delegate
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
// 将当前的tick保存在lastestTick中。
// 获取 lastTick
self.session.transferUserInfo(["tick": lastestTick])
}

func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}

watchos extension接受数据

watchos 需要接受ios传来的数据并刷新当前的complications来表示最新的价格。

这里注意一点是complications的更新,在watchos里面会有一个计数,一天更新超过一定的次数就无法更新了。
在上面的ios的实现中,我们通过didReceiveMessage 来触发传输给watchos的信息,所以我们在这里要主动发送一个空的信息,来让ios把信息发过来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 同样需要导入WatchConnectivity

import WatchConnectivity

// 初始化

func applicationDidFinishLaunching() {
if WCSession.isSupported() {
self.session.delegate = self
self.session.activate()
}
// Perform any final initialization of your application.
}

// 实现delegate

func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {

}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
let lastTick = userInfo["tick"] as! NSDictionary
// 更新持有的tick数据
TickData.setTick(tick: lastTick)
let complicationServer = CLKComplicationServer.sharedInstance()
guard let activeComplications = complicationServer.activeComplications else {
return
}

for complication in activeComplications {
complicationServer.reloadTimeline(for: complication)
}

}

注意我们这里主要实现didReceiveUserInfo,这个函数实现对通过transferUserInfo传过来的数据进行处理。

在具体的处理实现中,我们获取传来的lastTick, 然后通过complicationServer.reloadTimeline来刷新complication。

watchos complication 模版和渲染

ComplicationController.swift,我们可以看到xcode已经帮我们delegate了CLKComplicationDataSource

首先我们得决定当我们没有任何数据的时候,我们的complication表示什么内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// MARK: - Placeholder Templates

func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
// This method will be called once per supported complication, and the results will be cached
let template = CLKComplicationTemplateModularLargeStandardBody()
let image = UIImage(named: "bitcoin")

template.headerImageProvider =
CLKImageProvider(onePieceImage: image!)

template.headerTextProvider =
CLKSimpleTextProvider(text: "BTC/JPY")
template.body1TextProvider =
CLKSimpleTextProvider(text: "0")

handler(template)
}

CLKComplicationTemplateModularLargeStandardBody()用来新建一个ModularLarge尺寸的模版,这个模版的就是我们上图看到的日程安排那块的大小。

接着我们实现getCurrentTimelineEntry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// MARK: - Timeline Population

func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {

// Call the handler with the current timeline entry
let lastTick = TickData.getTick()
let ltp = String(describing: lastTick["ltp"] as! Int)
let template = CLKComplicationTemplateModularLargeStandardBody()
let image = UIImage(named: "bitcoin")

template.headerImageProvider =
CLKImageProvider(onePieceImage: image!)

template.headerTextProvider =
CLKSimpleTextProvider(text: "BTC/JPY")
template.body1TextProvider =
CLKSimpleTextProvider(text: ltp)

let entry = CLKComplicationTimelineEntry.init(date: Date(), complicationTemplate: template)

handler(entry)

}

在这里做的就是通过lastTick这个Datasource把数据获取数据,然后建立一个模版,和时间一起封装成一个CLKComplicationTimelineEntry的实例然后交给handler。

到这里,我们已经可以在complication上面显示比特币的价格了。

手表截图

方法2 使用PushOver的Glances API

上面的实装要是了解原理也不是那么复杂,但是等我们真正build这个application,上传,审核,发布,那可是很长一段岁月。
更何况往往我们并没有那么多耐心去折腾。

很多时候,稍微花一点钱,我们的问题很快就可以迎刃而解。比如我们可以使用PushOver的glances api来实现在complication上表示自定义信息的需求。

文档已经很详细就不多说了,唯一需要注意的,还是complication不接受太频繁的更新这一点。

手表截图2

总结

技术往往是达成目的的手段。当我们一味追求技术的时候,往往会忽视一些最根本的问题。
有些东西,如果是花钱就能解决的问题,那么不妨考虑一下花这个钱好了。

比特币自动交易策略入门

上周五开始入坑比特币交易。
由于各个交易所提供了丰富的API,基本上利用API来协助交易变得非常简单。
比如结合itchat这个工具我们可以实现使用微信来进行交易。

三天下来有一点感受就是,总是盯着价格容易精神恍惚,所以得早日转战自动交易。
gekko就是一个非常适合用来做自动交易的框架。

要自动交易自然了解交易策略是非常重要的。下面就gekko默认自带的几个交易策略做一下备忘。

DEMA

这个方法使用(EMA)Exponential Moving Average crossovers来预测当前市场的走向。所谓的EMA可以参考wikipedia,总的来说,可以把它理解成一个K线图的加权平均,所以自带一个参数α,数值介乎0至1。α也可用天数N来代表,这个时候(α=1/(N+1))。在gekko这个框架里面,涉及用到EMA的策略,我们通常可以看到short和long这两个参数。分别代表短期N和长期的N。
DEMA中,使用短期平均和长期平均曲线的交错点来判断市场走向。下面的down和up阈值就分别代表了其上下的幅度。

1
2
3
4
5
6
7
8
# EMA weight
# the higher the weight, the more smooth (and delayed) the line
short = 10
long = 21

[thresholds]
down = -0.025
up = 0.025

MACD

基本和DEMA相同,不同点是引入了一个叫signal的参数,这个时候会有第三条EMA曲线,是用short和long EMA的查生成的。signal是其期间长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
# EMA weight (α)
# the higher the weight, the more smooth (and delayed) the line
short = 10
long = 21
signal = 9

# the difference between the EMAs (to act as triggers)
[thresholds]
down = -0.025
up = 0.025
# How many candle intervals should a trend persist
# before we consider it real?
persistence = 1

PRO

基本和MACD相同,具体区别参考这里

RSI

Relative Strength Index。主要考察过卖,过买点来分析市场走向。

1
2
3
4
5
6
7
8
interval = 14

[thresholds]
low = 30
high = 70
# How many candle intervals should a trend persist
# before we consider it real?
persistence = 2

low 和 high两个参数代表RSI数值的上值和下值,超过上值就有可能发生超买,低于下值就有可能发生超卖。

StochRSI

从名字上可以看出和RSI类似,参数也相同,就不多说了。

CCI

Commodity Channel Index。计算当前价和均价的相关性。也是判断超买和超卖的指标,前提是假设这些走向具有周期性。

1
2
3
4
5
6
7
8
9
10
# constant multiplier. 0.015 gets to around 70% fit
constant = 0.015

# history size, make same or smaller than history
history = 90

[thresholds]
up = 100
down = -100
persistence = 0

talib-macd

talib的MACD实现。基本原理和参数和上面的MACD一致。